这里的讨论是关于Java究竟是传值还是传引用?在简单类型中是按值传递的,但是在其他不同的对象上呢?本文给出作者自己的一些见解。

1. 简略类型是按值传递的

评论:Java究竟是传值仍是传引证?(java传值还是传引用)  Java 传值 引用 第1张

Java 办法的参数是简略类型的时分,是按值传递的 (pass by value)。这一点咱们能够经过一个简略的比方来阐明:

public class Test {
   public static void test(boolean test) {
   test = ! test;
   System.out.println("In test(boolean) : test = " + test);
   }
   public static void main(String[] args) {
   boolean test = true;
   System.out.println("Before test(boolean) : test = " + test);
   test(test);
   System.out.println("After test(boolean) : test = " + test);
   }
  }

运转成果:

Before test(boolean) : test = true
  In test(boolean) : test = false
  After test(boolean) : test = true

不难看出,尽管在 test(boolean) 办法中改动了传进来的参数的值,但对这个参数源变量自身并没有影响,即对 main(String[]) 办法里的 test 变量没有影响。那阐明,参数类型是简略类型的时分,是按值传递的。以参数办法传递简略类型的变量时,实际上是将参数的值作了一个复制传进办法函数的,那么在办法函数里再怎样改动其值,其成果都是只改动了复制的值,而不是源值。

2. 什么是引证

Java 是传值仍是传引证,问题首要出在目标的传递上,由于 Java 中简略类型没有引证。已然争辩中说到了引证这个东西,为了搞清楚这个问题,咱们有必要要知道引证是什么。

简略的说,引证其实就像是一个目标的姓名或许别号 (alias),一个目标在内存中会恳求一块空间来保存数据,依据目标的巨细,它或许需求占用的空间巨细也不等。拜访目标的时分,咱们不会直接是拜访目标在内存中的数据,而是经过引证去拜访。引证也是一种数据类型,咱们能够把它幻想为相似 C 言语中指针的东西,它指示了目标在内存中的地址——只不过咱们不能够观察到这个地址终究是什么。

假如咱们界说了不止一个引证指向同一个目标,那么这些引证是不相同的,由于引证也是一种数据类型,需求必定的内存空间来保存。可是它们的值是相同的,都指示同一个目标在内存的中方位。比方

String a = "Hello";
  String b = a;

这儿,a 和 b 是不同的两个引证,咱们运用了两个界说句子来界说它们。但它们的值是相同的,都指向同一个目标 "Hello"。或许你还觉得不可直观,由于 String 目标的值自身是不可更改的 (像 b = "World"; b = a; 这种状况不是改动了 "World" 这一目标的值,而是改动了它的引证 b 的值使之指向了另一个 String 目标 a)。那么咱们用 StringBuffer 来举一个比方:
  

public class Test {
   public static void main(String[] args) {
   StringBuffer a = new StringBuffer("Hello");
   StringBuffer b = a;
   b.append(", World");
   System.out.println("a is " + a);
   }
  }
    运转成果:
  
  a is Hello, World

这个比方中 a 和 b 都是引证,当改动了 b 指示的目标的值的时分,从输出成果来看,a 所指示的目标的值也改动了。所以,a 和 b 都指向同一个目标即包括 "Hello" 的一个StringBuffer 目标。

这儿我描绘了两个关键:

1. 引证是一种数据类型,保存了目标在内存中的地址,这种类型即不是咱们平常所说的简略数据类型也不是类实例(目标);

2. 不同的引证或许指向同一个目标,换句话说,一个目标能够有多个引证,即该类类型的变量。

3. 目标是怎么传递的呢

关于目标的传递,有两种说法,即“它是按值传递的”和“它是按引证传递的”。这两种说法各有各的道理,可是它们都没有从实质上去剖析,即致于产生了争辩。已然现在咱们现已知道了引证是什么东西,那么现在无妨来剖析一下目标作是参数是怎么传递的。仍是先以一个程序为例:

public class Test {
   public static void test(StringBuffer str) {
   str.append(", World!");
   }
   public static void main(String[] args) {
   StringBuffer string = new StringBuffer("Hello");
   test(string);
   System.out.println(string);
   }
  }
    运转成果:
  
  Hello, World!

test(string) 调用了 test(StringBuffer) 办法,并将 string 作为参数传递了进去。这儿 string 是一个引证,这一点是勿庸置疑的。前面说到,引证是一种数据类型,并且不是目标,所以它不或许按引证传递,所以它是按值传递的,它么它的值终究是什么呢?是目标的地址。

由此可见,目标作为参数的时分是按值传递的,对吗?错!为什么错,让咱们看另一个比方:

public class Test {
   public static void test(String str) {
   str = "World";
   }
   public static void main(String[] args) {
   String string = "Hello";
   test(string);
   System.out.println(string);
   }
  }
    运转成果:  
  Hello

为什么会这样呢?由于参数 str 是一个引证,并且它与 string 是不同的引证,尽管它们都是同一个目标的引证。str = "World" 则改动了 str 的值,使之指向了另一个目标,可是 str指向的目标改动了,但它并没有对 "Hello" 形成任何影响,并且由于 string 和 str 是不同的引证,str 的改动也没有对 string 形成任何影响,成果就如例中所示。

其成果是推翻了参数按值传递的说法。那么,目标作为参数的时分是按引证传递的了?也错!由于上一个比方确实能够阐明它是按值传递的。

成果,就像光到底是波仍是粒子的问题相同,Java 办法的参数是按什么传递的问题,其答案就只能是:便是按值传递也是按引证传递,仅仅参照物不同,成果也就不同。

①单纯考虑参数str存的也是一种数据类型,能够看成是值传递。

②考虑参数str它是目标string的一个引证,此刻就可看做是引证传递。

4. 正确看待传值仍是传引证的问题

要正确的看待这个问题有必要要搞清楚为什么会有这样一个问题。

实际上,问题来源于 C,而不是 Java。

C 言语中有一种数据类型叫做指针,所以将一个数据作为参数传递给某个函数的时分,就有两种办法:传值,或是传指针,它们的差异,能够用一个简略的比方阐明:

void SwapValue(int a, int b) {
   int t = a;
   a = b;
   b = t;
  }
  void SwapPointer(int * a, int * b) {
   int t = * a;
   * a = * b;
   * b = t;
  }
  void main() {
   int a = 0, b = 1;
   printf("1 : a = %d, b = %d\n", a, b);
   SwapValue(a, b);
   printf("2 : a = %d, b = %d\n", a, b);
   SwapPointer(&a, &b);
   printf("3 : a = %d, b = %d\n", a, b);
  }
    运转成果:
  
  1 : a = 0, b = 1
  2 : a = 0, b = 1
  3 : a = 1, b = 0

我们能够显着的看到,按指针传递参数能够便利的修正经过参数传递进来的值,而按值传递就不可。

当 Java 生长起来的时分,许多的 C 程序员开端转向学习 Java,他们发现,运用相似SwapValue 的办法依然不能改动经过参数传递进来的简略数据类型的值,可是假如是一个目标,则或许将其成员随意更改。所以他们觉得这很像是 C 言语中传值/传指针的问题。可是 Java 中没有指针,那么这个问题就演化成了传值/传引证的问题。惋惜将这个问题放在 Java 中进行评论并不恰当。

评论这样一个问题的终究意图仅仅为了搞清楚何种状况才能在办法函数中便利的更改参数的值并使之长期有效。

Java 中,改动参数的值有两种状况,***种,运用赋值号“=”直接进行赋值使其改动,如例 1 和例 4;第二种,关于某些目标的引证,经过必定途径对其成员数据进行改动,如例 3。关于***种状况,其改动不会影响到办法该办法以外的数据,或许直接说源数据。而第二种办法,则相反,会影响到源数据——由于引证指示的目标没有变,对其成员数据进行改动则实质上是改动的该目标。

【修改引荐】

  1. Java编译器中对String目标的优化
  2. 痛批Java十大最无用特性
  3. 深化探究Java作业原理:JVM,内存收回及其他
转载请说明出处
知优网 » 评论:Java究竟是传值仍是传引证?(java传值还是传引用)

发表评论

您需要后才能发表评论