Java值引用和对象引用区别Demo

转自:http://blog.csdn.net/gundsoul/article/details/4927404

以前就知道JAVA对象分对象引用和值引用,并且还知道8种基础数据类型,即引用时是值引用的数据类型,比如 int,short,long,byte,float,double,char,boolean,其它都是对象引用。可是其它的对象引用我一直都以为跟c 里面是一样的指针传递,直到今天才发现原来JAVA里面还是别有一番天地的。

    1. 方法调用的时候,并不是类似c的指针传递,而是引用的复制

比如代码:

  1. void func1(List s) {
  2. s.add("dfdsa");
  3. }
  4. void test() {
  5. List<String> list = new ArrayList<String>();
  6. list.add("abc");
  7. func1(list);
  8. System.out.println(list.size()); // 此处结果为2
  9. }

以前一直以为在func1里面的s跟外面的list变量是同一个引用(暂且理解为指针好了)即在栈(stack)里面是同一个东东,这个结论无可厚非,可是看代码:

  1. void func(String s) {
  2. s += "tail";
  3. }
  4. void test() {
  5. String a = "abc";
  6. func(a);
  7. System.out.println(a); // 此处结果为abc
  8. }

经过讨论才发现,原来在stack里面a和func里面的s是完全不同的两个引用,虽然它们指向同一个堆(heap)里面的对象,之所以跟上面的代 码结果看起来不一样,只是因为String是一个非可变类(immutable),简单的说就是实例是不可被修改的。在func里面执行s += "tail";操作的时候,s这个引用已经变成指向heap里面另外一个值为"abctail"的对象了,老的s引用已经被废了,随时可以被gc回收了

    2. String对象在内存中的位置

既然String是一个immutable的类,那么对于同样值的String实例,我们是可以不必重复创建的,于是就有了JVM中的String Pool的概念。简单的说,String Pool里面放着heap里面String对象的引用。看代码:

  1. String s = "abc";

当程序执行该代码的时候,JVM会在String Pool里面通过equal("abc")方法查找有没有现成的String对象引用,如果没有,则在heap里面创建一个String对象并将该对象的 引用保存到String Pool里面;如果有了,那么就直接返回该对象的引用。

再看一段非常类似的代码:

  1. String s = new String("abc");

当程序执行该代码的时候,JVM会像普通对象一样生成这个String对象,在heap里面保存,直接返回引用,并不会与String Pool交互,这样一来,String Pool的优势就没有被发挥了,怎么办呢?难道我们就不去使用new的方法创建String了吗?答案是JVM还提供了一个方 法:String.intern();来让String Pool管理这种String对象。

intern方法的工作原理是这样的:首先在heap里面创建一个完全一样的String对象,并且将该对象的引用放入String Pool中,最后返回给调用方,看代码:

  1. String s1=new String("abc");
  2. String s2=s1.intern();
  3. String s3="abc";
  4. System.out.println(s1==s2); //false
  5. System.out.println(s2==s3); //true
  6. System.out.println(s1==s3); //false
  • s1引用的是heap里面的一个普通String对象,在String Pool中没有该对象的引用
  • s2是heap中另一个String对象的引用,并且该对象的引用已经存在在String Pool中了
  • s3在创建的时候JVM通过查找String Pool发现已经有一个同样的对象,所以直接返回给s3一个到该对象的引用

结论:我们在写JAVA代码的时候要尽量避免使用String s = new String("abc");这种方式,因为这样产生的对象并没有“注册”到String Pool中,无法被重复使用,如果已经存在这种对象了,我们可以通过使用s = s.intern();的方式重新创建对象并“注册”到String Pool中,方便后面的重复使用。

    3. 深入JVM内存的划分

由于JVM对与heap和stack内存的使用有其特殊的规则,深入了解JVM是如何使用内存的,非常有助于我们在写程序的时候搞清楚自己的对象到底在什么地方,从而可以帮助我们在多线程程序和性能要求较高的程序中优化自己代码,有兴趣的同学可以参考sun的官方文档(http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#1732),下面仅就部分知识做简单描述。

a. 每个线程都有自己独占的stack,里面存放的是当前线程执行的method及其局部变量

b. heap中有部分是公共区域,存放的是类实例(class instance)和已分配内存的数组(array)

c. heap中对于每个线程都有各自独立的内存区域,存放以下内容:

运行时常量池(runtime constant pool),上面提到的String Pool就属于其中的一部分

方法代码(method code),即线程要执行的方法代码

静态变量和方法(static variables and method),我们定义的static类型的变量和方法都存放在这里

更详细的描述可以参考图片:

时间: 2024-10-24 11:16:02

Java值引用和对象引用区别Demo的相关文章

Java中对象、对象引用、堆、栈、值传递以及引用传递的详细解释

Java中对象.对象引用.堆.栈.值传递以及引用传递的详细解释 1.对象和对象引用的区别: (1).对象: 万物皆对象.对象是类的实例.在Java中new是用来在堆上创建对象用的.一个对象可以被多个引用所指向. (2).对象引用: 类似于C++中的地址.通过对象引用可以找到对象.一个引用可以指向多个对象.操纵的标识符实际上是指向对象的引用. 就像:对象存放在屋子里,对象的引用就相当于屋子的钥匙. 2.值传递和引用传递的区别: (1).值传递:传递的是值的拷贝.也就是说传递后就不互相关了. (2)

Java技术_Java千百问(0039)_引用传递和值传递有什么区别

点击进入_更多_Java千百问 1.什么是值传递 值传递,是将内存空间中某个存储单元中存放的值,传送给另一个存储单元.(java中的存储单元并不是物理内存的地址,但具有相关性) 例如: //定义了一个改变参数值的函数 public static void changeValue(int x) { ??x = x *2; } public class TestMain{ //调用该函数 int num = 5; System.out.println(num); changeValue(num);

Java Object 引用传递和值传递

Java Object 引用传递和值传递 @author ixenos Java中的引用传递: 除了在将参数传递给方法(或函数)的时候是"值传递",传递对象引用的副本,在任何用"="向引用对象变量赋值的时候都是"引用传递",传递对象的引用给另一个变量. 参数传递,传递引用的副本,这看起来是引用传递,实则是传递了副本,这已经是值传递的概念了: 变量赋值,传递引用,这算引用传递 Java参数传递中没有引用传递都是值传递 1.在 Java 应用程序中永

Java值传递和引用传递

1.Java到底是值传递还是引用传递呢? 对于java中的值传递和引用传递一直颇受争论,<Core Java>的作者,以及JAVA的创造者James Gosling都认为当一个对象或引用类型变量被当作参数传递时,也是值传递,这个值就是对象的引用,因此JAVA中只有值传递,没有引用传递.还有一种说法是引用可以看作是对象的别名,当对象被当作参数传递给方法时,传递的是对象的引用,因此是引用传递.而<Thinking in Java>一书的作者Bruce Eckel则站在了中立的立场上.

[引用区别] c++中引用与java中引用区别

综述: 在Java中,类实例声明和构造是分开."T a;"是声明,而"a=new T();"才是构造.引用声明和C++相同.但是Java的机制与C++不同,Java中的引用也叫句柄,或者说句柄才是其真实名称.类声明的都是一个句柄,调用构造函数才会使得句柄指向类实例.因此Java中没有类似于C++中的复制函数,因为Java的复制都是直接复制句柄内容.例如"T b=a;"只不过是将a的句柄复制(赋值)给了b,从而b也指向a指向的类实例.可以看出Jav

JVM内存划分以及值传递和引用传递的区别

4-8-2017_SHJavaTraing_Day05 一.JVM对自己的内存划分为5个区域    1.方法栈:所有的方法运行的时候进入内存    2.堆:存储的是容器和对象    3.方法和数据共享: 运行时期class文件进入的地方    4.本地方法栈: JVM调用了系统中的功能    5.寄存器:内存和CUP之间 二.值传递和引用传递的区别(易错内容) 1.方法参数是基本数据类型 方法参数是基本数据类型时,传递的是值. 1 //演示方法参数是基本数据类型的传递 2 class Demo{

Java中的基本数据类型和引用数据类型的区别

一.数据类型 Java中的数据类型分为两大类,基本数据类型和引用数据类型. 1.基本数据类型 基本数据类型只有8种,可按照如下分类 ①整数类型:long.int.short.byte ②浮点类型:float.double ③字符类型:char ④布尔类型:boolean No. 数据类型 大小/位 可表示数据范围 默认值 1 byte(字节型) 8 -128~127 0 2 short(短整型) 16 -32768~32767 0 3 int(整型) 32 -2147483648~2147483

PHP值传递和引用传递的区别

PHP值传递和引用传递的区别.什么时候传值什么时候传引用 (1)按值传递:函数范围内对值的任何改变在函数外部都会被忽略 (2)按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改 (3)优缺点: A:按值传递时,php必须复制值.特别是对于大型的字符串和对象来说,这将会是一个代价很大的操作. B.按引用传递则不需要复制值,对于性能提高很有好处. 1 <?php 2 header('content-type:text/html;charset=utf-8'); 3 4 //探讨一下 a

C++ Primer 学习笔记_17_从C到C++(3)--引用、const引用、引用传递、引用作为函数返回值、引用与指针区别

欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 一.引用 1.引用是给一个变量起别名 变量: 名称 空间 引用: 引用不是变量 引用仅仅是变量的别名 引用没有自己独立的空间 引用要与它所引用的变量共享空间 对引用所做的改变实际上是对它所引用的变量的改变 引用在定义的时候必须要进行初始化 引用一经初始化,不能重新指向其他变量 2.定义引用的一般格式: (1)类型  &引用名 = 变量名: (2)例如: int a=1; int &b=a; // b是a的别名,因此a和b是同一个单元 (3)