如何区分Java中的值传递和引用传递(急)

2024-11-06 03:29:17
推荐回答(5个)
回答(1):

值传递(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。

引用传递(形式参数类型是引用数据类型参数):也称为传地址。方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。

回答(2):

只有在方法调用的时候才涉及到值传递的概念!

Java中进行方法调用的时候传递参数时,遵循值传递的原则:
1)基本数据类型,传递的是数据的拷贝
2)引用数据类型,传递的是传递的引用地址的拷贝,而不是该对象本身

楼主的问题涉及到的内容太多,首先理解以下概念

形参:方法声明时的参数变量,用于接收调用方法时传过来的实参
如:void f(int i){} 或 void f(String s){}
实参:方法调用时实际传过去的内容,用于给形参赋值
如:f(1) 或 f("abc")

变量按不同的数据类型分为2类:
1)基本数据类型变量:4类8种基本类型,byte,short,char,int,long,float,double,boolean
如:int i = 0;
2)引用数据类型变量: 类,接口,数组
如:String s = "abc";

注意:Java中除了4类8种基本数据类型以外全部是引用数据类型

变量按声明的位置不同分为2类:
1)成员变量:方法外部,类内部声明的变量
2)局部变量:方法内部声明的变量,形参属于局部变量

变量的初始化:
1)成员变量:如果不显示对其初始化,那么Java采用默认值对其进行初始化
2)局部变量:不赋值,就不能使用

看来楼主对引用和对象的概念还不是特别了解,执行中的内存管理:

不同的操作系统不太一样,但一般内存都分为4个区域:
1)heap(堆):存放new出来的对象
2)stack(栈):存放局部变量
3)data segment(数据区):静态变量 和 字符串常量
4)code segment(代码区):存放代码

例子:
public class Test {

void f(int j) {
System.out.println(j);
}

void ff(String ss) {
System.out.println(ss);
}

public static void main(Stirng[] args) {
int i = 100;
String s = "hello";
Test t = new Test();
t.f(i);
t.ff(s);
}
}

当mian方法开始执行的时候
int i = 100; 栈中分配一块空间,存放变量i,值为100,基本数据类型只占一块空间
String s = "hello"; "hello"是字符串常量,分配在data区,字符串常量为String类的一个对象,
s指向了这个"hello"对象,这就是引用数据类型,在内存中占两块空间,
有点形象思维:一提引用类型,就是一块内存指向另一块内存
s可以被叫做:引用、引用变量、引用地址,其实s就是一个指针,在这里不用钻牛角尖,你就知道
s是一个引用,s的值是一个地址,根据这个地址就可以找到一个对象就ok了,
Test t = new Test(); 同理,栈中的引用t指向了堆中new出来的这个Test对象

Java中进行方法调用的时候传递参数时,遵循值传递的原则:
1)基本数据类型,传递的是数据的拷贝
2)引用数据类型,传递的是传递的引用地址的拷贝,而不是该对象本身

t.f(i);
方法的形参属于局部变量,所以在调用f方法的时候,栈内存分配一个int型的变量j,将i的值当做
实参传递过去,i的值是100,现在将100拷贝给了j,那么j的值就是100,这就是楼主说的“值传递
”,接着打印,最后方法结束,为该方法分配的局部变量立刻全部清空,那么Stack中这个j消失了

t.ff(s);
调用ff方法的时候,栈内存分配一个String型的变量ss,将s的值当做实参传递过去,s指向
了"hello"对象,s的值是一个地址,现在将这个地址拷贝给了ss,那么ss也就指向这个"hello"了
这就是楼主说的"引用传递",现在s 和 ss 两个引用 同时指向了"hello"对象,然后打印ss,最后方
法结束,栈中这个ss被清除

现在main方法执行结束,为main方法分类的局部变量清除,i,s,t全部消失,data区的符串常
量"hello"和堆内存的Test对象,由于没有任何引用指向他们了,就会被垃圾收集器回收

累死我了..

回答(3):

关于JAVA中参数传递问题有两种,一种是按值传递(如果是基本类型),另一种是按引用传递(如果是对象).
首先以两个例子开始:
1)
public class Test2 {

public static void main (String [] args) {
StringBuffer a = new StringBuffer ("A");
StringBuffer b = new StringBuffer ("B");
operate (a,b);
System.out.println(a+","+b);
}

static void operate(StringBuffer x, StringBuffer y){
x.append(y);
y = x;
}
}
输出:AB,B

2)
public class Test2 {
public static void add3 (Integer i){
int val=i.intValue();
val += 3;
i = new Integer (val);
}

public static void main (String args [ ] ) {
Integer i = new Integer (0);
add3 (i);
System.out.println (i.intValue ( ));
}
}
输出:0
首先我们应该明白JAVA中的参数传递全是以值传递的。是基本类型,就拷贝一个基本类型传进方法;是引用,就拷贝一个引用变量传进去方法,理解了这两点就能理解方法操作对象的相关问题了。最好能画出引用指向对象的图出来,就能完全理解了。
第1题,调用operate方法时,传入了两个引用a,b的拷贝x,y,这两个x,y都指向原a,b引用所指向的对象。x.append(y)对它指向的对象(即a指向的对象)进行了操作。而x=y,只是两个拷贝变量在赋值,并没有影响到原b所指向的对象。所以b所指向的对象仍然为B。
第2题,i=new Integer(val)只是一个引用的拷贝指向了另外一个对象,而原来的i仍然是指向对象new Integer(0)的。
把握住了JAVA都是传值并且传的都是拷贝的话,类似的题大家都能迎刃而解了。

Java中的参数传递只有一种方式: by value. 理论说教太麻烦了,直接看些例子吧:
1). 基本类型
public class A{
public static void main(String[] args){
int x = 1;
System.out.println(x); //1
test(x);
System.out.println(x); //还是1==>By value
}

static void test(int a){
a = 2;
}
}

2). 引用类型
public class B{
public static void main(String[] args){
Integer x = new Integer(1);
System.out.println(x);
test(x);
System.out.println(x);

}

static void test(Integer a){
a = new Integer(2);
}
}

理解这里的关键是区分对象和引用。 这里声明的x是一个引用,而不是一个对象(只是Java把它设计为看上去好像是对象一样)。这个引用它指向了一个对象,这个对象就是后面用new关键字生成的对象。因此,可以说x指向了一个Integer对象。
在调用test方法的时候,程序将x作为参数传递给test方法了。这里仍然是值传递,在test调用过程中,会产生一份新的引用(不妨叫做y)。此时,x和y指向了同一个对象。
x和y指向的是同一个对象, 由于Java的设计,我们可以通过操作引用来达到操作对象的目的。因此,如果我们此时使用y来修改对象的属性 (例如,y.someField++); 你可以看到x指向的对象同时也被修改到了。
另一方面,如果我们让y指向另外一个对象, y=new Integer(2); 此时x和y就指向了不同的
对象。y修改了它指向的对象的属性,很显然不会影响到x指向的对象。

有人说了数组。数组也是一个引用类型,它的参数传递方式按照引用类型的参数传递一样可以解释得通:

import java.util.Arrays;

public class A{
public static void main(String[] args){
int[] aa = {3, 2, 1};
System.out.println(Arrays.toString(aa)); //[3, 2, 1]
test(aa);
System.out.println(Arrays.toString(aa)); //[3, 2, 1]
test2(aa);
System.out.println(Arrays.toString(aa)); //[4, 2, 1]
}

static void test(int[] a){
a = new int[]{1, 2, 3}; //指向了新对象
}

static void test2(int[] a){
if(a != null && a.length > 0)
a[0]++; //修改原来的那个对象
}
}

对象是传引用,简单类型是传值,不要被网上的一些概念所迷惑!!!你可以自己做个试验。
至于String等类型传的还是引用。如果你用concat方法,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 = "World" 就等同于 String str=new String("World")。所以结果没有改变!!!

下列程序在1处是否会有异常,如果没有,输出是什么?是否会运行到2处,如果会,输出是什么?为什么会有这样的结果?

  import java.util.arraylist;
   import java.util.list;
  
   public class testclass {

   public static void main(string args[]) {
     list list = new arraylist();
     test2(list);
     system.out.println(list.size()); // 1处
     test3(list);
     system.out.println(list.size()); // 2处
   }
  
   public static void test2(list list) {
     list = null;
   }
  
   public static void test3(list list) {
      list.add(“aaaa“);
   }
   }

plumechen:

不会出错的。结果是0,1。

因为test2(list)传得是list的引用,我理解成指针置的副本,list=null;只是把那个传入的值设置为null,不改变原来list的指针和内容。test3(list)传入的一样,但是执行了list.add()由于传入指针值的副本也指向原来的那个list的地址,所以原来的那个list的内容就改变了,size变成了1了

回答(4):

形参和实参的传递是国内某个知名教授一个错误观点误导了整整一代程序员啊。
java的2%非oop里面就是基本类型,除String外,int,float,double和boolean这些基本类型不是对象外,万事万物皆是对象,为一个方法传递一个或一组对象,我们可以简单的认为传递的是这个对象的内存地址,也就是引用,在方法里对这个对象做了什么事,都真实反映到该对象身上,这是引用传递。只有基本类型作为参数才是值传递,方法里对这个值的任何操作并不影响基本类型的值。

回答(5):

//值传递
int a = 10;
int b = a;
//引用传递
int a = 10;
void fun(int a)
{
int b = a;
}
fun(a);