So lets see how we can test for ”param is valid type”.

Bar
[code lang=”java”]
public class Bar {
}
[/code]

Test
[code lang=”java”]
public class Test {
private static final Class CLS = Bar.class;

public static void test1(Object a) {
if (a instanceof Bar) {
int x = 0;
}
}
public static void test2(Object a) {
if (a.getClass() == Bar.class) {
int x = 0;
}
}
public static void test3(Object a) {
if (a.getClass() == CLS) {
int x = 0;
}
}
}
[/code]

These translate into this

Bar Disassembled: javap -c Bar
[code lang=”java”]
public class Bar extends java.lang.Object{
public Bar();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object.””:()V
4: return

}
[/code]

Test Disassembled: javap -c Test
[code lang=”java”]
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object.””:()V
4: return

public static void test1(java.lang.Object);
Code:
0: aload_0
1: instanceof #2; //class Bar
4: ifeq 9
7: iconst_0
8: istore_1
9: return

public static void test2(java.lang.Object);
Code:
0: aload_0
1: invokevirtual #3; //Method java/lang/Object.getClass:()Ljava/lang/Class;
4: ldc_w #2; //class Bar
7: if_acmpne 12
10: iconst_0
11: istore_1
12: return

public static void test3(java.lang.Object);
Code:
0: aload_0
1: invokevirtual #3; //Method java/lang/Object.getClass:()Ljava/lang/Class;
4: getstatic #4; //Field CLS:Ljava/lang/Class;
7: if_acmpne 12
10: iconst_0
11: istore_1
12: return

static {};
Code:
0: ldc_w #2; //class Bar
3: putstatic #4; //Field CLS:Ljava/lang/Class;
6: return

}
[/code]

So what we learn from this, hopefully something. At least it seems that it’s not good idea trying to outsmart compiler, and secondly it doesn’t matter. I.e. I believe that in this case there isn’t any differerence in performance, however, it seems that instanceof version creates slightly shorter bytecode. However, must be noted that there is various very valid reasons for exact class equality instead of instanceof.

For example,

Ensuring that equals() produces correct results

[code lang=”java”]
public class Foo {
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o == null) {
return false;
}
if (o.getClass() == getClass() {
// …
}
return false;
}
}
[/code]

[code lang=”java”]
public class Bar extends Foo {
// …
}
[/code]

Strict class equality ensures here that equals() contract is implemented properly, with instanceof, Foo could equal to Bar, but Bar would not equal to Foo.

If you’ve developed with java long enough, you surely have had enough of horror stories of equals() -methods, which implement interesting hacks to provide equality between Apples and Oranges (naturally without any documentation, and at some point of time those hacks start to haunt you when some refactoring is done, and fixing hacks is difficult, since there ain’t any clear traces why such strange things exists at all).

PS. Please notice that ”a != null” checks are irrelevant in the Test class, since it conforms into standard safe API spec convention. This convention states that all values (param or return) are NON-NULL unless otherwise stated. I.e. makes programming much easier, since that is the best default value. Thus when you conform to this convention, safe API spec is specified with minimal effort, and it also promotes using safe methods (i.e. no horror stories of methods, without any kind of specifications, returning randomly null values, which can cumulate incredible amount of highly unclear and unmaintainable code in the full call chain for such methods).

References:
JavaWiki: PerformanceTechniques

/ java

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *

This site uses Akismet to reduce spam. Learn how your comment data is processed.