求 Java 大佬帮忙分析下这个程序

2022-11-15 13:58:58 +08:00
 jawe001
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 Ba.getClass() 得到的结果是class A,得出的结果是 false ,这个和第 1 个位置有什么不同呢?第 1 个位置和第 2 个位置结果都是class Aclass B,但第一个却是报错的。

请问大佬这是为啥呢?

2665 次点击
所在节点    Java
21 条回复
imzcg2
2022-11-15 14:27:31 +08:00
首先==是比较基本数据类型用的,比较对象一般用 equals 来比较,这个回答了问 1

根据第一个回答,比较的是对象,那么要看怎么比较对象是否相同的,是先比较对象的引用地址,然后再比较对象内容,Aclass 和 Bclass 都不是一个对象,比较结果肯定是 false 这个回答了问 2

结合上面回答 第三个为什么是 true 呢,因为这个是自己和自己比较,不是 true 还能是 false?
imzcg2
2022-11-15 14:32:14 +08:00
https://imgse.com/i/zEGBad
https://imgse.com/i/zEG0VH

而且用 idea 开发 这么大的警告 看不见吗
imzcg2
2022-11-15 14:38:07 +08:00
而且再编程语言中 class 代表的是对象,一个 class 就是一个对象,不会连这个都不知道吧
qinxi
2022-11-15 14:55:26 +08:00
纠结语法错误没啥意思. javac 直接报错的东西没有任何讨论价值
至于 2 是 false, 因为 A.class 和 B.class 内存地址本身就不一样. 至于这种写法不报错, 因为 jvm 运行时认为这是合法的写法. 你也要明白, java (java 语言规范) 和 jvm(jvm 规范) 是可以分开的, 只要符合 jvm 规范的字节码文件都可以被 jvm 运行.
jawe001
2022-11-15 14:55:28 +08:00
== 可以用来比较对象吧。虽然对象比较一般用 equals()。但我想问的是 b.getClass() 得到的结果是 class B 、a.getClass() 得到的结果是 class A ,而 A.class 得到的结果也是 class A ,为什么 2 可以运行(结果为 false ),但 1 却报错了(无法比较)
SeanChang
2022-11-15 15:09:29 +08:00
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.
chendy
2022-11-15 15:15:09 +08:00
@SeanChang 头一次看到这么全面的解释
PS ,看到报错第一反应都加上 (Object) 果然就可以编译了
imzcg2
2022-11-15 15:19:40 +08:00
@jawe001 #5 getclass 反回的类型是确定的 class 类型,.class 获得的编译器不确定,不确定的是不能比的呗
Hurriance
2022-11-15 15:22:24 +08:00
xx.getClass() 和 xx.class 不可比较
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--
pocketz
2022-11-15 15:45:19 +08:00
@SeanChang 我靠,这个强
pocketz
2022-11-15 15:49:35 +08:00
wetalk
2022-11-15 15:59:11 +08:00
A.class 和 a.getClass(),虽然结果一致,但语义区别很大
jawe001
2022-11-15 16:29:43 +08:00
@imzcg2 如果说,“getclass 反回的类型是确定的 class 类型,.class 获得的编译器不确定,不确定的是不能比的呗” 那请问大佬,为啥第 3 个就能比呢?
makese
2022-11-15 16:34:55 +08:00
我看了下 1 的问题 b.getClass()应该是返回的 class 泛型应该是 extends B ,而 A.class 返回 class 的泛型是 A 。因为 A 并不属于 extends B 。你可以把 1 的 AB 换一下应该就不报错了。
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 的绑定对象。
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 关系
jawe001
2022-11-15 21:12:41 +08:00
感谢大佬们为小弟进行解惑。非常感谢!
goalidea
2022-11-17 13:17:17 +08:00
你是纯纯的 java 基础不扎实,去 oracle 官网仔细看看 jls 。如果看英文有障碍就买本 java 基础书看看
MineDog
2022-11-22 15:12:33 +08:00
按我的理解,这就是编译器对 class 判断做的一个短路优化吧,我的猜测是,编译器可以在编译阶段直接确定"=="两侧值且一侧是 X.class 声明格式,如果结果为 false 时,就直接报错。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/895388

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX