Java 按值(或按引用)返回引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9955863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java returning references by value (or by reference)
提问by Ramy Al Zuhouri
Consider this code:
考虑这个代码:
package Prova;
import java.util.ArrayList;
public class Prova
{
private ArrayList<String> people;
public Prova() {
people=new ArrayList<String> ();
}
public ArrayList<String> getPeople (){
return people;
}
public static void main(String[] args) {
Prova p=new Prova();
p.go();
}
public void go(){
ArrayList<String> temp=getPeople();
temp.add("Hyman");
System.out.print(getPeople());
}
}
It prints "Hyman".
它打印“Hyman”。
Why? Doesn't this violate encapsulation? How to return it by value?
为什么?这不违反封装吗?如何按值返回?
回答by Johan Sj?berg
You need to program defensively. There are a few alternatives to consider
你需要防御性地编程。有几个替代方案需要考虑
- Don't expose the list externally, expose methods to apply to the list instead, e.g.,
- 不要在外部公开列表,而是公开应用于列表的方法,例如,
public void addPerson(String personName) {
people.add(personName);
}
- Return immutable objects or a copy of the object. E.g.,
- 返回不可变对象或对象的副本。例如,
public List<String> getPeople {
return new ArrayList<String>(people);
}
As far as the whygoes, it's as already explained by other posts. The value to the reference of the ArrayList
is passed (alas changing the value doesn't change the original reference). However the list itself contains modifiable references to its objects.
至于原因,其他帖子已经解释过了。ArrayList
传递给 的引用的值(但是更改值不会更改原始引用)。然而,列表本身包含对其对象的可修改引用。
回答by Kowser
Java is always pass by value:
Java 总是按值传递:
- For primitive type, it passes value directly.
- For object it passes value of the object reference.
- 对于原始类型,它直接传递值。
- 对于对象,它传递对象引用的值。
So for your case, it is passing value of the reference object. Thus object reference.
因此,对于您的情况,它正在传递引用对象的值。因此对象引用。
回答by Christian Schlichtherle
The getPeople() method is violating encapsulation here because it returns a reference to its private list instead of returning an immutable view or a copy. You could easily solve this by implementing this method as:
getPeople() 方法在这里违反了封装,因为它返回对其私有列表的引用,而不是返回不可变的视图或副本。您可以通过实现此方法轻松解决此问题:
public List<String> getPeople() {
return Collections.unmodifiableList(people);
}
I recommend to have a look at Joshua Bloch's excellent book "Effective Java (2nd Edition)", "Item 39: Make defensive copies when needed".
我建议看看 Joshua Bloch 的优秀著作“Effective Java (2nd Edition)”、“Item 39: Make防御性副本”。
回答by nansen
Immutability is charming but as with making defensive copies, it can become expensive. The standard java collections just aren't designed as immutable data structures. So it would be nice if you can go like Johan Sj?berg suggests and do not expose the list at all.
不变性是迷人的,但与制作防御性副本一样,它可能会变得昂贵。标准的 java 集合并不是设计为不可变的数据结构。因此,如果您能像 Johan Sj?berg 建议的那样去做并且完全不公开列表,那就太好了。
But you should also consider why you need to enforce such a high level of encapsulation. Are you exposing your class as a public API? If not, if you know and control the clients of your class well, too much encapsulation can be just impractical. Remember that encapsulation/information hiding is less about security but more about presenting a concise and unambiguous API to a client.
但是您还应该考虑为什么需要执行如此高级别的封装。您是否将类公开为公共 API?如果没有,如果您很好地了解和控制类的客户端,过多的封装可能是不切实际的。请记住,封装/信息隐藏与安全性无关,而更多的是向客户端呈现简洁明了的 API。
回答by Svilen
Java is essentially "pass by value", with a small but significant difference from what is usually meant by that i.e. it acutually is "pass by reference value".
So when you deal with Java Types(the Class citizens of the JVM, the non-primitive types), declaration like the following basically means that you will get a copy of the reference referenceToMyObject
of Type MyClass
, pointing to the same specific MyClass
Object instance in the JVM heap memory.
Java 本质上是“按值传递”,与通常的意思有细微但显着的区别,即它实际上是“按引用值传递”。因此,当您处理 Java 类型(JVM 的类公民,非原始类型)时,像下面这样的声明基本上意味着您将获得referenceToMyObject
Type引用的副本MyClass
,指向MyClass
JVM 中相同的特定Object 实例堆内存。
public class SomeClass {
private MyClass referenceToMyClassInstance = new MyClass("instanceId-1");
public MyClass getMyClassInstance() {
return referenceToMyClassInstance;
}
}
So in your example you basically get copy of reference pointing to the same ArrayList
instance and anyone who called getPeople()
will now be able to change the actual instance anyway he/she likes, possibly corrupting what should be encapsulated state.
因此,在您的示例中,您基本上会获得指向同一ArrayList
实例的引用副本,并且任何调用它的getPeople()
人现在都可以以任何他/她喜欢的方式更改实际实例,这可能会破坏应该封装的状态。
So you should return a copy of the ArrayList or wrap it with unmodifiable Decorator Collections.unmodifiableList(people)
所以你应该返回一个 ArrayList 的副本或者用不可修改的装饰器包装它 Collections.unmodifiableList(people)