instanceof Vs getClass( ) - java

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.

Related

IntelliJ show "always true" hint but not "always false" for instanceof

So, I use IntelliJ IDEA to program in Java, and I was experimenting with the keyword instanceof and my code looked eventually like this:
public class Main {
public static void main(String args[])
{
One one = new One();
One two = new Two();
if (one instanceof Two)
{
System.out.println(one);
}
if (two instanceof Two)
{
System.out.println(one);
}
}
}
class One { }
class Two extends One { }
IntelliJ gives me at the two instanceof Two line a hint "[...] is allways true", but for one instanceof Two IntelliJ doesn't give me a "[...] is always false" hint. Does anyone know why?
Updated: fixed in IDEA 2018.3.
(Disclaimer: IntelliJ IDEA developer is here, who is responsible for this feature).
Short answer: because it's not implemented.
When we track an actual type of variable within the data flow analysis, we use a model described by TypeConstraint class. It allows us to track the facts of two kinds: 1) if variable actual type is instanceof something and 2) if variable actual type is not instanceof something. Having these facts we can infer always true/always false instanceof in many cases E.g.:
void test(Object foo) {
if (foo instanceof String) {
if (foo instanceof Integer) {
// always false: "instanceof String" fact is not compatible
// with "instanceof Integer"
}
}
}
Or
void test(Object foo) {
if (!(foo instanceof Number)) {
if (foo instanceof Integer) {
// always false: "not instanceof Number" fact is not compatible
// with "instanceof Integer"
}
}
}
However for your case this model is not enough. We need to extend it to track the exact type of variable. In your code we track that one is instanceof One (which is compatible with instanceof Two fact), despite from the new expression we could know more precise type information that one is exactly One. This is not often usable, because in most of the cases (variable is method parameter, variable is returned from method, variable is assigned from field, array element, cast expression etc.) we cannot know whether the type is exact or subtype, so the current model is completely satisfactory. I can imagine only two cases where exactly One fact tracking is useful: the new expression (like in your case) and after comparison like obj.getClass() == Xyz.class.
I think, it's a reasonable feature to implement. I already thought about this, but as somebody else besides me also cares, I filed an issue, so you can track it.

Inheritance and 'Instanceof' testing result

I'm studying 'instanceof' java, but I couldn't understand 'instanceof' clearly, I thought below answer would be true and false, but result is both true. Could you explain why this result happen? As I know, when A is child of B (Parent), and a instanceof B is 'false' but result is different with what I thought.
class Car{
String color;
int door;
}
class FireEngine extends Car{
void water(){
System.out.println("water");
}
}
public class Operator {
public static void main(String[] args) {
Car car = new FireEngine();
FireEngine fireCar = new FireEngine();
System.out.println(car instanceof FireEngine);
System.out.println(fireCar instanceof Car);
}
}
Declaration != Value
You declare car as an Car, but the Value is an FireEngine.
instanceof works based on values, not on the declarations of their variables!!!
Shortening may help to understand:
System.out.println(new FireEngine() instanceof FireEngine); // true
System.out.println(new FireEngine() instanceof Car); // true
The output of instanceof depends on the runtime type of the variable whose type you are testing. The compile time type of the variable doesn't matter (as long as it is possible that x instanceof Y will return true for some value of x, otherwise the expression won't pass compilation).
Both car and fireCar hold instances of FireEngine in your code. And since FireEngine is a kind of a Car, both car and fireCar are instanceof both Car and FireEngine, so your code prints true and true.
Implementation of the Instanceof operator. Returns a Boolean if the Object parameter (which can be an expression) is an instance of a class type.
Input 1: An object or Expression returning an object.
Input 2: A Class or an Expression returning a Class
Returns: A Boolean that is the result of testing the object against the Class.
For more information please go throught the javadocs # http://docs.oracle.com/cd/E13155_01/wlp/docs103/javadoc/com/bea/p13n/expression/operator/Instanceof.html
For more detailed explanation with examples please go through the following web page : http://mindprod.com/jgloss/instanceof.html
In Java there are two types of bindings: static (the reference type)
and dynamic (the object type).
In your case:
Car car = new FireEngine();
Car is the static type and FireEngine is dynamic type. It means, you are actually working with a FireEngine (the object type). You can imagine Car as a special pointer with a car shape pointing to the real object that is your awesome FireEngine. If you read 'instanceof' you can understand it, this method tell you if an object is an instance of a class, not the reference. So the compiler will see: FireEngine (car) instanceOf FireEngine? Of course, let's return a true!
You can have a look to this post also: What is the 'instanceof' operator used for?
The statement
As I know, when A is child of B (Parent),
and a instanceof B is 'false' but result is different with what I thought.
is not correct. instanceof does not check for the child, it tests for the parent.

calling specific methods of generic types in ny equals() method

I am working on the equals() method for my sparse matrix class that I'm writing (part of a school project). I am constantly runnung into the issue that it won't let me use any methods or other members specific to my class, because that(the name I used for the parameter to equals) has to be of the generic type Object in order to override Objects's equals() method. Even beyond that, I need to be able to use some of the methods of my SparseMatrix's type parameter in order to really compare the equality, unless I can also figure ou. How can I write it to get around that obstacle?
I have a few ideas how I night do it, but none of them seem to work: I've triedcasting the parameter, I've tried overlading equals(), I've even tried some other stuff, but none of it seems to work.
This is what I have so far, but, as I said, I just can't get it to work.
public boolean equals(Object that) {
if (that instanceof SparseMatrix<?>) {
if (this.xSize != that.xSize ||
this.ySize != that.ySize)
return false;
/* make some more comparisons that depend on specific
* members of my matrix class, etc...*/
}
return false;
}
I have tried searching SO for this, and while I was able to find a few that seemed to be asking the same thing, I couldn't find any answers that actually explained how to do it.
When you have an object of a base class and you know which kind of subclass it is, you can convert it by downcasting it. Then you can call any methods specific to the subclass.
public boolean equals(Object o) {
if (o instanceof SparseMatrix<?>) {
SparseMatrix that = (SparseMatrix)o; // <-- downcast
if (this.xSize != that.xSize ||
this.ySize != that.ySize)
return false;
}
return false;
}
Should o not be an instance of SparseMatrix or a class which extends/implements SparseMatrix (you already checked that, but let's assume you didn't) you would get a ClassCastException.
public boolean equals(Object that) {
if (that !=null && that instanceof SparseMatrix<?>) {
SparseMatrix that = (SparshMatrix)o;
if (this.xSize != that.xSize ||
this.ySize != that.ySize)
return false;
}
return false;
}
Added Code to check for null value.
You need to have this method overrided in the class whose instances you want to compare.. And when you actually invoke equals on instances of that class, this overrided method will be invoked..
** Moved from comment: - Using instanceof you can only assure of what type your instance is, and not the parameterized type of that instance.. (You cannot findout whether you have ArrayList<String>, what you can find out is that it is ArrayList or ArrayList<?> to be precise) .. Reason for that is, generic type information is only available at compile time, and is erased through type erasure , so they are not available at runtime..

Comparing Class objects

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

Is there any way other than instanceof operator for object type comparison in java?

I remember reading in some Java book about any operator other than 'instanceof' for comparing the type hierarchy between two objects.
instanceof is the most used and common. I am not able to recall clearly whether there is indeed another way of doing that or not.
Yes, there is. Is not an operator but a method on the Class class.
Here it is:
isIntance(Object o )
Quote from the doc:
...This method is the dynamic equivalent of the Java language instanceof operator
public class Some {
public static void main( String [] args ) {
if ( Some.class.isInstance( new SubClass() ) ) {
System.out.println( "ieap" );
} else {
System.out.println( "noup" );
}
}
}
class SubClass extends Some{}
You can also, for reflection mostly, use Class.isInstance.
Class<?> stringClass = Class.forName("java.lang.String");
assert stringClass.isInstance("Some string");
Obviously, if the type of the class is known at compile-time, then instanceof is still the best option.
The instanceof operation is the best option for two reasons:
1) It handles subtyping, so if you have an instance of a subclass/subtype you would still get true.
2) It handles null, so null instanceof Class would return false
If you take an object's class and then compare to another class, you're risking taking the class of a null object, and you can't directly get subtyping.
If you work with objects that represent classes, you can use the reflection operations, since instanceof would refer to their own class, Class, rather than to the class they represent.
if ( someClass.isAssignableFrom( obj.getClass() ) )
is equivalent to
if ( obj instanceof Foo )
Use instanceof if the class to be checked against is known at compile time, use isAssignableFrom if it is only known at runtime.

Categories

Resources