【问题标题】:Java memory management Objects vs Primitive TypesJava 内存管理对象与原始类型
【发布时间】:2018-12-04 15:43:20
【问题描述】:

我对有关 Java 内存管理的几点感到有些困惑。

了解了堆栈和堆之间的区别,我去看了一个适当的例子,说明我们执行一些代码时这些内存是什么。

我以这几行为例

public static void main(String[] args)
{
    int a = 5;
    calculate(a);
    System.out.println(a); //will print 5 not 50
}
private static void calculatee(int a)
{
    a = a * 10;
}

我了解堆栈和堆中发生了什么。变量没有被返回,在这种情况下没有对堆的引用。

在这个例子中:

public static void maina(String[] args)
{
    Customer customer = new Customer("John");
    setAName(customer);
    System.out.println(customer.getName()); // this will return Philip
}

private static void setAName(Customer c)
{
    c.setName("Philip");
}

我可以看到这次对象的状态发生了变化!

栈不是共享的思想线程,但堆是共享的!对我来说,当我打印它时,对象客户已将其价值从 Jhon 更改为 Philip! 伟大的!一切都说得通!

但是,我期待如果我会这样做

public static void main(String[] args)
{
    Integer i = new Integer(5);
    calculate(i);
    System.out.println(i); // printing 5 and not 50
}
private static void calculate(Integer i)
{
    i = i * 10;
}

我会得到 50 而不是 5!

在这种情况下,整数是一个对象,我假设它是在堆中创建的!

有趣的是,如果我将 Integer 包装在 Customer 中,我将得到 50 而不是 5。

为什么会这样? Integer 类型不是在 Heap 中创建的吗?

【问题讨论】:

标签: java memory memory-management jvm


【解决方案1】:

这是一个引用问题,而不是堆和栈问题。

当调用 calculate 方法时,您传递了一个引用(在您的情况下,i 来自 main)。

诀窍在于,Java 将在 calculate 内创建一个新引用。因此,calculate 内部的imain 内部的i 最初可能“指向”同一个对象,但它们不是“相同的”。

因此,如果您将 calculate 内部的 i 更改为乘法产生的对象,则不会自动更改 main 内部的 i 的引用。

Customer 不同。你永远不会改变setAName 中的c 指向的位置。您更改了对象的一个​​引用inside,但main 内部的customersetAName 中的c 仍然指向那个对象!

这里有两张糟糕的画图来解释我的意思(以0x 为前缀的数字是参考):

对于整数示例:

以客户为例:

如有任何问题,请随时回来。

我希望这会有所帮助。

【讨论】:

  • 知道了...如果我尝试在 setAName() 中执行“c = new Cusotmer (...)”,我实际上不会改变客户价值...发生这种情况因为 name 是一个成员变量。非常感谢
  • @OEH 好主意!欢迎来到不变性的世界,一个参考一旦设置,就永远不会再改变。 (相反,任何转换都会产生一个“新”对象)。这使您可以更简单地考虑您的代码,因为您永远不必记住可能更改对象的位置 - 它不会。在 Java 中,这可以通过使用 final 来强制执行。
猜你喜欢
  • 2018-12-20
  • 2015-12-09
  • 2016-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多