有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

将一种对象类型分配给另一种对象类型时,Java变量是如何工作的?

我真的不知道如何立即解释我的怀疑,所以我将从一个例子开始。我有以下几行:

Object myObject = null;
Integer myInteger = 10;

myObject = myInteger;

基本上,我知道我可以将一个子类对象分配给一个超类对象(在这个场景中,myInteger类型为Integer,而myObject类型为Object)。到目前为止还不错,但现在。。。假设我想得到myObject的类

System.out.println("myObject: " + myObject.getClass());

它打印了这个:

myObject: class java.lang.Integer 

它说是类型Integer

我知道一个变量实际上在内存中存储了对实际对象的引用,因此方法getClass()返回实际对象的类。但是

  1. 为什么我不能通过myObject访问类Integer的方法,因为它指向类型为Integer的对象?我是说,为什么我不能做这样的事myObject.intValue();

  2. 如果我只能通过myObject访问Object的方法(即使它指向类型为Integer的对象),Java如何知道可以通过myObject调用哪些方法?变量本身存储一种类型的类

基本上,我想知道Java在变量中存储了什么信息,它只是一个引用吗?或者它还有一个类名?如果变量已将引用分配给子类对象,它如何知道可以调用哪些方法

我希望我的疑问是清楚的,请原谅我的语法


共 (2) 个答案

  1. # 1 楼答案

    考虑这个类比:你提供三层“安全级别”的存储服务:一般商品、价值物品和奢侈品。你有一个在线系统,可以让你的客户预订空间,并根据他们想要存储的内容付款。根据级别的不同,您的服务和预订要求也有所不同:

    一般商品:

    • 你可以在共享仓库中获得空间
    • 你是按商品数量付费的

    贵重物品:

    • 你可以在共享仓库中获得存储空间
    • 你可以通过摄像头监控获得额外的安全保护
    • 你是按商品数量付费的

    奢侈品:

    • 您可以获得带有位置标签的专用存储空间
    • 你会有摄像头监控和安保人员全天候监视你的物品
    • 你按物品价值付款
    现在,考虑到你的客户把物品放在你的预订系统发出的参考号码的盒子里,你的保安在位置上检查内容。p>

    让我们看看你的流程步骤是怎么做的:

    在线系统:

    • 让你的客户声明他们要购买哪一层
    • 为申报的预订预留存储空间
    • 根据客户的预订,以正确的金额向他们的付款方式收费
    • 提供一个跟踪系统,显示物理存储的基本细节

    保安:

    • 检查盒子中的实际实物
    • 确保物品符合预订要求,但如果客户选择,黄金可以存放在普通商品区,但出于保险考虑,旧塑料杯不能带到奢侈品区

    你觉得这些场景怎么样

    • 客户使用您的在线系统预订普通商品仓库并完成预订。当他们回来检查物品的状态时:系统会让他们看到24/7监视他们物品的保安的名字吗?
      提示:不,系统知道他们有普通货物层,不提供专门的守卫服务
    • 同一位客户将黄金放入盒子中,并在指定地点展示。
      • 在线系统会让他们看到24/7守卫的细节还是视频片段?
        提示:没有(仍然),因为系统知道这是一个普通商品预订
      • 登记的警卫会知道盒子里是金子而不是便宜的东西吗?
        提示:是的。但客户仍然无法获得奢侈品服务。对吧
    • 另一位客户预订了“奢侈品”,但却赠送了一个盒子,里面装着一个旧塑料杯。
      • 你的在线系统会阻止他们这样做吗?
        提示:不,它不能,因为它不知道客户在想什么,也不能检查物品
      • 你的现场警卫能阻止这个箱子被检入吗?
        提示:是的,因为他们可以看到物理项目并确定它实际上是什么。而且,由于保险禁止在更高级别的低价值物品,警卫可以阻止这种情况

    Java也是如此(粗略地说):

    • 声明变量并为其指定类型=>;做一个预订并宣布好的
    • 为声明的变量赋值=>;将物品放入盒子中,并将其交给警卫检查
    • 对声明的变量调用方法=>;使用服务或在线跟踪(你无法获得你所在级别无权获得的服务:即使你拥有普通商品的黄金,你也无法获得视频片段)

    换句话说,在线系统就像编译器,物理位置就像运行时。
    在Java中,在线保留的层类型称为“静态类型”,即编译时(预订时)已知的类型。放入框中的实际类型称为“运行时类”,是动态的(就像一个普通的商品层盒子可以容纳黄金,或者一个中等价值的物品,比如电视)

    就像盒子一样,只有运行时知道变量的实际/运行时类:只有现场工作人员知道它是盒子里的金子。当你调用myObject.getClass()时,这正是你想要的:myObject运行时类(这是调用其构造函数或使用new的类;或者在某些情况下,是文本类,例如intInteger,但这是另一天的故事)。但即使在运行时它被称为Integer,编译器(在线系统,记得吗?)不会让你调用Integer上的方法,因为myObject被声明为Object:在线系统不会让你看到普通商品预订的视频片段,即使盒子里有钻石。你可以用类型转换强制编译器接受Integer上的myObject方法,如Sweeper's good answer所示,这有点像是升级到网站上的奢侈品,之后在线系统会让你获得更高级别的服务:)


    这种类比在某些方面可能是荒谬的,例如编译器阻止您将不兼容或更广泛的类型化值分配给变量。。。但这只是一个例子,一个有限的例子

  2. # 2 楼答案

    你的问题的答案基本上可以归结为两个关键点:“编译器不允许你做危险的事情”和“编译器没有你想象的那么聪明”

    Why can't I access the methods of the class Integer through myObject since is pointing to an object of type Integer?

    知道这一点,因为您看到行myObject = myInteger;,所以您知道myObject将有一个intValue()方法

    当编译器看到您调用myObject.intValue();时,它不会像您那样返回几行来找出myObject实际引用的内容。它只看到它的类型是Object,并且只允许使用Object中定义的可用内容。因为它不会回顾myObject实际上指的是什么,就编译器而言,myObject可以指的是Integer,但它也可以指的是String,因为您可以做到:

    myObject = "Hello";
    

    String没有intValue()方法。“安全总比抱歉好”,编译器说,而且不允许你调用intValue。您可以通过强制转换告诉编译器您更了解:

    ((Integer)myObject).intValue();
    

    how does Java know which methods can be called through myObject?

    这是由表达的类型决定的。表达式myObject的类型为Object,因为变量myObject的类型为Object。另一方面,表达式((Integer)myObject)是类型Integer