首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Integer类如何不调用字段或方法直接存储值

Integer类如何不调用字段或方法直接存储值
EN

Stack Overflow用户
提问于 2021-05-13 09:35:06
回答 2查看 63关注 0票数 0

示例:

代码语言:javascript
运行
复制
Integer x = 56; 

据我所知,只有在类或方法中调用了字段时,才能将值存储在对象中。在Integer类的情况下,如果不实例化一个对象,它应该不能调用它的value字段,因为value不是静态的。这怎么可能呢?

EN

回答 2

Stack Overflow用户

发布于 2021-05-13 09:51:25

只有在类或方法中调用了字段时,才能将

值存储在对象中。

这句话没有任何意义。我不知道这是对是错,只是...这说不通。

如果不实例化一个对象,它就不能调用它的value字段,因为value不是静态的。我就是想不通这是怎么回事。

Javac看到这一点后说:嘿,你把一个正方形的钉子(一个int类型的常量)塞进了一个圆孔(一个对象类型的变量)--这是没有意义的。除非,在Java中明确指出,如果int表达式出现在int表达式不应该出现的位置,但Integer表达式工作正常,则可以使用“应用自动装箱”。

“应用自动装箱”的意思是:假设程序员想写的是:Integer.valueOf(the expression),而不是他们写的东西。

因此:

代码语言:javascript
运行
复制
Integer x = 56;
Integer x = Integer.valueOf(56);

是完全相同的。它们是如此的相同,它们产生相同的字节码。无论您如何编写,对valueOf的调用都在您的类文件中。让我们测试一下:

代码语言:javascript
运行
复制
> cat Test.java
class Test {
    Integer x = 56;
}

> javac Test.java
 (`javap` is part of java distributions and prints bytecode)
> javap -private -c Test
Compiled from "Test.java"
class Test {
  java.lang.Integer x;

  Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: bipush        56
       7: invokestatic  #7                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      10: putfield      #13                 // Field x:Ljava/lang/Integer;
      13: return
}

看看这个-调用静态方法Integer.valueOf,即使Integer.valueOf在我们的Test.java文件中完全没有出现。

那么,Integer.valueOf是如何工作的呢?

本质上,它是这样工作的:

代码语言:javascript
运行
复制
package java.lang;

public class Integer {
    private static final Integer[] CACHE = generateCache();

    private final int value;
    public Integer(int value) {
        this.value = value;
    }

    private static Integer[] generateCache() {
        for (int i = 0; i < 256; i++) {
            CACHE[i - 128] = new Integer(i);
         }
    }

    public static Integer valueOf(int v) {
        if (v >= -128 && v < 128) return CACHE[i + 128];
        return new Integer(v);
    }
}

换句话说,Integer类预先创建了256个整数对象,从-128到+127 (为什么是这些值?嗯,因为sun认为这些东西会经常出现,25年前就值得缓存它们了)。如果你用一个介于-128和+127之间的值进行valueOf(),你会得到一个缓存。如果你在它之外使用valueOf,你会得到一个新的对象。

我们也可以证明这一点:

代码语言:javascript
运行
复制
> cat Example.java
class Example {
    public static void main(String[] args) {
        Integer a = -100;
        Integer b = -100;
        Integer c = 200;
        Integer d = 200;
        System.out.println("a == b? " + (a == b));
        System.out.println("c == d? " + (c == d));
        System.out.println("ident-hash a: " + System.identityHashCode(a));
        System.out.println("ident-hash b: " + System.identityHashCode(b));
        System.out.println("ident-hash c: " + System.identityHashCode(c));
        System.out.println("ident-hash d: " + System.identityHashCode(d));
    }
}
> java Example.java
a == b? true
c == d? false
ident-hash a: 1880794513
ident-hash b: 1880794513
ident-hash c: 1991313236
ident-hash d: 736778932

此代码显示,对于-100,该Integer.valueOf调用返回的是完全相同的对象(==比较引用标识,即:它是否相同的对象,当在对象上使用时,它不会比较值。A和b只是指向相同的对象,而c和d指向具有相同值的不同对象)。

这就像在郊区某处建造的一堆相同的房子:a和b就像一张纸,上面写着相同的地址,而c和d就像一张纸,每个纸上都有不同的地址,但这两个地址上的房子看起来是一样的。

票数 1
EN

Stack Overflow用户

发布于 2021-05-13 09:55:24

对于语言中内置的对象类型,该语言可以而且确实会做出任何它想要的例外。简而言之,你可以在Java中做到这一点,因为Java说你可以做到。

具体地说,原始值(int、long等)到包装类(Integer、Long等)的转换称为“自动装箱”,顾名思义,它是自动执行的。

为什么允许这样做?因为它对用户来说非常方便。与自动拆箱一起,它允许您非常接近于像对待包装器类所包含的原始值一样对待它们。

一些术语:你只“调用”方法,而不是变量或字段。‘'Call’的意思是‘转移控制到’。

在像Integer这样的类中,你甚至不知道它有什么字段。你所知道的就是它可以存储一定范围内的整数值。只能通过调用构造函数或将返回Integer的静态方法之一将值输入Integer。

Documentation for Integer,如果你还没看过的话。请注意,没有任何操作可以“更改”Integer的值;我们说它是“不可变的”。如果你想要一个不同的值,你只能生成一个新的Integer。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67512882

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档