在Java中使用引用时的注意事项和注意事项

时间:2009-11-16 09:19:02

标签: java reference

在Java中使用引用时有什么注意事项?

4 个答案:

答案 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 ++。