java对象引用在方法中传递

java对象引用在方法中传递

package com.cy;

public class Client {

public static void main(String[] args) {

Student std = new Student("cy", 24);

changeStudentNameAndAge(std);

System.out.println(std.toString());

}

// 改变学生姓名和年纪

// 1.直接操作对象

private static void changeStudentNameAndAge(Student std) {

std.setName("chenyin");

std.setAge(84);

}

// 2.重新new一个对象

private static void changeStudentNameAndAge(Student std) {

std = new Student("chenyin", 84);

}

}

情况1. 执行代码1  输出的语句是 Student [age=84, name=chenyin]

情况 2. 执行代码2  输出的语句是Student [age=24, name=cy] 为什么会出现两种不同点结果呢?

因为 Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。

即上述的方法中 changeStudentNameAndAge(Student std),std只是main函数中std引用的一个副本。即

局 部变量std 指向了 main方法变量std指向的地址。因为方法中的参数是形参,他只是保存了main方法中std指向内存区域的地址。不能理解 changeStudentNameAndAge(Student std)中std和mian中的std是一样的。因为你可以写changeStudentNameAndAge(Student std1) changeStudentNameAndAge(Student std2).

当情况1时 游泳changeStudentNameAndAge(Student std)中std指向的地址和main方法中std指向的是同一个地址,那么对changeStudentNameAndAge(Student std)中std操作,则也改变了mian中std指向的内容。

而情况2则不同。 changeStudentNameAndAge(Student std)std使用了new的方法,则std重新指向了一块存储区域。那么对changeStudentNameAndAge(Student std)中std操作,实际上改变了std新创建区域的值,而对mian方法std指向的内容是没有影响的。因为mian中std和 changeStudentNameAndAge(Student std)中的std指向的不是同一个内存区域。

将代码1编译后的.class文件拖放到eclipse中

public class com.cy.Client { 
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public Client();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: com.cy.Client
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 4, Locals: 2
  public static void main(java.lang.String[] args);
     0  new com.cy.Student [16]
     3  dup
     4  ldc <String "cy"> [18]
     6  bipush 24
     8  invokespecial com.cy.Student(java.lang.String, int) [20]
    11  astore_1 [std]
    12  aload_1 [std]
    13  invokestatic com.cy.Client.changeStudentNameAndAge(com.cy.Student) : void [23]
    16  getstatic java.lang.System.out : java.io.PrintStream [27]
    19  aload_1 [std]
    20  invokevirtual com.cy.Student.toString() : java.lang.String [33]
    23  invokevirtual java.io.PrintStream.println(java.lang.String) : void [37]
    26  return
      Line numbers:
        [pc: 0, line: 11]
        [pc: 12, line: 13]
        [pc: 16, line: 15]
        [pc: 26, line: 17]
      Local variable table:
        [pc: 0, pc: 27] local: args index: 0 type: java.lang.String[]
        [pc: 12, pc: 27] local: std index: 1 type: com.cy.Student
  // Method descriptor #26 (Lcom/cy/Student;)V
  // Stack: 2, Locals: 1
  private static void changeStudentNameAndAge(com.cy.Student std);
     0  aload_0 [std]
     1  ldc <String "chenyin"> [47]
     3  invokevirtual com.cy.Student.setName(java.lang.String) : void [49]
     6  aload_0 [std]
     7  bipush 84
     9  invokevirtual com.cy.Student.setAge(int) : void [52]
    12  return
      Line numbers:
        [pc: 0, line: 25]
        [pc: 6, line: 26]
        [pc: 12, line: 28]
      Local variable table:
        [pc: 0, pc: 13] local: std index: 0 type: com.cy.Student
}

可以看出在mian中存储了Student对象在changeStudentNameAndAge(com.cy.Student std)中aload_0 [std]即该方法操作的地址和main中申请的地址一样。所以改变changeStudentNameAndAge方法中的name和age会引起main中的变量同步改变。

将2编译后的.class拖放到eclipse

public class com.cy.Client {
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public Client();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: com.cy.Client
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 4, Locals: 2
  public static void main(java.lang.String[] args);
     0  new com.cy.Student [16]
     3  dup
     4  ldc <String "cy"> [18]
     6  bipush 24
     8  invokespecial com.cy.Student(java.lang.String, int) [20]
    11  astore_1 [std]
    12  aload_1 [std]
    13  invokestatic com.cy.Client.changeStudentNameAndAge(com.cy.Student) : void [23]
    16  getstatic java.lang.System.out : java.io.PrintStream [27]
    19  aload_1 [std]
    20  invokevirtual com.cy.Student.toString() : java.lang.String [33]
    23  invokevirtual java.io.PrintStream.println(java.lang.String) : void [37]
    26  return
      Line numbers:
        [pc: 0, line: 11]
        [pc: 12, line: 14]
        [pc: 16, line: 16]
        [pc: 26, line: 18]
      Local variable table:
        [pc: 0, pc: 27] local: args index: 0 type: java.lang.String[]
        [pc: 12, pc: 27] local: std index: 1 type: com.cy.Student
  // Method descriptor #26 (Lcom/cy/Student;)V
  // Stack: 4, Locals: 1
  private static void changeStudentNameAndAge(com.cy.Student std);
     0  new com.cy.Student [16]
     3  dup
     4  ldc <String "chenyin"> [47]
     6  bipush 85
     8  invokespecial com.cy.Student(java.lang.String, int) [20]
    11  astore_0 [std]
    12  return
      Line numbers:
        [pc: 0, line: 23]
        [pc: 12, line: 29]
      Local variable table:
        [pc: 0, pc: 13] local: std index: 0 type: com.cy.Student
}

可以发现main中的std使用了astore_1 [std]而changeStudentNameAndAge使用了astore_0 [std]很明显,代码2中的changeStudentNameAndAge使用了new Student()方法导致mian中std指向的地址和changeStudentNameAndAge中的std指向的地址不是用一个模块了。因此对changeStudentNameAndAge中std的改变影响不了mian中。

由 上例可见,将对象的引用传递给方法时,只是将这个引用指向的地址传给了方法。或者说只是将对象的引用复制了一个副本。是这两个引用指向了同一块地址,当在方法中直接操作这个引用副本时会改变这个引用副本和引用指向的区域。但是若在方法中将引用的副本重新指向了一个内存区域,对这个引用副本的操作不会引起引 用指向地址的内容的改变。

时间: 2024-10-11 12:54:42

java对象引用在方法中传递的相关文章

Python向方法中传递自定义类型参数

定义类型 class Fish: def __init__(self,x): self.num = xclass Turtle: def __init__(self,y): self.num = yclass Pool: def __init__(self,x,y): self.fish = Fish(x) self.turtle = Turtle(y) def print_num(self): print('fish %d,trutle %d'%(self.fish.num,self.turt

java List.subList方法中的超级大陷阱

ArrayList 中 subList 的基本用法: subList(fromIndex:int,toIndex:int):List<E> 返回从fromIndex到toindex-1 的 子列表 在使用集合中,可能常常需要取集合中的某一部分子集来进行一下操作,于是subList这个方法就映入我们的眼帘,毫不犹豫地使用. 例如以下代码: public static void main(final String[] args) { List<Object> lists = new A

java 访问器方法中对象引用的问题

"注意不要编写返回引用可变对象的访问器方法".因为会破坏类的封装性,引用的内容可能会被改变,产生业务逻辑上的错误. 什么是可变对象? 先要搞清楚java中值传递和引用传递的问题,总结如下: 1.对象就是传引用 2.原始类型就是传值 3.String,Integer, Double等immutable类型因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待.可以认为是传值. Integer 和 String 一样.保存value的类变量是Final属性,无法被修改,只能被重新赋值

java 关于getProperty()方法中反斜杠问题

问: 在配置文件a.properties中有一行path=C:\test在java中getProperty("path")后,java把\t认为是一个字符TAB.怎样才能取到正确的结果:C:\test呢 答: 使用C:\\test或者C:/test... properties文件的约定 在windows下"/""\"都是合法路径分隔符,在Linux/Unix下只有"/"是合法的

C#方法中的ref和out

ref        通常我们向方法中传递的是值.方法获得的是这些值的一个拷贝,然后使用这些拷贝,当方法运行完毕后,这些拷贝将被丢弃,而原来的值不将受到影响.此外我们还有其他向方法传递参数的形式,引用(ref)和输出(out).    有时,我们需要改变原来变量中的值,这时,我们可以向方法传递变量的引用,而不是变量的值.引用是一个变量,他可以访问原来变量的值,修改引用将修改原来变量的值.变量的值存储在内存中,可以创建一个引用,他指向变量在内存中的位置.当引用被修改时,修改的是内存中的值,因此变量

【Java基础】11、java方法中只有值传递,没有引用传递

转自:http://www.cnblogs.com/linkstar/p/5951141.htmlpublic class Example { String testString = new String("good"); char[] testCharArray = {'a','b','c'}; public static void main(String[] args){ Example ex = new Example(); ex.change(ex.testString,ex.

java方法中只有值传递,没有引用传递

public class Example { String testString = new String("good"); char[] testCharArray = {'a','b','c'}; public static void main(String[] args){ Example ex = new Example(); ex.change(ex.testString,ex.testCharArray); System.out.println(ex.testString)

Android中Intent传递Java对象的方法

Android中Intent传递Java对象有两种方法:一是通过调用Bundle对象的putSerializable(Key,Object)方法[参见示例],另一种是通过调用Bundle对象的putParcelable(Key,Object)方法[参见示例]. 第一种方法要求传递的Java对象实现Serializable接口--Serializable接口是JavaSE特有的接口,采用该种方法实现类的序列化非常简单,声明一下系统会自动将其序列化. 第二种方法要求传递的Java对象实现了Parce

Java方法中传值和引用传递的问题(转)

说明:标题其实说法是错误的.Java中只有值传递,没有引用传递. ... ... //定义了一个改变参数值的函数 public static void changeValue(int x) { x = x *2; } ... ... //调用该函数 int num = 5; System.out.println(num); changeValue(num); System.out.println(num); ... ... 调用函数changeValue()前后num的值都没有改变. 值传递的过