在Java中使用引用时有什么注意事项?
答案 0 :(得分:10)
Java新手的常见问题是:
关于Java的参数传递机制的困惑。他们认为因为对象是引用,所以它们在方法调用中“通过引用传递”。这不是真的。参数始终在Java中“按值传递”。
关于Java数组是什么的混淆。数组只是一种特殊的对象。它们是在堆上创建的,具有引用,并且这些引用“按值传递”...就像任何其他对象一样。
关于==
对引用的意义的困惑。它的意思是“与...相同的对象”,不“等于”。 equals
方法用于测试两个对象是否相等......无论这意味着什么。
新用户经常出错的一个众所周知的子案例是在处理字符串时,两个String对象通常是“相等”但不是“同一个对象”。简单的规则是不要使用==
来比较字符串。
一个鲜为人知的子案例是原始包装类Boolean,Character,Integer等。问题......和解决方案......基本上与字符串相同;即不要使用==
来比较布尔值,字符,整数等实例。
有些人遇到null
的问题。基本概念很简单,但有些人养成了在应该抛出异常时返回null
的坏习惯。这会导致对null
进行大量不必要的测试,并在遗漏了必要的空值测试时因意外NullPointerExceptions
而导致的瑕疵。
有些人认为您应该能够为堆栈上分配的某些对象创建引用。 Java不允许这样做。在Java中,始终在堆中分配对象。堆栈框架只包含引用和原始值,Java没有提供“取任何地址”的方法。
有些人认为你应该可以用引用做指针算术。 Java不允许这样做。
但基本上,Java引用非常简单易懂,并且基本上没有问题......一旦你停止尝试用C / C ++指针思考它们。
答案 1 :(得分:2)
如果您的意思是SoftReference,WeakReference和PhantomReferences:
DOS:
使用软引用缓存创建或内存方面成本高昂的对象。这将使您的应用程序有机会在内存不足之前删除对象,但会降低性能。
如果您需要保留对注册Observer的类的引用,请在使用Observer模式时使用WeakReferences。这保证了监听者不会阻止父母被垃圾收集。
注意事项:
可以随时删除软引用对象和弱引用对象,所以永远不要这样做:
if (reference.get() != null){
Object o = reference.get();
// Do something with o....
}
可能是o收到空指针的情况,因为无法保证垃圾收集器何时被激活。
答案 2 :(得分:1)
简而言之......
Java通过引用操作对象,所有对象变量都是引用。但是,Java不通过引用传递方法参数;它按值传递它们。
所以对象可以通过引用传递给方法,但是原语(int / boolean)是按值传递的。
这个网站很好地解释了这些差异...... Javaworld: pass by reference
答案 3 :(得分:0)
这个领域的大多数书籍,文章甚至你的测试程序可能会给你一些不好的理解(原始类型总是按值传递,而对象和数组总是通过引用传递) 如果您尝试使用基本测试代码,如下所示
public class Test {
public void changeArrayValues(String[] names) {
for(int i=0; i<names.length; i++)
names[i] += "_ALTERED";
}
public static void main(String[] args) {
String[] names = {"Cairo", "Alex", "Giza"};
for(int i=0; i<names.length; i++)
System.out.print(names[i] + ", ");
System.out.println();
new Test().changeArrayValues(names);
for(int i=0; i<names.length; i++)
System.out.print(names[i] + ", ");
}
}
您将获得以下输出:
Cairo,Alex,Giza,Cairo_ALTERED,
Alex_ALTERED,Giza_ALTERED
这会强化你的想法。
但(基本类型总是按值传递,而对象和数组总是通过引用传递)是正确的。因为在通过引用传递时,您可以将引用移动到指向另一个对象但在Java中如果您这样做,引用的对象将不会感觉到该更改
试试这个
public class Test {
public void reIntializeArray(String[] names) {
names = new String[]{"X", "Y", "Z"};
}
public static void main(String[] args) {
String[] names = {"Cairo", "Alex", "Giza"};
for(int i=0; i<names.length; i++)
System.out.print(names[i] + ", ");
System.out.println();
new Test().reIntializeArray(names);
for(int i=0; i<names.length; i++)
System.out.print(names[i] + ", ");
}
}
这将转储以下输出:
Cairo,Alex,Giza,
Cairo,Alex,Giza,
因此,从输出中看到的数组没有使用新值进行初始化。
所以Java中的所有传递都是通过值传递
然而,你可以从改变对象内容的第一个行为中受益,但你必须记住这是Java而不是C ++。