【问题标题】:Java: Object pointer handlingJava:对象指针处理
【发布时间】:2013-10-08 02:27:20
【问题描述】:

假设我有这个 Java 代码(中期审查!):

public class A {
public int key;
}

public class B extends A {
}

public class Problem1 {
public static void f(A x) {
A y = x;
y.key = x.key + 1;
}

public static void f(B x) {
B y = new B();
y.key = x.key + 2;
x = y;
}

public static void main(String[] args) {
A p = new A();
p.key = 3;
B q = new B();
q.key = 10;
f(p);
f(q);
p = q;
f(p);
System.out.println(p.key);
}
}

我不确定我是否正确理解 p = q。到目前为止,这是我的理解:因为 B 扩展了 A,所以允许此操作,但它不会使 p 和 q 指向同一个对象。相反,它更新了 p 的键值,但它仍然属于 A 类。这就是为什么 f(p) 最后返回 11 的原因。这与我之前认为我对 Java 的了解不相符,因此将不胜感激。

例如,如果我有 int a = 4 和 int b = 3,那么我会这样做:

a = b;
b++;
return a;

a 将返回 3,即使它应该指向 b 指向的同一事物?

请指教。

【问题讨论】:

标签: java pointers reference


【解决方案1】:

考虑一下。 Java 原语将实际值保存在内存字节区域中: 所以如果 a = 4b = 3 ,那么一个 8 字节的机器内存区域可能会像(二进制)一样保存它

a = 0 0 0 0 0 0 1 1 
b = 0 0 0 0 0 0 1 0

现在,当你说a=b; 时,意味着

a = 0 0 0 0 0 0 1 0 
b = 0 0 0 0 0 0 1 0

然后b++ (i.e. b = b+1)

a = 0 0 0 0 0 0 1 0 
b = 0 0 0 0 0 0 1 1

然后

return a;

Then  a = 0 0 0 0 0 0 1 0 (i.e. 3)

希望你能理解它的原始价值。尽管对于 java 中的对象,这是完全不同的情况。

现在想想,a 和 b 不是原始的,而是具有 int 字段的对象。 Sample 类可能看起来像

class Test {
private int value;

public Test(int value){
 this.value = value;
}

public int getValue(){
return value;
}

public int increment(){
value++;
}
}

然后a = new Test(4); and b = new Test(3);在内存中表示为:

堆:

a = x63489DF8 ---> [Test(4) Object, value = 4, Heap Memory address = x63489DF8]
b = xDFA78945 ---> [Test(3) Object, value = 3, Heap Memory address = xDFA78945]

ab 持有指向对象的堆内存地址)

现在,当你说a=b; 时,意味着

a = xDFA78945 ---> [Test(3) Object value = 3, Heap Memory address = xDFA78945]
b = xDFA78945 ---> [Test(3) Object value = 3, Heap Memory address = xDFA78945]

(内存地址x63489DF8中的对象是可垃圾回收的,a, b指的是同一个对象)

现在,说 b.increment();,然后内存区域 xDFA78945 中的对象被操作,新对象变为 [Test(3) Object value = 4, Heap Memory address = xDFA78945]

a = xDFA78945 ---> [Test(3) Object value = 4, Heap Memory address = xDFA78945]
b = xDFA78945 ---> [Test(3) Object value = 4, Heap Memory address = xDFA78945]

(请注意,更改反映了两个引用,因为两者实际上都指向同一个对象)

现在返回 a.getValue() 返回 4。 (即通过引用 b 完成的更改也反映在引用 a 中)

【讨论】:

    【解决方案2】:

    所有变量都是位持有者。好的

    所以如果它是原始类型,它将持有代表位 lavel 表示的位 原始的。

    a = b; b++; return a;
    

    这里“3”的位表示被分配给“a”所以它现在是3。但是 b 仍然持有代表“3”的位,所以 b 中的 cange 将只保留“b”

    现在如果 a 是一个类变量并且 b 也是,在 java 中变量总是持有位。上课的时候 变量它保存表示到达位于堆上的类对象的路径的位。因此,当您这样做时,a = b; a 还将保留到达堆上对象的路径。所以“a”和“b”都持有同一个对象的路径。

    如果您更改“a”的属性(更改由 var“a”持有的路径到达的对象的属性)。将反映在 b 中。因为这些都指向同一个变量。

    【讨论】:

      【解决方案3】:

      例如,如果我有 int a = 4 和 int b = 3,那么我会这样做:

      a = b;
      b++;
      return a;
      

      a 将返回 3,即使它应该指向同一个东西 b 指的是什么?

      原语会按照您的预期进行处理。换句话说,a 将给出值 3,因为它占用了 b 的数字或位值。但是,您应该查看autoboxingimmutability

      我不确定我是否正确理解 p = q。这是我的理解 far:因为 B 扩展了 A,所以允许此操作,但不允许 使 p 和 q 指向同一个对象。相反,它会更新密钥 p 的值,但它仍然属于 A 类。

      关于对象,p = q 操作实际上将 p 赋值为“引用”(见底部链接)与 q 相同的对象。这就是为什么需要像defensive copying 这样的方法。

      这也解释了为什么尽管 Java passing by value 通过重载的 f 方法进行了修改。参数x 保持原样,一旦进程离开方法范围就会消失,但引用对象的状态可以修改。

      这是一个关于 C 指针和 Java 引用之间差异的问题。

      https://softwareengineering.stackexchange.com/questions/141834/how-is-a-java-reference-different-from-a-c-pointer

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-22
        • 2016-10-24
        • 2015-10-07
        • 2011-02-12
        • 1970-01-01
        相关资源
        最近更新 更多