Question about == and .equals() for objects.

Discussion in 'Plugin Development' started by Sulphate, Dec 21, 2016.

Thread Status:
Not open for further replies.
  1. Hello,

    I've been a bit confused about this lately as some say that it only compares if the objects are an instance of the same class, while others say it compares the variables within the object as well.

    Which is it? If I do player1 == player2, is that just going to check if they are both Players? Or will it check the name, uuid, etc?

    Thanks in advance.


    EDIT: Addition question, what are the benefits of using Set or Collection over ArrayList / List?
     
    Last edited: Dec 21, 2016
  2. Offline

    Tecno_Wizard

    @Sulphate
    Instance of the same class? Please slap whoever told you that for me. That's instanceof

    == compares objects using their memory location. It does not care what the contents of the class are, when it was created, what you named it, nothing. It compares the 2 memory locations and sees if they are pointing to the same place. If they are, they are seen as equal. (In objects, this means they are what are known as aliases. Go Google it). Java hides a lot of the memory things lower level languages have to deal with and it's a lifesaver most of the time.

    .equals is a dynamic comparison that's a bit more complicated to explain. It does not always exhibit the same behavior.
    Imagine we have an object of the String class. I'm sure you've heard over and over to never compare Strings with ==, but why? == is a memory location comparison, and depending on how the String was created (and a lot of times you don't even know this) there's a good chance even 2 identical Strings will point to 2 different memory locations.

    So why is .equals different? When overridden by a class, the .equals method defines how to compare for object equality not using the memory location, but using the fields within the class. Here's the String classes .equals implementation for reference.

    Code:
    public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    What is this doing? First, it is overriding the default Object#equals method. The default method simply uses the == equality check, because it has no data to compare (Half-truth, but go with it). It then checks each way it could be equal, putting the fastest comparison first, the memory equality check. If that's true, they are equal, and return true. If that's false, then check if they have the same length. If they don't, they're different, and if they are the same, check every character for equality. If one isn't equal, return false.

    It's important to know that not every class implements it's own equality check, but know that if something has a reason to need an equality check, chances are it's implemented.

    I believe you can answer this yourself now.

    Sets do not allow duplicate items and the HashSet#contains check has an asymptotic complexity of O(1), while the list has a contains of O(n). If you're new to Comp Sci, that just means the contains check for Lists is much slower and becomes longer as there is more data while the HashSet (most frequently used implementation of set) is always fast regardless of how much data there is. Lists can save data in a certain order while Sets cannot.
     
    Last edited: Dec 21, 2016
  3. @Tecno_Wizard

    Thank you very much for this reply :) I am fairly new to comp sci (doing it at AS level atm), so this is very helpful. Sadly we only get taught VB.NET :c

    So I take it it's probably a better idea to just compare the UUID, right? Unless I'm just not understanding it properly. Thanks for the in-depth explanation.

    As a matter of fact, I've never been told not to compare Strings with ==, but now I know not to :) I don't think I have been anyway so not much of a problem.

    Thanks! ^-^
     
  4. Offline

    DoggyCode™

    However, enums are perfectly fine to compare with ==. And yes, compare the two Player objects UUIDs, as they would either be different if it's not the same player, or the same if it is.
     
  5. Offline

    mythbusterma

    @DoggyCode™ @Sulphate

    Specifically, the reason this works with enumerations is that although they are in fact Objects like any other, the way the VM interprets them is by having a static instance of the class for each enumeration value, and having each of them be publicly accessible fields in the class. This way, any comparison of the enumeration values (including those by comparing the equality of reference) works as expected.

    @Tecno_Wizard

    A few notes.

    It doesn't actually compare the memory locations, it compares reference. Subtle difference. This is because the JVM is constantly moving things around in memory, and maintains reference tables, so it doesn't check the actual pointer values, instead preferring other methods. It is still called "aliasing," however.

    It is indeed the complete truth that the default equals method uses the "==" operator, although it checks for null first.

    To be explicit, since the server only maintains one "Player" object per player, a simple "==" comparison will work, however note that this will not work if a player logs out and you maintain a reference after they log out, then try to see if they are the same when the player logs back in.

    Technically, for small "n," a List will be faster, and will take less memory no matter the size. That being said, the difference is so small that you should use whichever one makes the most sense.

    @Sulphate

    You can't "use" a Collection in the sense you mean it. Collection is a super class of many different data structures, ArrayList and HashSet included (although not Maps). In general just pick the data structure that makes the code the easiest to understand/most intuitive. For example use a Set to forbid duplicates, use a List where you need ordering, and a Map where you need to associate one value with another.
     
    DoggyCode™ likes this.
  6. Alright, thank you! :) What if I don't need order or to forbid duplicates? :p
     
  7. Offline

    mythbusterma

    @Sulphate

    A List would work fine, you just would ignore the ordering.
     
Thread Status:
Not open for further replies.

Share This Page