在Java中修改对象引用值的最佳实践?

在Java中修改对象引用值的最佳实践?,java,Java,我对Java相当陌生,最近我读了一些关于Java按值传递的材料。在我自己进行测试之前,我已经仔细阅读了一遍 现在,根据我的阅读和快速测试,我发现有两种方法可以改变对象引用中包含的变量。以下哪种方法更好或更安全?这两种方法都有明显的问题吗 这两种输出的iArr[0]=45 方法1: 方法2: 第二种方法打开了别名的可能性 int[] n = {1}; int[] j; j = method(n); j[0] = 342; System.out.println("iArr[0] = " + n[0

我对Java相当陌生,最近我读了一些关于Java按值传递的材料。在我自己进行测试之前,我已经仔细阅读了一遍

现在,根据我的阅读和快速测试,我发现有两种方法可以改变对象引用中包含的变量。以下哪种方法更好或更安全?这两种方法都有明显的问题吗

这两种输出的iArr[0]=45

方法1:

方法2:


第二种方法打开了别名的可能性

int[] n = {1};
int[] j;

j = method(n);
j[0] = 342;
System.out.println("iArr[0] = " + n[0]);
System.out.println("iArr[0] = " + j[0]);
将打印:

iArr[0] = 342
iArr[0] = 342

因此,在这种情况下,我会选择第一种方法。您只想更改数组,不需要返回引用。如果需要,还可以轻松创建自己的别名。第二种方法也不清楚您是否更改了实际的参数值,我认为这是一种非常糟糕的做法。

第二种方法可能会出现别名

int[] n = {1};
int[] j;

j = method(n);
j[0] = 342;
System.out.println("iArr[0] = " + n[0]);
System.out.println("iArr[0] = " + j[0]);
将打印:

iArr[0] = 342
iArr[0] = 342
因此,在这种情况下,我会选择第一种方法。您只想更改数组,不需要返回引用。如果需要,还可以轻松创建自己的别名。从第二种方法也不清楚您是否更改了实际参数值,我认为这是非常糟糕的做法。

我发现两种方法都不理想,因为它们都会导致相同的副作用

也就是说,它们是相同的,但是第二种方法也返回修改过的对象:第二种方法仍然修改传入的数组对象!将示例代码中2的返回值重新分配给iArr对修改的对象没有影响!记住Java对引用类型使用语义;返回值与此行为无关

实际上,我真的不喜欢方法2,因为它隐藏了这样一个事实:我看着签名,然后想,哦,我得到了一个新的数组对象!,虽然方法1确实很糟糕,但我可以从void返回类型很快看出这一点。在某些先进的情况下,套管链是有用的;这不是其中之一

这是一个不会引起副作用的简单版本:我建议将副作用最小化,因为它通常使代码更容易推理和调试

public static void main(String args[] )
{
   int[] iArr = {1};
   int[] newArr = method(iArr) ;
   System.out.println( "iArr[0] = " + iArr [0] ) ;
   // This is different here, but it would "be the same" in the 
   // 2nd-case example in the post.
   System.out.println( "newArr[0] = " + newArr [0] ) ;
}
public static int[] method(int[] n ) {
    // This is a silly stub method, n would be presumably used.
    int[] x = new int[1];
    x[0] = 45; // modifying a DIFFERENT object
    return x;  // returning the NEW object
}
我发现这两种方法都不理想,因为它们都会产生相同的副作用

也就是说,它们是相同的,但是第二种方法也返回修改过的对象:第二种方法仍然修改传入的数组对象!将示例代码中2的返回值重新分配给iArr对修改的对象没有影响!记住Java对引用类型使用语义;返回值与此行为无关

实际上,我真的不喜欢方法2,因为它隐藏了这样一个事实:我看着签名,然后想,哦,我得到了一个新的数组对象!,虽然方法1确实很糟糕,但我可以从void返回类型很快看出这一点。在某些先进的情况下,套管链是有用的;这不是其中之一

这是一个不会引起副作用的简单版本:我建议将副作用最小化,因为它通常使代码更容易推理和调试

public static void main(String args[] )
{
   int[] iArr = {1};
   int[] newArr = method(iArr) ;
   System.out.println( "iArr[0] = " + iArr [0] ) ;
   // This is different here, but it would "be the same" in the 
   // 2nd-case example in the post.
   System.out.println( "newArr[0] = " + newArr [0] ) ;
}
public static int[] method(int[] n ) {
    // This is a silly stub method, n would be presumably used.
    int[] x = new int[1];
    x[0] = 45; // modifying a DIFFERENT object
    return x;  // returning the NEW object
}

我发现这两种方法都不理想,因为它们都会产生副作用。实际上,我真的不喜欢方法2,因为它隐藏了这个事实,而方法1做的是肮脏的工作,但我可以从void返回类型很快看出这一点。在java中,修改对象引用值的最佳做法是:最好的做法是不要这样做。关于传递值/引用的整个事情让我发疯。Java只是做了您通常期望和应该做的事情。您可能会检查pass-by-value的作用,并且可能会想出一些巧妙的技巧来解决这个问题,但它们通常会导致代码更难阅读,并且只在最边缘的情况下才有用。始终只对INs使用参数,对OUT使用返回,并且您传入的对象可能会修改其状态。如果你修改调用者参数的实际值,你会激怒任何试图在以后重用或修复代码的人。我发现这两种方法都不理想,因为它们都会产生副作用。实际上,我真的不喜欢方法2,因为它隐藏了这个事实,而方法1做的是肮脏的工作,但我可以从void返回类型很快看出这一点。在java中,修改对象引用值的最佳做法是:最好的做法是不要这样做。关于传递值/引用的整个事情让我发疯。Java只是做了您通常期望和应该做的事情。您可能会检查pass-by-value的作用,并且可能会想出一些巧妙的技巧来解决这个问题,但它们通常会导致代码更难阅读,并且只在最边缘的情况下才有用。始终只使用INs参数、OUT参数和传递的对象参数
在中,可能会修改其状态。如果您正在修改callers参数的实际值,您将激怒任何试图稍后重用或修复代码的人。谢谢。我通常是这样做手术的。。创建一个新对象。我感到惊讶和有点吃惊的是,我的方法1甚至是可能的。然而,我认为方法1的一个“好处”是它不创建新对象来节省内存,也不象Evan提到的那样操纵堆栈。这就是说,我不认为像方法一那样就地操纵对象的值适用于公共方法,可能只适用于内部、私有方法。理解对象共享调用语义非常重要。简而言之,它意味着引用类型值或对象在作为参数传递或分配给变量时不会被复制/克隆/复制。再次注意,方法1和方法2是相同的;返回对象与改变对象无关。充其量这是一个坏例子;然而,我怀疑这是混淆/误导。请参阅MAV的答案。将此标记为答案,因为您指出了方法2的更多错误,并提出了对象共享调用。谢谢谢谢我通常是这样做手术的。。创建一个新对象。我感到惊讶和有点吃惊的是,我的方法1甚至是可能的。然而,我认为方法1的一个“好处”是它不创建新对象来节省内存,也不象Evan提到的那样操纵堆栈。这就是说,我不认为像方法一那样就地操纵对象的值适用于公共方法,可能只适用于内部、私有方法。理解对象共享调用语义非常重要。简而言之,它意味着引用类型值或对象在作为参数传递或分配给变量时不会被复制/克隆/复制。再次注意,方法1和方法2是相同的;返回对象与改变对象无关。充其量这是一个坏例子;然而,我怀疑这是混淆/误导。请参阅MAV的答案。将此标记为答案,因为您指出了方法2的更多错误,并提出了对象共享调用。谢谢