【问题标题】:Partial access from class type variable that points at an instance of a specialized type从指向特定类型实例的类类型变量的部分访问
【发布时间】:2013-04-21 20:44:36
【问题描述】:

当声明一个指向特定类型实例的类类型变量时,对象类型由实例化而不是声明决定。示例:

Object o = new ArrayList<>();
if(o instanceof ArrayList)
System.out.println("ArrayList it is!");

所以,ArrayList 只能使用 Object 的方法和属性,在这种情况下,即使我向下转型。 ArrayList 怎么可能只是部分实现,如果将类型设为 Object 不是更有意义吗?

另外,为什么可以在没有通用声明的情况下使用菱形推理?

【问题讨论】:

  • 这应该打印“ArrayList it is!”,但是“ArrayList”看起来很奇怪(应该是 ArrayList 或 ArrayList)...这是否可以编译?
  • 尝试重新表述您的问题,因为即使是第一句话也似乎有点胡言乱语。 “编程到接口”?你的意思是实现一个接口?为什么用“实际”?
  • 不会键入擦除使 ArrayList 和 ArrayList 是相同的类型,Jacob?
  • 不,当我们实际使用接口类型的引用变量并使其引用其类也实现它的对象时,我们对接口进行编码。当您使超类引用引用子类对象时,您正在使用继承和(如果您选择)多态性。
  • 我认为您混淆了“抽象类”和“接口”这两个术语。抽象类是具有部分实现并且不能被实例化的类。只有它的子类可以被实例化为对象。接口永远不会有任何实现。它仅表示 API 与其实现者之间的合同。 “所有类都有接口”这句话并不完全正确,因为绝对有可能编写一个不实现任何接口的类。

标签: java class inheritance interface casting


【解决方案1】:
Object O = new ArrayList<>();

这个特定的代码说; “创建一个Object 类型的引用变量o 并将其指向在堆上创建的新ArrayList&lt;&gt; 对象。”

jvm 运行代码时会检查instanceof 条件。即使引用变量是Object 类型,在执行期间创建的实际对象也是ArrayList 对象。

如果您尝试使用Object 引用变量oArrayList&lt;&gt; 的任何属性/方法,例如o.size(); 编译器会报错。

【讨论】:

    【解决方案2】:

    Java 7 之前的空菱形是所谓的原始泛型,实际上这意味着容器不会对所包含的项目强制执行任何类型约束,除了它们应该是一个对象。所以基本上new ArrayList&lt;&gt;();new ArrayList(); 意味着new ArrayList&lt;Object&gt;();。这基本上会抛弃 Java 泛型提供的任何类型安全性。

    @scottb 提醒我们:Java 7 为空菱形提供了更好的用法:通过编译器执行类型推断,您的代码可以更简洁,更不容易出错。你可以说HashMap&lt;String, Integer&gt; m = new HashMap&lt;&gt;();,而不是HashMap&lt;String, Integer&gt; m = new HashMap&lt;String, Integer&gt;();

    对于第一部分:java.lang.Object 是您在使用 o 变量引用 ArrayList 对象时感知到的类型。 instanceof 运算符不关心 o 的类型是什么,它会准确回答您的问题:“存储在”变量 o 后面的东西是否真的是 ArrayList

    【讨论】:

    • 我认为这个关于钻石算子的结论是不正确的。菱形运算符仅表明编译器通过推断而不是通过显式声明来确定引用类型。说菱形运算符意味着类型是原始的、弱的、未指定的或通用的是不正确的。编译器肯定会强制执行严格的类型检查。
    • 谢谢@scottb,你说得对,Java 7 有了新的含义。
    • 我又吃了一个啊哈!经验,感谢您对“存储在变量后面”的澄清。如果我创建一个 ArrayList 类型的新变量,它指向与 o 变量相同的对象,我将获得对所有公共 ArrayList 方法的访问权限,从而访问由于 o 作为对象实现而访问受限的同一个对象。我从中学到了很多。谢谢!
    【解决方案3】:

    如果你和我通过电话交谈,那么你只能与我的声音交流,但这并不意味着我的其余部分不复存在。您正在与该 ArrayList 作为一个对象进行交互,但它仍然具有 ArrayList 的所有部分 - 您只是没有与其他部分进行交互。

    【讨论】:

    • 天哪,这令人困惑。它实现为 ArrayList,但仅使用其声明类型的接口。如果我尝试将它发送到以 ArrayList 作为参数的方法,Netbeans 告诉我它是 Object 类型。我的猜测是编译器在编译时认为它是一个对象,而在运行时它变成了一个 ArrayList。啊哈!
    • 不,对象是一个ArrayList,但是你的变量o已经被声明为Object类型,所以当使用o作为句柄时,你只能访问声明的可用方法和字段类型,对象。底层对象不会停止成为 ArrayList,但变量 o 只能访问 Object 方法和字段。
    猜你喜欢
    • 2011-05-11
    • 2020-01-13
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多