我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
当前回答
在这里,每一个单一的答案都倾向于从其他语言中提到通过指标,并显示在Java中不可能做什么,因为任何原因,没有人试图从其他语言中展示如何实施通过对象的价值。
这个代码表明如何做这样的事情:
public class Test
{
private static void needValue(SomeObject so) throws CloneNotSupportedException
{
SomeObject internalObject = so.clone();
so=null;
// now we can edit internalObject safely.
internalObject.set(999);
}
public static void main(String[] args)
{
SomeObject o = new SomeObject(5);
System.out.println(o);
try
{
needValue(o);
}
catch(CloneNotSupportedException e)
{
System.out.println("Apparently we cannot clone this");
}
System.out.println(o);
}
}
public class SomeObject implements Cloneable
{
private int val;
public SomeObject(int val)
{
this.val = val;
}
public void set(int val)
{
this.val = val;
}
public SomeObject clone()
{
return new SomeObject(val);
}
public String toString()
{
return Integer.toString(val);
}
}
在这里,我们有一个函数需要值,它正在立即创建一个对象的克隆,需要在对象本身的类中实施,而该类必须被标记为克隆。
可能很好,Java没有通过参考语法,但称之为“通过价值”的语言沿着有愿望的思维线。
其他回答
查看此代码. 此代码不会扔 NullPointerException... 它将打印“Vinay”
public class Main {
public static void main(String[] args) {
String temp = "Vinay";
print(temp);
System.err.println(temp);
}
private static void print(String temp) {
temp = null;
}
}
如果 Java 通过参考,则应该将 NullPointerException 扔下来,因为参考设置为 Null。
Java 以参考方式操纵对象,而所有对象变量都是参考。
例如,使用 badSwap() 方法:
public void badSwap(int var1, int
var2{ int temp = var1; var1 = var2; var2 =
temp; }
public void tricky(Point arg1, Point arg2)
{ arg1.x = 100; arg1.y = 100; Point temp = arg1; arg1 = arg2; arg2 = temp; }
public static void main(String [] args) {
Point pnt1 = new Point(0,0); Point pnt2
= new Point(0,0); System.out.println("X:
" + pnt1.x + " Y: " +pnt1.y);
System.out.println("X: " + pnt2.x + " Y:
" +pnt2.y); System.out.println(" ");
tricky(pnt1,pnt2);
System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y); }
如果我们执行这个主要()方法,我们会看到以下输出:
X: 0 Y: 0 X: 0 Y: 0 X: 100 Y: 100 X: 0 Y: 0
该方法成功地改变了 ofpnt1 的值,尽管它通过了值;但是,pnt1 和 pnt2 的交换失败了! 这是混乱的主要来源. 在 themain() 方法中,pnt1 和 pnt2 只是对象参考。 当你 passpnt1 和 pnt2 到 tricky() 方法时,Java 通过了值的参考,就像其他参数一样。
Java 复制并通过参考值,而不是对象. 因此,方法操纵将改变对象,因为参考指向原始对象. 但因为参考是复制,交换将失败. 如图 2 描述,方法参考交换,但不是原始参考。
Java 只通过值,这是一个很简单的例子来验证这一点。
public void test() {
MyClass obj = null;
init(obj);
//After calling init method, obj still points to null
//this is because obj is passed as value and not as reference.
}
private void init(MyClass objVar) {
objVar = new MyClass();
}
在我所知道的范围内,Java只知道值的呼叫,这意味着对于原始数据类型,您将使用复印件工作,对于对象,您将使用对象的参考复印件工作。
public static void swap(StringBuffer s1, StringBuffer s2) {
StringBuffer temp = s1;
s1 = s2;
s2 = temp;
}
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("Hello");
StringBuffer s2 = new StringBuffer("World");
swap(s1, s2);
System.out.println(s1);
System.out.println(s2);
}
这将人口Hello World而不是World Hello,因为在交换函数中,您使用复印件,这些复印件不会对主要的参考产生影响。
public static void appendWorld(StringBuffer s1) {
s1.append(" World");
}
public static void main(String[] args) {
StringBuffer s = new StringBuffer("Hello");
appendWorld(s);
System.out.println(s);
}
如果您将 StringBuffer 更改为 String,它只会产生 Hello 因为 String 是不可变的。
public static void appendWorld(String s){
s = s+" World";
}
public static void main(String[] args) {
String s = new String("Hello");
appendWorld(s);
System.out.println(s);
}
但是,你可以为 String 做一个插槽,这将使它能够与 Strings 一起使用:
class StringWrapper {
public String value;
public StringWrapper(String value) {
this.value = value;
}
}
public static void appendWorld(StringWrapper s){
s.value = s.value +" World";
}
public static void main(String[] args) {
StringWrapper s = new StringWrapper("Hello");
appendWorld(s);
System.out.println(s.value);
}
编辑:我认为这也是使用 StringBuffer 的理由,当涉及到“添加”两个线条时,因为你可以修改原始对象,你不能用像 String 这样的不可变的对象。
讓我試圖用四個例子來解釋我的理解:Java是通過價值,而不是通過参考。
* * *
◎
public class PassByValueString {
public static void main(String[] args) {
new PassByValueString().caller();
}
public void caller() {
String value = "Nikhil";
boolean valueflag = false;
String output = method(value, valueflag);
/*
* 'output' is insignificant in this example. we are more interested in
* 'value' and 'valueflag'
*/
System.out.println("output : " + output);
System.out.println("value : " + value);
System.out.println("valueflag : " + valueflag);
}
public String method(String value, boolean valueflag) {
value = "Anand";
valueflag = true;
return "output";
}
}
output : output
value : Nikhil
valueflag : false
例子2:
/** * * Pass By 價值 */
public class PassByValueNewString {
public static void main(String[] args) {
new PassByValueNewString().caller();
}
public void caller() {
String value = new String("Nikhil");
boolean valueflag = false;
String output = method(value, valueflag);
/*
* 'output' is insignificant in this example. we are more interested in
* 'value' and 'valueflag'
*/
System.out.println("output : " + output);
System.out.println("value : " + value);
System.out.println("valueflag : " + valueflag);
}
public String method(String value, boolean valueflag) {
value = "Anand";
valueflag = true;
return "output";
}
}
output : output
value : Nikhil
valueflag : false
/** 这个“通过价值”具有“通过参考”的感觉
但是,从这个例子,我们可以理解,它只是通过值,记住,在这里我们通过参考作为值. 也就是说:参考通过值. 这就是为什么它们可以改变,但它仍然保持在当地范围后真实。
public class PassByValueObjectCase1 {
private class Student {
int id;
String name;
public Student() {
}
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
public static void main(String[] args) {
new PassByValueObjectCase1().caller();
}
public void caller() {
Student student = new Student(10, "Nikhil");
String output = method(student);
/*
* 'output' is insignificant in this example. we are more interested in
* 'student'
*/
System.out.println("output : " + output);
System.out.println("student : " + student);
}
public String method(Student student) {
student.setName("Anand");
return "output";
}
}
结果
output : output
student : Student [id=10, name=Anand]
例子4:
* * *
除了在Example3(PassByValueObjectCase1.java)中提到的外,我们不能在原始范围之外更改实际参考。
注意: 我不符合私人课堂学生的代码. 学生的课堂定义与例子3相同。
◎
public class PassByValueObjectCase2 {
public static void main(String[] args) {
new PassByValueObjectCase2().caller();
}
public void caller() {
// student has the actual reference to a Student object created
// can we change this actual reference outside the local scope? Let's see
Student student = new Student(10, "Nikhil");
String output = method(student);
/*
* 'output' is insignificant in this example. we are more interested in
* 'student'
*/
System.out.println("output : " + output);
System.out.println("student : " + student); // Will it print Nikhil or Anand?
}
public String method(Student student) {
student = new Student(20, "Anand");
return "output";
}
}
output : output
student : Student [id=10, name=Nikhil]