两个新创建的对象似乎引用相同的地址
我用Java编程只用了几个月,所以我不熟悉Java(有些技巧和我应该知道的基本知识)。
我遇到了一个可能很明显但我看不到的问题。
public class SomeClass { private final int[] numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; private LabelText AText = new LabelText('A', numbers); private LabelText BText = new LabelText('B', numbers); public void foo() { AText.numbers[6] = -1; BText.numbers[3] = -1; if (BText.numbers[6] == -1) System.out.println("Wtf?"); } }
这是我的代码摘录。
这怎么可能是真的? 这是两个独立的对象。 我不明白。
foo方法直接在我的main方法中调用(用于测试目的)。
如果你需要LabelText的构造函数,这里是:
public class LabelText { private final char letter; public int[] numbers; public LabelText(char letter, int[] numbers) { this.letter = letter; this.numbers = numbers; } }
因为您在不进行复制的情况下传递对numbers
的引用 ,所以两个对象最终都指向同一个 int[]
实例 。 虽然有两个不同的外部对象,但它们指向的内部对象是同一个对象 ,因此您可以通过取消引用AText.numbers
和BText.numbers
任何一个来更改该内部对象,并且更改将在两个中都可见。访问其numbers
字段时的外部对象。
您可以检查AText == BText
将返回false
,但AText.numbers == BText.numbers
将返回true
。 并且this.numbers == AText.numbers
也将返回true
。
就像尝试这个相同的代码,但使用此构造函数:
public LabelText(char letter, int[] numbers) { this.letter = letter; this.numbers = numbers.clone(); // so it will always be unique array here }
Java中的Object Refreneces:
在Java编程语言中,有两种数据类型:原始和引用。
- 基元:char,byte,short,int,long,float和double
- 参考:Java和数组中的所有对象。
示例Java对象:
- 在Java编程语言中,有类,如
String
,Exception
,Integer
和File
。 使用这些类创建对象。 此外,可以创建自定义类和对象 – 例如Person
或LabelText
。
Java对象的创建如下。 如果Person
是一个类:
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public void setName(String s) { name = s; } public String getName() { return name; } public void setAge(int i) { age = i; } public int getAge() { return age; } }
考虑一下代码:
Person personA = new Person("A", 32);
在上面的语句中, Person
是一个类, personA
是一个变量, new Person(..)
创建一个Person
类型的对象。 =
将新创建的Person
对象分配给变量personA
。 personA
是引用类型的变量,它指向或引用新创建的Person
对象。
Person
类具有属性(或属性) name
和age
。 这些代表对象的状态 。 通常,状态区分对象。
该引用类型的行为如何? 查看此示例代码:
public class TestingReferences { public void foo() { Person a = new Person("A", 32); // 1 Person b = new Person("B", 28); // 2 Person c = a; // 3 a.setName("X"); // 4 System.out.println("Are the names of a and c equal? " + a.getName().equals(c.getName())); // 5 } } public static void main(String [] args) { TestingReferences app = new TestingReferences(); app.foo(); } }
在上面的示例代码中,注意在方法foo()
打印的输出 – 人员a和c都具有相同的名称X. 这是怎么发生的?
1: Person a = new Person("A", 32);
创建一个新的人物对象并将其分配给变量a
。
2: Person b = new Person("B", 28);
创建一个新的人物对象并将其分配给变量b
。
3: Person c = a;
创建人员变量c
– 并且 – 为其分配参考变量a
。 在此阶段,引用变量a
和c
都指向或引用同一个人对象(见下图)。
4: a.setName("X");
人物对象的name
从“A”变为“X”。
5: System.out.println("Are the names of a and c equal? " + a.getName().equals(c.getName()));
这打印true
!
由于引用变量a
和c
都指向同一个对象,因此两个引用都可以看到对象状态的任何更改。
如果语句被添加到foo
: c.setAge(44);
, a
和c
人的age
都设定为44岁。
上面的示例演示了对象引用在Java编程语言中的行为方式。 同样适用于这篇文章中的问题。
从post的问题:
请注意,数组,两个基元数组(如int[]
)和对象数组( Person[]
)始终是对象。
1: private final int[] numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
2: private LabelText AText = new LabelText('A', numbers);
3: private LabelText BText = new LabelText('B', numbers);
上述三个语句中有三个对象和引用变量。 注意, numbers
对象引用被分配给AText
和BText
的状态。 numbers
数组的所有这三个引用都指向在第1行上创建的相同数组对象。 现在,在方法foo()
:
AText.numbers[6] = -1; BText.numbers[3] = -1; (BText.numbers[6] == -1) ... returns true -and- (AText.numbers[3] == -1) ... also, returns true.
将此语句添加到方法foo
: System.out.println(java.util.Arrays.toString(numbers));
这打印: [0, 1, 2, -1, 4, 5, -1, 7, 8, 9]
。 注意位置3和6中的数组值。