当前位置: 首页 > 面试题库 >

为什么没有在Java中缓存Integer?

顾俊茂
2023-03-14
问题内容

我知道在该主题上也有类似的帖子,但是它们并没有完全解决我的问题。当您这样做时:

Integer a = 10;
Integer b = 10;
System.out.println("a == b: " + (a == b));

(显然)true大多数时间都会打印,因为以某种方式缓存了[-128,127]范围内的整数。但:

Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println("a == b: " + (a == b));

会回来的false。我知道我正在html" target="_blank">请求一个Integer的新实例,但是由于装箱的原语在Java中是不可变的,并且已经有了执行“正确的事情”的机制(如第一种情况所示),为什么会发生这种情况?

如果Integer的所有实例(具有10)都在内存中是同一对象,这是否更有意义?换句话说,为什么我们没有类似于“字符串实习”的“整数实习”?

更好的是,如果代表盒装基元的实例代表相同事物( 无论其值(和类型)如何) 是同一对象,这是否更有意义?或至少正确回应==


问题答案:

非常清楚的是,缓存会对性能造成不可接受的影响–每次创建Integer时,都会产生额外的if语句和内存查找。仅此一个因素就掩盖了任何其他原因,而使该线程感到痛苦的其余部分。

就“正确”响应==而言,OP在其正确性假设中是错误的。整数确实通过Java社区对正确性的期望,当然也通过规范对正确性的定义,对==做出正确的响应。也就是说,如果两个引用指向同一对象,则它们为==。如果两个引用指向
不同的 对象,即使它们具有相同的内容,它们 也不 ==是相同的。因此,得出的结果就不足为奇new Integer(5) == newInteger(5)false

更为有趣的问题是, 为什么 new Object();每次都需要创建一个唯一的实例?即为什么newObject();不允许缓存?答案是wait(...)notify(...)。缓存new Object()s会错误地导致线程在不应该同步时彼此同步。

如果不是那样的话,那么Java实现可以完全new Object()单例缓存s。

new Integer(5)这就说明了为什么必须创建7个唯一的Integer对象(每个对象都包含值5
)需要完成7次(因为Integerextend Object)。

次要的,不太重要的东西: 自动装箱和自动拆箱功能导致本来不错的方案中的一个问题。没有该功能,您将无法进行比较new Integer(5) == 5。要启用这些功能,Java 会将 对象 取消装箱 (并且 不对 原语进行装箱)。因此new Integer(5) == 5被转换为:(new Integer(5).intValue() == 5不是 new Integer(5) == newInteger(5)

最后一两件事要了解是那个自动装箱n 被做new Integer(n)。通过内部调用来完成Integer.valueOf(n)

如果您认为自己了解并想要测试自己,请预测以下程序的输出:

public class Foo {
  public static void main (String[] args) {
    System.out.println(Integer.valueOf(5000) == Integer.valueOf(5000));
    System.out.println(Integer.valueOf(5000) == new Integer(5000));
    System.out.println(Integer.valueOf(5000) == 5000);
    System.out.println(new Integer(5000) == Integer.valueOf(5000));
    System.out.println(new Integer(5000) == new Integer(5000));
    System.out.println(new Integer(5000) == 5000);
    System.out.println(5000 == Integer.valueOf(5000));
    System.out.println(5000 == new Integer(5000));
    System.out.println(5000 == 5000);
    System.out.println("=====");
    System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
    System.out.println(Integer.valueOf(5) == new Integer(5));
    System.out.println(Integer.valueOf(5) == 5);
    System.out.println(new Integer(5) == Integer.valueOf(5));
    System.out.println(new Integer(5) == new Integer(5));
    System.out.println(new Integer(5) == 5);
    System.out.println(5 == Integer.valueOf(5));
    System.out.println(5 == new Integer(5));
    System.out.println(5 == 5);
    System.out.println("=====");
    test(5000, 5000);
    test(5, 5);
  }
  public static void test (Integer a, Integer b) {
    System.out.println(a == b);
  }
}

为了获得额外的信用,如果所有值==都更改为,还可以预测输出.equals(...)

更新: 感谢用户@sactiw的评论:“缓存的默认范围是-128到127,并且从Java 1.6开始,您可以通过从命令行传递-
XX:AutoBoxCacheMax =来重置上限值> = 127”



 类似资料:
  • 问题内容: 在Java中,为什么以下代码行不起作用? 如果我将其更改为 起初,我以为您可能没有接口列表,但是我可以创建一个很好的接口。 有想法吗? 问题答案: 泛型类型比较古怪。 表示或任何子类型,但仅表示。如果您想要一个子类型,您需要 我怀疑你可以用 无法执行此操作的原因是,您可以使用对引用的引用,并且必须谨慎使用额外的间接级别。 使用泛型,您可以有两个间接级别,这会给您带来问题,因此它们更容易

  • 问题内容: 我知道每次键入字符串文字时,字符串池中都会引用相同的String对象。 但是,为什么String API不包含,所以我可以使用引用? 至少,这将节省编译时间,因为编译器将知道引用现有的String,而不必检查是否已创建它以进行重用,对吗?我个人认为,字符串文字(尤其是很小的文字)在许多情况下是一种“代码异味”。 那么是否没有String.Empty背后的宏伟设计原因,还是语言创建者根本

  • 问题内容: 在Java中,有和接口。两者都属于Java的标准框架,并提供了一种访问元素的分类方法。 但是,据我了解没有。你可以用来对列表进行排序。 知道为什么要这样设计吗? 问题答案: 列表迭代器首先确保你以列表的内部顺序(也称为插入顺序)获取列表的元素。更具体地说,它是按照插入元素的顺序或操作列表的方式进行的。排序可以看作是对数据结构的一种操作,有几种方法可以对列表进行排序。 我将按照自己的见解

  • 下面是我的AJAX函数: 如在铬合金中观察到的 即使在后续调用中,请求头也总是相同的: Chrome不应该在收到ETag标头后缓存资源并在后续调用相同URL时设置“If-Noo-Match”标头吗?我不应该获得304而不是200的状态码,因为返回的内容是相同的吗? 不过,对其他服务器(如Google地图服务器)中的资源的调用有时会返回304。

  • 问题内容: 恐怕这是一个愚蠢的问题。 有谁能告诉我为什么没有对立的东西? 除了“因为根本就没有”以外,还有其他原因吗? 我应该创建自己的一个吗?还是我想念其他东西? 更新资料 在哪里使用?我正在编写一个使用大量消费者和供应商的图书馆。我成功地写了一行,并且遇到一种情况,期望消费者接受来自方法结果的布尔值。说什么 问题答案: 并且需要避免开销自动装箱每个值。处理原始图元更有效。但是,对于布尔值和字节

  • 问题内容: 在Java has 方法中,但是,它仅在诸如或的关联容器中使用。为什么要这样设计?具有方法的界面看起来更优雅。 问题答案: 在我看来,主要的论据是,可以为任何Java对象计算出一个定义明确的默认值,以及一个同样定义明确的。根本没有充分的理由要保留所有对象的该功能,当然也有很多理由 不 保留此功能。因此,这本书毫无疑问。