V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jawe001
V2EX  ›  Java

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

  •  
  •   jawe001 · 2022-11-15 13:58:58 +08:00 · 2658 次点击
    这是一个创建于 729 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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,但第一个却是报错的。

    请问大佬这是为啥呢?

    21 条回复    2022-11-28 09:25:06 +08:00
    imzcg2
        1
    imzcg2  
       2022-11-15 14:27:31 +08:00
    首先==是比较基本数据类型用的,比较对象一般用 equals 来比较,这个回答了问 1

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

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

    而且用 idea 开发 这么大的警告 看不见吗
    imzcg2
        3
    imzcg2  
       2022-11-15 14:38:07 +08:00
    而且再编程语言中 class 代表的是对象,一个 class 就是一个对象,不会连这个都不知道吧
    qinxi
        4
    qinxi  
       2022-11-15 14:55:26 +08:00
    纠结语法错误没啥意思. javac 直接报错的东西没有任何讨论价值
    至于 2 是 false, 因为 A.class 和 B.class 内存地址本身就不一样. 至于这种写法不报错, 因为 jvm 运行时认为这是合法的写法. 你也要明白, java (java 语言规范) 和 jvm(jvm 规范) 是可以分开的, 只要符合 jvm 规范的字节码文件都可以被 jvm 运行.
    jawe001
        5
    jawe001  
    OP
       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
        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.
    chendy
        7
    chendy  
       2022-11-15 15:15:09 +08:00
    @SeanChang 头一次看到这么全面的解释
    PS ,看到报错第一反应都加上 (Object) 果然就可以编译了
    imzcg2
        8
    imzcg2  
       2022-11-15 15:19:40 +08:00
    @jawe001 #5 getclass 反回的类型是确定的 class 类型,.class 获得的编译器不确定,不确定的是不能比的呗
    Hurriance
        9
    Hurriance  
       2022-11-15 15:22:24 +08:00
    xx.getClass() 和 xx.class 不可比较
    pocketz
        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--
    pocketz
        11
    pocketz  
       2022-11-15 15:45:19 +08:00
    @SeanChang 我靠,这个强
    pocketz
        12
    pocketz  
       2022-11-15 15:49:35 +08:00
    wetalk
        13
    wetalk  
       2022-11-15 15:59:11 +08:00
    A.class 和 a.getClass(),虽然结果一致,但语义区别很大
    jawe001
        14
    jawe001  
    OP
       2022-11-15 16:29:43 +08:00
    @imzcg2 如果说,“getclass 反回的类型是确定的 class 类型,.class 获得的编译器不确定,不确定的是不能比的呗” 那请问大佬,为啥第 3 个就能比呢?
    makese
        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 换一下应该就不报错了。
    zpf124
        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 的绑定对象。
    apake
        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 关系
    jawe001
        18
    jawe001  
    OP
       2022-11-15 21:12:41 +08:00
    感谢大佬们为小弟进行解惑。非常感谢!
    goalidea
        19
    goalidea  
       2022-11-17 13:17:17 +08:00
    你是纯纯的 java 基础不扎实,去 oracle 官网仔细看看 jls 。如果看英文有障碍就买本 java 基础书看看
    MineDog
        20
    MineDog  
       2022-11-22 15:12:33 +08:00
    按我的理解,这就是编译器对 class 判断做的一个短路优化吧,我的猜测是,编译器可以在编译阶段直接确定"=="两侧值且一侧是 X.class 声明格式,如果结果为 false 时,就直接报错。
    MineDog
        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
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5845 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 46ms · UTC 02:58 · PVG 10:58 · LAX 18:58 · JFK 21:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.