class A {}
class B extends A {}
public class Test {
public static void main(String[] args) {
B b = new B();
A a = new A();
// System.out.println(b.getClass() == A.class); //报错 1
// System.out.println(b.getClass() == a.getClass()); // false 2
System.out.println(b.getClass() == B.class); // true 3
}
}
为什么 1 这个位置会产生报错呢?b.getClass()
得到的结果是 class B
,而 A.class
得到的结果是 class A
,==
不是可以比较两个具有父子关系的两个对象吗?而 B 和 A 是有继承关系的呀。按我理解结果应该是 false ,但是编译器给出的结果却是报错,不太理解。
第 2 个位置b.getClass()
得到的结果是class B
,a.getClass()
得到的结果是class A
,得出的结果是 false ,这个和第 1 个位置有什么不同呢?第 1 个位置和第 2 个位置结果都是class A
和 class B
,但第一个却是报错的。
请问大佬这是为啥呢?
1
imzcg2 2022-11-15 14:27:31 +08:00
首先==是比较基本数据类型用的,比较对象一般用 equals 来比较,这个回答了问 1
根据第一个回答,比较的是对象,那么要看怎么比较对象是否相同的,是先比较对象的引用地址,然后再比较对象内容,Aclass 和 Bclass 都不是一个对象,比较结果肯定是 false 这个回答了问 2 结合上面回答 第三个为什么是 true 呢,因为这个是自己和自己比较,不是 true 还能是 false? |
2
imzcg2 2022-11-15 14:32:14 +08:00
|
3
imzcg2 2022-11-15 14:38:07 +08:00
而且再编程语言中 class 代表的是对象,一个 class 就是一个对象,不会连这个都不知道吧
|
4
qinxi 2022-11-15 14:55:26 +08:00
纠结语法错误没啥意思. javac 直接报错的东西没有任何讨论价值
至于 2 是 false, 因为 A.class 和 B.class 内存地址本身就不一样. 至于这种写法不报错, 因为 jvm 运行时认为这是合法的写法. 你也要明白, java (java 语言规范) 和 jvm(jvm 规范) 是可以分开的, 只要符合 jvm 规范的字节码文件都可以被 jvm 运行. |
5
jawe001 OP == 可以用来比较对象吧。虽然对象比较一般用 equals()。但我想问的是 b.getClass() 得到的结果是 class B 、a.getClass() 得到的结果是 class A ,而 A.class 得到的结果也是 class A ,为什么 2 可以运行(结果为 false ),但 1 却报错了(无法比较)
|
6
SeanChang 2022-11-15 15:09:29 +08:00 3
The incomparable types error is telling you that it doesn't make sense to compare two things that cannot possibly be equal.
For example, there's no point in Integer.valueOf(0) == "", because they're not the same types; nor is one a supertype of the other. It will always be false. The compiler will prevent the a == b if both are class types (as opposed to interfaces), and both a = b and b = a would be disallowed. So, you are being told that a Class<? extends T[]> cannot be equal to a Class<Object[]>, because you can't assign a reference of one type to a variable of the other type. By casting one of the references to Object, the compiler no longer knows (/thinks) that the types are definitely not related - because Object is a supertype of everything, so "nor is one a supertype of the other" is no longer true - so the compiler allows the check. One thing that is redundant in that method is U. There's no need for it, just use Object[] in the parameter type instead. |
8
imzcg2 2022-11-15 15:19:40 +08:00
@jawe001 #5 getclass 反回的类型是确定的 class 类型,.class 获得的编译器不确定,不确定的是不能比的呗
|
9
Hurriance 2022-11-15 15:22:24 +08:00
xx.getClass() 和 xx.class 不可比较
|
10
pocketz 2022-11-15 15:42:51 +08:00
有报错为啥不去看报错呢?
“Incompatible operand types Class<capture#1-of ? extends B> and Class<A>” == 只能用于相同类型的比较,你加一个强制转型就没报错了 顺便 https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass-- |
12
pocketz 2022-11-15 15:49:35 +08:00
|
13
wetalk 2022-11-15 15:59:11 +08:00
A.class 和 a.getClass(),虽然结果一致,但语义区别很大
|
14
jawe001 OP @imzcg2 如果说,“getclass 反回的类型是确定的 class 类型,.class 获得的编译器不确定,不确定的是不能比的呗” 那请问大佬,为啥第 3 个就能比呢?
|
15
makese 2022-11-15 16:34:55 +08:00
我看了下 1 的问题 b.getClass()应该是返回的 class 泛型应该是 extends B ,而 A.class 返回 class 的泛型是 A 。因为 A 并不属于 extends B 。你可以把 1 的 AB 换一下应该就不报错了。
|
16
zpf124 2022-11-15 18:28:49 +08:00
我来说一下.
1 、getclass 是返回 obj 的,那自然 NullPointerException 的可能(这里是不是应该会 NoClassFound 啊?)。 2 、class 不同 自然不相等, 因为 class 也是对象,所有反射类都是对象,只不过这个对象是 jvm 创建的并且与 jvm 中实际的 class 操作绑定。 3 、jvm 中 默认的类加载器中每个 class 是唯一的,也就是说如果你没有自定义类加载器修改相关方法,然后通过你自定义的类加载器加载这个 class 的话, 不论是 b.class 、new B().getClasss()、class.forName("B") 实际上返回的都是 jvm 默认创建的那一个 B class 的绑定对象。 |
17
apake 2022-11-15 18:45:31 +08:00
B.class => Class<B>
A.class => Class<A> b.getClass() => Class<? extends B> a.getClass() => Class<? extends A> 第二个可以编译, 因为 Class<? extends B> 是 Class<? extends A> 的 subtype 第三个可以编译, 因为 Class<B> 是 Class<? extends B> 的 subtype 第一个报错, 因为 Class<? extends B> 与 Class<A> 之间不构成 super-subtype 关系 |
18
jawe001 OP 感谢大佬们为小弟进行解惑。非常感谢!
|
19
goalidea 2022-11-17 13:17:17 +08:00
你是纯纯的 java 基础不扎实,去 oracle 官网仔细看看 jls 。如果看英文有障碍就买本 java 基础书看看
|
20
MineDog 2022-11-22 15:12:33 +08:00
按我的理解,这就是编译器对 class 判断做的一个短路优化吧,我的猜测是,编译器可以在编译阶段直接确定"=="两侧值且一侧是 X.class 声明格式,如果结果为 false 时,就直接报错。
|
21
MineDog 2022-11-28 09:25:06 +08:00
java 语言规范中有相关描述,不过没有规定更具体场景,https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3
|