Beny Bosko
Beny Bosko

Reputation: 239

Java: Objects in collections

Vector v = new Vector();
String a = "element";
String b = "element";
v.add(a);
v.contains(b) // true

So my question: if the type of the elements in the vector are Object than how contains compare the Object inside with the String outside if equals() is not overriden as an Object I would like to know what's going on under the surface.

Upvotes: 2

Views: 92

Answers (4)

Vivin Paliath
Vivin Paliath

Reputation: 95508

See here:

Returns true if this vector contains the specified element. More formally, returns true if and only if this vector contains at least one element e such that (o==null ? e==null : o.equals(e)).

The .equals that ends up being called is the overridden .equals. The fact that the method parameter is typed with Object doesn't mean that the vector will use .equals method of the Object class; it will use the overridden .equals method if one exists (otherwise using the one inherited from Object). The parameter being typed Object just means that you can pass in anything that is an Object (which String is, since all Java classes inherit from Object).

Your confusion stems from the fact that the method invoked at runtime depends on the actual type of the object whose method is being invoked. Look at the JLS section on runtime evalution of method invocations for more details. You can see that it mentions a "target reference", which is the object whose method you are invoking.

Consider what would happen otherwise: behavior would change based on the type of the method parameter, rather than the type of the instance. This would completely defeat polymorphism! Consider the oft-used Animal example: let's say there is a single method called makeNoise() that returns the string "Noise!". Now you have two subclasses Dog and Cat that have overridden the method to return "Woof!" and "Meow!" respectively. Let's now say you have this method:

public void animalNoiseMaker(Animal animal) {
    System.out.println(animal.makeNoise());
}

Going by your expectation, regardless of whether you passed in a Dog or Cat instance, it would call makeNoise on Animal every time and print Noise! because the parameter type is Animal. This is not very useful behavior.

Upvotes: 3

Jack Bister
Jack Bister

Reputation: 11

Object already contains a definition for the equals method. Therefore, if the object you are calling contains on (b in this case) is of a class that does not override the equals method, it will use Object's definition of equals.

The definition of equals in Object compares the address of the two objects and returns true if they are equal. From https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object) :

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).

If the class overrides the equals method (as is the case for String) then the overriding version will be used.

Upvotes: 1

Woot4Moo
Woot4Moo

Reputation: 24316

You are using what are typically called 'raw types' for your collection. You can add whatever you like to it, but at run time it may cause issues (type casting). See here for a discussion

Upvotes: 0

Eran
Eran

Reputation: 393781

Vector's contains method calls indexOf, which compares the elements of the Vector with the element we are searching for using equals.

If equals is executed on an instance whose runtime type is String (which is the case in your code), String's equals is executed (that's method overriding), and if the passed parameter is also a String and contains the same characters in the same order, it will return true.

Here's what's going "under the surface" :

public boolean contains(Object o) {
    return indexOf(o, 0) >= 0;
}

public synchronized int indexOf(Object o, int index) {
    if (o == null) {
        for (int i = index ; i < elementCount ; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = index ; i < elementCount ; i++)
            if (o.equals(elementData[i])) // if the runtime type of o is String,
                                          // String's equals is executed
                return i;
    }
    return -1;
}

Upvotes: 1

Related Questions