为什么可以在 Java 中通过引用比较不兼容的类型?
Why is it possible to compare incompatible types by reference in Java?
看看这个片段:
List<Integer> c = new ArrayList<>();
Map<String,Boolean> m = new HashMap<>();
if( c == m ) //no error here! WHY?
{
c = m; //"Incompatible types" error, as expected.
m = c; //"Incompatible types" error, as expected.
}
为什么c == m
没有报错?
我正在使用 jdk1.8.0.20 的 javac,我没有理由怀疑它无视 java 语言规范,所以这是相当绝对的确定性在规范中,所以:
规范允许这样的东西有什么意义/目的/用处?
出现Incompatible types
错误是因为当赋值被触发时,一个名为Assignment conversion的操作开始了。它的作用是:
Assignment conversion occurs when the value of an expression is assigned (§15.26) to a variable: the type of the expression must be converted to the type of the variable.
如果转换失败,则会抛出编译时错误。
但是,当 == operator 发生时,不会抛出编译时错误。
写的时候
if(c==m)
你只是在检查@hashcode 在某些情况下两个对象可能相同,所以你可能不会在该行中收到任何错误!
仅仅因为类型不可转换并不意味着它们不是相等的对象。如果类型是 "Inconvertible",则意味着需要强制转换来检查类型实际上是否可转换。
interface Outputer extends Consumer<String>, Serializable { }
Outputer out = System.out::println;
Consumer<String> cs = out;
Serializable s = out;
System.out.println(s == cs); // prints true
// s = cs; // Inconvertible types, doesn't compile
s = (Serializable) cs; // compiles and runs fine.
cs
和 s
是不可转换的类型,但它们指向同一个对象并且打印 true
这是允许的,因为 List
和 Map
是接口。
我们可以想象一些 class
// (please only imagine)
class ListMap implements List, Map {...}
引用相等性的编译时合法性 (15.21.3) is the same as that of reference type casting (5.5.1)。简而言之,由于您通常可以在任何引用类型和接口之间进行转换,因此您通常也可以将任何类型的引用相等性与接口进行比较。
权限似乎在 Comparable
、Serializable
、Iterable
等较小接口的上下文中更有用,其中 class 更有可能实现不止一个。
在Java中,只要你有对象,系统就会使用指针。当您在两个对象上使用 ==
时,它会比较它们的 指针 。换句话说,它检查两个指针是否指向内存中的同一个对象。这始终是一个安全的检查。
另外,应该注意的是,当涉及继承(和polymorphism)时,可能有多个不同类型的指针指向同一个对象。当然,在您的示例中并非如此。但正如我之前所说,检查两个指针是否指向同一个对象是无害的,因为该检查不会对所涉及的 类 做出任何假设。
看看这个片段:
List<Integer> c = new ArrayList<>();
Map<String,Boolean> m = new HashMap<>();
if( c == m ) //no error here! WHY?
{
c = m; //"Incompatible types" error, as expected.
m = c; //"Incompatible types" error, as expected.
}
为什么c == m
没有报错?
我正在使用 jdk1.8.0.20 的 javac,我没有理由怀疑它无视 java 语言规范,所以这是相当绝对的确定性在规范中,所以:
规范允许这样的东西有什么意义/目的/用处?
出现Incompatible types
错误是因为当赋值被触发时,一个名为Assignment conversion的操作开始了。它的作用是:
Assignment conversion occurs when the value of an expression is assigned (§15.26) to a variable: the type of the expression must be converted to the type of the variable.
如果转换失败,则会抛出编译时错误。
但是,当 == operator 发生时,不会抛出编译时错误。
写的时候
if(c==m)
你只是在检查@hashcode 在某些情况下两个对象可能相同,所以你可能不会在该行中收到任何错误!
仅仅因为类型不可转换并不意味着它们不是相等的对象。如果类型是 "Inconvertible",则意味着需要强制转换来检查类型实际上是否可转换。
interface Outputer extends Consumer<String>, Serializable { }
Outputer out = System.out::println;
Consumer<String> cs = out;
Serializable s = out;
System.out.println(s == cs); // prints true
// s = cs; // Inconvertible types, doesn't compile
s = (Serializable) cs; // compiles and runs fine.
cs
和 s
是不可转换的类型,但它们指向同一个对象并且打印 true
这是允许的,因为 List
和 Map
是接口。
我们可以想象一些 class
// (please only imagine)
class ListMap implements List, Map {...}
引用相等性的编译时合法性 (15.21.3) is the same as that of reference type casting (5.5.1)。简而言之,由于您通常可以在任何引用类型和接口之间进行转换,因此您通常也可以将任何类型的引用相等性与接口进行比较。
权限似乎在 Comparable
、Serializable
、Iterable
等较小接口的上下文中更有用,其中 class 更有可能实现不止一个。
在Java中,只要你有对象,系统就会使用指针。当您在两个对象上使用 ==
时,它会比较它们的 指针 。换句话说,它检查两个指针是否指向内存中的同一个对象。这始终是一个安全的检查。
另外,应该注意的是,当涉及继承(和polymorphism)时,可能有多个不同类型的指针指向同一个对象。当然,在您的示例中并非如此。但正如我之前所说,检查两个指针是否指向同一个对象是无害的,因为该检查不会对所涉及的 类 做出任何假设。