Why is second SOP showing output as true here, I was hoping it would display false like first SOP ?
public class reflect1 {
public static void main(String[] args) {
Reflect1A obj1 = new Reflect1A();
Reflect1A obj2 = new Reflect1A();
System.out.println(obj1 == obj2);
Class c1 = obj1.getClass();
Class c2 = obj2.getClass();
System.out.println(c1 == c2);
}
}
class Reflect1A {
}
From the Java Language Specification
The method getClass returns the Class object that represents the class of the object.
A Class object exists for each reference type. It can be used, for
example, to discover the fully qualified name of a class, its members,
its immediate superclass, and any interfaces that it implements.
Since both your objects are of type Reflect1A, they both return the same Class object.
You would get the same object by doing
Class<?> clazz = Class.forName("com.example.Reflect1A")
System.out.println(c1 == clazz); // true
(though this is not necessarily required by all classloaders.)
The values of obj1 and obj2 refer to different objects - when you use == in Java and both operands are references, the result is to compare whether those references refer to the exact same object. In this case you've got two different objects, so the references are not the same.
However, they're both of the same class, so that's why c1 == c2 is true.
The first line prints false because it is a different instance of the same class.
The second line prints true because it is the same class type. There is a obscure gotcha here to be aware of, if you're in a multiple classloader environment, e.g. an application server like JBoss, or OSGI etc, it is possible for two class instances to not be equal
An object is equal (==) only to itself. So clearly both getClass() statements are returning the same Class object
Because obj1 and obj2 are different instances (first check is false) of the same type (class - second check is true).
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass%28%29
why did you expect to return false?
The operator == compares the references in which the objects are created by default
Obj1 and Obj2 are of same type class Reflect1. For these objects are equal only when compared like this obj1.equal(obj2).
While the class type of obj1 and obj2 are the same == operation will be true.
Related
I come up with the scenario & can't understand the logic behind it ? I understood the first one only, rest two unable to understand ? Please explain how internally it work?
public class Test {
public static void main(String[] args) {
String s = "Karan";
Object o = "Karan";
System.out.println(s.equals(o)); // True
System.out.println(o.equals(s)); // True
System.out.println(s == o); // True
}
}
String s = "Karan" this is a String object referred by a String reference.
Object o = "Karan" this is a String object referred by an Object reference. Super class can refer to object of sub-class.
For both s.equals(o) and o.equals(s) the underlying objects equal() is called, since the objects are of type String (even if reference 'o' is of type Object) String's equals is called which compares the value of the string which are equal. That is what you got true as result.
s == o compares the object reference of s and o. They were created using double quote which uses the String pool, creates the object once and refers it again. So both s and o are exactly same String object. This makes == return true.
There is a difference between the static type of an object and the dynamic type of a variable.
The static type is the type known at compile time. For Object o = "Karan";, the static type is the one at the left of o, i.e. Object. Now, one could ask why that is the case since at compile-time, it can be inferred that o is a String. Well if we consider something like
Object o;
if (someCondition) {
o = "Karam";
} else {
o = new StringBuffer();
}
then we cannot know whether o is a String or a StringBuffer, thus its static type is Object (since o is defined as Object).
The dynamic type is the type at runtime. In the example above, after the if-statement has been executed, o is either a String or a StringBuffer, but not both and nothing else. In your example, the dynamic type of Object o = "Karan"; is String.
When variables are compared through equals(...), they must have the same dynamic type in order for the comparison to return true (notice that this property is necessary, but not sufficient). Since o in your example is, in fact, a String AND the content is equal to s, s.equals(o) == o.equals(s) == true.
As to why s == o returns true: the question is answered in this post.
How do I let the user insert a String and check for classes with the same "name"?
Imagine I have a method marked as public A[] getB(String bString) and two classes, A and B, where B extends A.
In this method I want to search through an existing A[] for objects that are upcast from being from the class B and return an A[] with said objects.
I searched through the internet and found out that the class Class has the method forName(), but I don't really understand how to use it. For example, I do this:
Class<?> cl = Class.forName(bString);
Where bString is a String that contains B, B being another class.
My questions are:
What exactly is the object "cl" now?
How could I now check if objects are of the same class as it?
What exactly is the object "cl" now?
cl is an instance of Class class.
How could I now check if objects are of the same class as it?
you have 2 object o1 and o2 you can use getClass()
o1 != null && o2 != null && o1.getClass().equals(o2.getClass())
The method Class.forName(String) returns a Class object for the corresponding class, if known. To quote from its documentation:
Returns the Class object associated with the class or interface with the given string name.
An example would be:
Class threadClass = Class.forName("java.lang.Thread");
Note that the name of the class needs to be fully qualified, not just Thread but java.lang.Thread.
The object you are getting is, as said, a representation of the corresponding class. You can use it to dynamically create instances, check methods, and so on. Here is its documentation and here is an example:
Class<?> threadClass = Class.forName("java.lang.Thread");
// Dynamically create a thread, unchecked cast
Thread thread = (Thread) threadClass.newInstance();
You can check whether two objects are of the same class by using the getClass (documentation) method which every object has:
if (first.getClass().equals(second.getClass()) {
// Same
} else {
// Different
}
However note that this comparison is strict. It would throw false if you compare Integer and Number although Integer extends Number. If you want a less strict variant you may use the instanceof operator:
if (first instanceof second) {
// Is type of
} else {
// Not type of
}
are you sure you wouldn't rather use isInstance?
You could change your method to take a Class instead of a String, since that's what you're really using, a Class.
public A[] getB(Class type){
// I'm assuming you have an array of all As somewhere, called Aarray here
List<A> BList = new ArrayList<>();
for(int i = 0; i < Aarray.length; i++){
if(type.isInstance(Aarray[i])){
BList.add(Aarray[i]);
}
}
return BList.toArray();
}
I'm a beginner in Java programming. Currently I'm reading about Inheritance and the equals method at this page.
I understand the explanations until this point:
Compare the classes of this and otherObject. If the semantics of
equals can change in subclasses, use the getClass test:
if (getClass() != otherObject.getClass()) return false;
If the same semantics holds for all subclasses, you can use an instanceof test:
if (!(otherObject instanceof ClassName)) return false;
I don't understand what 'semantics of equals' mean. Can someone share scenarios where we use getClass() and instanceof please?
Thank you for reading.
Simply put, getClass() returns the immediate class of the object. for example,
class A { }
class B extends A { }
if we create two objects from A and B,
A objA = new A();
B objB = new B();
now we can check how getClass work
System.out.println(objA.getClass()); //Prints "class A"
System.out.println(objB.getClass()); //Prints "class B"
So,
objA.getClass() == objB.getClass()
returns false. But
System.out.println(objB instanceof A); //Prints true
This is because instanceof returns true even if a superclass is given of the provided object.
So, when you design your equals() method, if you want to check the given object(otherObject) is instantiated from the same immediate Class, use the
if (getClass() != otherObject.getClass()) return false;
If it is okay that the given object(otherObject) is made even from a subclass of a Class (ClassName) you provide, use
if (!(otherObject instanceof ClassName)) return false;
Simply, "semantics of equals" means "The purpose you expect from equals() method". So you can use the appropriate method according to your need.
changing semantics of equals
It means that may be the equals method can be overwritten in subclasses, in such scenarios use getClass to check whether objects belong to same class.
In general, getClass vs instance of
We use getClass when we need to know the class of a particular object. Consider cases when there is linear chain of Inheritance as follows:
MainClass -> SubClassLevel1 -> SubClassLevel2
and initialize as
MainClass mc = new SubClassLevel2();
Here to know that which class in the hierarchy is the class of our object.
Now, instance of method is used in the cases where you have to merely check that whether x is an instance of class Y or not. It returns boolean.
Hope this answers your query :)
I want to compare the class type in Java.
I thought I could do this:
class MyObject_1 {}
class MyObject_2 extends MyObject_1 {}
public boolean function(MyObject_1 obj) {
if(obj.getClass() == MyObject_2.class) System.out.println("true");
}
I wanted to compare in case if the obj passed into the function was extended from MyObject_1 or not.
But this doesn't work. It seems like the getClass() method and the .class gives different type of information.
How can I compare two class type, without having to create another dummy object just to compare the class type?
Try this:
MyObject obj = new MyObject();
if(obj instanceof MyObject){System.out.println("true");} //true
Because of inheritance this is valid for interfaces, too:
class Animal {}
class Dog extends Animal {}
Dog obj = new Dog();
Animal animal = new Dog();
if(obj instanceof Animal){System.out.println("true");} //true
if(animal instanceof Animal){System.out.println("true");} //true
if(animal instanceof Dog){System.out.println("true");} //true
For further reading on instanceof: http://mindprod.com/jgloss/instanceof.html
If you don't want to or can't use instanceof, then compare with equals:
if(obj.getClass().equals(MyObject.class)) System.out.println("true");
BTW - it's strange because the two Class instances in your statement really should be the same, at least in your example code. They may be different if:
the classes have the same short name but are defined in different packages
the classes have the same full name but are loaded by different classloaders.
It prints true on my machine. And it should, otherwise nothing in Java would work as expected. (This is explained in the JLS: 4.3.4 When Reference Types Are the Same)
Do you have multiple classloaders in place?
Ah, and in response to this comment:
I realise I have a typo in my
question. I should be like this:
MyImplementedObject obj = new MyImplementedObject ();
if(obj.getClass() == MyObjectInterface.class) System.out.println("true");
MyImplementedObject implements
MyObjectInterface So in other words, I
am comparing it with its implemented
objects.
OK, if you want to check that you can do either:
if(MyObjectInterface.class.isAssignableFrom(obj.getClass()))
or the much more concise
if(obj instanceof MyobjectInterface)
As said earlier, your code will work unless you have the same classes loaded on two different class loaders.
This might happen in case you need multiple versions of the same class in memory at the same time, or you are doing some weird on the fly compilation stuff (as I am).
In this case, if you want to consider these as the same class (which might be reasonable depending on the case), you can match their names to compare them.
public static boolean areClassesQuiteTheSame(Class<?> c1, Class<?> c2) {
// TODO handle nulls maybe?
return c1.getCanonicalName().equals(c2.getCanonicalName());
}
Keep in mind that this comparison will do just what it does: compare class names; I don't think you will be able to cast from one version of a class to the other, and before looking into reflection, you might want to make sure there's a good reason for your classloader mess.
Comparing an object with a class using instanceOf or ... is already answered.
If you have two objects and you want to compare their types with each other, you can use:
if (obj1.getClass() == obj2.getClass()) {
// Both have the same type
}
If you had two Strings and compared them using == by calling the getClass() method on them, it would return true. What you get is a reference on the same object.
This is because they are both references on the same class object. This is true for all classes in a java application.
Java only loads the class once, so you have only one instance of a given class at a given time.
String hello = "Hello";
String world = "world";
if (hello.getClass() == world.getClass()) {
System.out.println("true");
} // prints true
Hmmm... Keep in mind that Class may or may not implement equals() -- that is not required by the spec. For instance, HP Fortify will flag myClass.equals(myOtherClass).
Check Class.java source code for equals()
public boolean equals(Object obj) {
return this == obj;
}
I have a question about the Java "equals" method.
I created a class called Person:
public class Person {
}
And I am comparing two references to Person like this.
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.equals(p2)); //returns false
If I add any instance variable and setter method to set the instance variable, then the "equals" method returns true.
Can anybody explain this behavior?
If you do not override Object.equals(Object) then the default implementation uses the objects identity for comparison. (i.e. equals only returns true if the objects are the same object in memory).
Relevant JavaDoc: Object.equals
Excerpt:
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).
Object a = new Object();
Object b = new Object();
System.out.println(a.equals(b)); // Prints 'false'
b = a;
System.out.println(a.equals(b)); // Prints 'true'
As I mentioned in one of my comments the additions of methods or fields should not affect the default implementation of equals method, something else must be going on.
p1 and p2 are two different references, that's why. It will return false unless you have your own equals method. It doesn't matter if you have instance variable or not.