I have to compare a Class object against a list of pre-defined classes.
Is it safe to use == or should I use equals?
if (klass == KlassA.class) {
} else if (klass == KlassB.class) {
} else if (klass == KlassC.class) {
} else {
}
Note: I cannot use instanceof, I don't have an object, I just have the Class object. I (mis)use it like an enum in this situation!
java.lang.Class does not override the equals method from java.lang.Object, which is implemented like this:
public boolean equals(Object obj) {
return (this == obj);
}
So a == b is the same as a.equals(b) (except if a is null).
I am not sure if this will work for your specific situation, but you could try Class.isAssignableFrom(Class).
KlassA.class.isAssignableFrom(klass)
For the most of the Java applications this is correct. However, comparing Java classes using the operator == is safe just if both the classes are loaded by the same classloader.
As mentioned in previous answers, to compare objects of Class type (or java.lang.Class objects) we should use == operator. However, It may be a bit confusing because always the result of comparison between objects through == operator can not cause right results (we usually use equal() method). For example, the result of this expression is false:
new String("book") == new String("book")//false
The reason is that,
The virtual machine manages a unique Class object for each type.
Therefore, you can use the == operator to compare java.lang.Class
objects. From Core Java for the Impatient - Page 153
Therefore:
new String("book").getClass() == new String("book").getClass()//true
or
Class.forName("java.lang.String") == Class.forName("java.lang.String")//true
result in true.
It's probably safe.
If the object doesn't override the Equals method it will make a comparison between the references. And if two variables point to the same object, their references match.
I prefer to use == for comparison between class objects and enum constants because it results in compilation time errors in case of incompatible types.
For example:
Class<?> cls1 = Void.class;
String cls2 = "java.lang.String";
if (cls1 == cls2) doSomething(); // Won't compile
if (cls1.equals(cls2)) doSomething(); // Will compile
Related
I'm trying to figure out what the syntax is for calling an object inside a method..
Pseudocode:
boolean check(Object someObject) {
return someObject == theOtherObject;
}
public static void main(String args[]) {
someClass one = new someClass();
someClass two = new someClass();
one.check(two);
}
So the check method is supposed to check whether the two objects are equal, but how would I specify the other object (theOtherObject should be one)?
Thanks in advance!
One word answer: this
boolean check(Object someObject) {
return someObject == this;
}
which will test object identity only. You should override equals and use that.
if (one.equals(two)) {
// ...
}
You can have the boolean check(Object o) method inside SomeClass and check
boolean check(Object o) {
this == (SomeClass) o;
}
This would work only if both reference variables are pointing to same object. Moreover the right way to check if two objects are meaningfully equal would be to use the inherited equals and hashCode method.
Override equals and hashCode method.
Why do I need to override the equals and hashCode methods in Java?
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-
So what you're asking for there is actually already a command in java.lang.Objects class to compare to objects.
one.equals(two)
the comparison this does is called a shallow comparison. So if that's what you're looking to do then this would work. For reference, the definitions of shallow comparison defined by geeksforgeeks.org is
Shallow comparison: The default implementation of equals method is defined in Java.lang.Object class which simply checks if two Object references (say x and y) refer to the same Object. i.e. It checks if x == y. Since Object class has no data members that define its state, it is also known as a shallow comparison.
if you're looking to do a more complicated comparison you're the best bet would be to actually override the equals command in the one class file
this article would be a good place to start to learn more about this topic.
https://www.geeksforgeeks.org/equals-hashcode-methods-java/
public boolean equals(Object o) {
if (this == o)
return true;
if ((o == null) || (this.getClass() != o.getClass()))
return false;
else {
AlunoTE umAluno = (AlunoTE) o;
return(this.nomeEmpresa.equals(umAluno.getNomeEmpresa()) && super.equals(umAluno);
}
}
Could anyone explain me how the fourth line ((this.getClass() != o.getClass())) works when the argument is a super class? Because the classes have different names. this.getClass will return a different name than o.getClass, right?
Check the following code snippet which answers your question. Object O can hold any object. o.getClass() will return the run time class of the object
public class Main {
void method(Object o) {
System.out.println(this.getClass() == o.getClass());
}
public static void main(String[] args) {
new Main().method(new Object()); // false
new Main().method(new Main()); // true
new Main().method(new String()); // false
new Main().method(new MainOne()); // false
}
}
class MainOne extends Main
{
}
So lets say there are two classes. Class A and Class B. Class A is a super class of class B. So this method would be in class B. "this.getClass()" refers to an object of class B while o.getClass()(The super class) will refer to class A. So Class B will not equal Class A. Meaning it will go into the if statement.
Suppose your super class is SHAPE and you have a class RECT that is a subclass of SHAPE.
If the this variable is for a RECT and the Object o is also a RECT,
then line 4 will return true because they are the same class (RECT).
The two objects will be equal as long as their types are the same at runtime.
However, if Object o is of type SQUARE, which also subclasses SHAPE,
(and could even subclass RECT).
then it will not be equal to the this pointer (RECT),
because their classes are different at runtime.
Now for why this kind of type checking is bad in the equals method (specifically for the use case of Hibernate entity classes).
If you use Hibernate and you are checking a newly created object whose class type is RECT against an object whose class type was RECT at the time it was cached in Hibernate, the class of the object in the cache will actually be a sub-class of type RECT, because Hibernate does byte-code manipulation and wraps the objects in a synthetic sub-class (RECT_$$javassist).
This means that your Hibernate cached objects that you expect to be equal will never be equal.
If the object is in a child collection, Hibernate will assume you wanted to delete the old object from the collection and create the new object in the collection instead of doing a (potential) update on an existing object in the collection.
We have legacy code that did this and could never figure out why (until now) it kept doing deletes and re-inserts on our collection.
For Hibernate entity objects you should use the instanceof operator to determine if two objects could be equal - and then cast Object o and continue the comparison operation with class SHAPE specific fields.
If your subclasses should not be considered equal, then you will have to implement equals() in each subclass to check for instanceof.
For other use cases, you will have to determine if there is a chance that someone (or some other library) could sub-class your Class (even through byte code manipulation) and whether any sub-classes should still be considered equal or not.
For instance, if you do any kind of mocking in your unit tests, a bad equals method may cause otherwise equal objects to be non-equal due to their classes not being equal.
Back to the OP's code. A better way to code the equals method would be:
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof AlunoTE))
return false;
AlunoTE umAluno = (AlunoTE) o;
return(this.nomeEmpresa.equals(umAluno.getNomeEmpresa()) && super.equals(umAluno);
}
Because the instanceof operator always returns false for null, there is no need for a null check too.
The following coding mistake is possible because the Boolean equals(Object) method doesn't require a boolean/Boolean argument:
private void foo() {
Boolean isSomeConditionTrue = false;
String doSomething = "YES";
if(isSomeConditionTrue.equals(doSomething)) {
// Do Something
}
}
This code won't "do something" because the coder forgot to evaluate doSomething as a String in the predicate. Why does the Boolean equals accept Object instead of boolean/Boolean as an argument?
Because equals() is defined in the Object class.
There is no possible signature it could have that would do what you want.
(without making Object generic, which would defeat the purpose)
This method overrides
Object.equals(Object)
and as such must accept all objects.
Similarly you can write
if (isSomeConditionTrue == doSomething)
even though this can never be true either.
One way around this is to avoid using Wrappers which cannot be null anyway. i.e. Your code will only work if the Boolean is not null so don't use the wrapper, use the primitive.
private void foo() {
boolean isSomeConditionTrue = false;
String doSomething = "YES";
if(isSomeConditionTrue == doSomething) { // doesn't compile
// Do Something
}
}
Primitives are not only faster, they make it clearer that the value cannot be null and you can use the normal Java operations like == != > etc.
equals() is a method on Object and the method contract requires that the parameter be an Object. The contract for equals states that if the object is the wrong type then it should return false.
So you must convert doSomething into a Boolean first. Note that even Boolean.parseBoolean(String) only will return a Boolean.TRUE if the String word "true" ignoring case. "yes" will not parse as TRUE.
I see gain in performance when using getClass() and == operator over instanceOf operator.
Object str = new Integer("2000");
long starttime = System.nanoTime();
if(str instanceof String) {
System.out.println("its string");
} else {
if (str instanceof Integer) {
System.out.println("its integer");
}
}
System.out.println((System.nanoTime()-starttime));
starttime = System.nanoTime();
if(str.getClass() == String.class) {
System.out.println("its string in equals");
} else {
if(str.getClass() == Integer.class) {
System.out.println("its integer");
}
}
System.out.println((System.nanoTime()-starttime));
Is there any guideline, which one to use getClass() or instanceOf?
Given a scenario: I know exact classes to be matched, that is String, Integer (these are final classes), etc.
Is using instanceOf operator bad practise ?
The reason that the performance of instanceof and getClass() == ... is different is that they are doing different things.
instanceof tests whether the object reference on the left-hand side (LHS) is an instance of the type on the right-hand side (RHS) or some subtype.
getClass() == ... tests whether the types are identical.
So the recommendation is to ignore the performance issue and use the alternative that gives you the answer that you need.
Is using the instanceOf operator bad practice ?
Not necessarily. Overuse of either instanceOf or getClass() may be "design smell". If you are not careful, you end up with a design where the addition of new subclasses results in a significant amount of code reworking. In most situations, the preferred approach is to use polymorphism.
However, there are cases where these are NOT "design smell". For example, in equals(Object) you need to test the actual type of the argument, and return false if it doesn't match. This is best done using getClass().
Terms like "best practice", "bad practice", "design smell", "antipattern" and so on should be used sparingly and treated with suspicion. They encourage black-or-white thinking. It is better to make your judgements in context, rather than based purely on dogma; e.g. something that someone said is "best practice". I recommend that everyone read No Best Practices if they haven't already done so.
Do you want to match a class exactly, e.g. only matching FileInputStream instead of any subclass of FileInputStream? If so, use getClass() and ==. I would typically do this in an equals, so that an instance of X isn't deemed equal to an instance of a subclass of X - otherwise you can get into tricky symmetry problems. On the other hand, that's more usually useful for comparing that two objects are of the same class than of one specific class.
Otherwise, use instanceof. Note that with getClass() you will need to ensure you have a non-null reference to start with, or you'll get a NullPointerException, whereas instanceof will just return false if the first operand is null.
Personally I'd say instanceof is more idiomatic - but using either of them extensively is a design smell in most cases.
I know it has been a while since this was asked, but I learned an alternative yesterday
We all know you can do:
if(o instanceof String) { // etc
but what if you dont know exactly what type of class it needs to be?
you cannot generically do:
if(o instanceof <Class variable>.getClass()) {
as it gives a compile error.
Instead, here is an alternative - isAssignableFrom()
For example:
public static boolean isASubClass(Class classTypeWeWant, Object objectWeHave) {
return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}
getClass() has the restriction that objects are only equal to other objects of the same class, the same run time type, as illustrated in the output of below code:
class ParentClass{
}
public class SubClass extends ParentClass{
public static void main(String []args){
ParentClass parentClassInstance = new ParentClass();
SubClass subClassInstance = new SubClass();
if(subClassInstance instanceof ParentClass){
System.out.println("SubClass extends ParentClass. subClassInstance is instanceof ParentClass");
}
if(subClassInstance.getClass() != parentClassInstance.getClass()){
System.out.println("Different getClass() return results with subClassInstance and parentClassInstance ");
}
}
}
Outputs:
SubClass extends ParentClass. subClassInstance is instanceof ParentClass.
Different getClass() return results with subClassInstance and parentClassInstance.
Is there any magic hanging around anywhere that could mean that
(object0 == object1) != (object0.equals(object1))
where object0 and object1 are both of a certain type which hasn't overridden Object.equals()?
No. That's exactly the definition of Object.equals().
...this method returns true if and only if x and y refer to the same object (x == y has the value true) ...
public boolean equals( Object o ) {
return this == o;
}
Yes, if by "The type of object0 doesn't override Object.equals()" you mean the specific type and not a superclass.
If object0 and object1 are of type B, B extends A, and A overrides equals(Object obj) but B doesn't, then it is possible that B doesn't override equals(Object obj) but (object0 == object1) != (object0.equals(object1)).
Well, if object0 == null and object1 == null, the first will deliver true, and the second a NullPointerException. Apart from that, there should be no observable difference.
Although the objects don't override equals() themselves, it is possible that one of superclasses of the object overrides the equals() method.
If you are using eclipse: open the object.java file and press control-o twice. Type 'equals' and check if you only see one 'equals' method: the equals method of Object.
The Object.java src defines its equals method as;
return (this == obj)
so no :-)
Yes, null == null is true, but null.equals(null) is not defined.
No, if equals() is not overridden, it returns true if the objects are the same identical objects in memory.
Here is the source code for Object.equals:
public boolean equals(Object obj) {
151 return (this == obj);
152 }
153
So, No.
No. The actual class of object0 (not necessarily the declared type of the variable) must have overridden equals(). Try printing out:
object0.getClass()