转自: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类型的变量和方法都存放在这里

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

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

  1. 对C++11中的`移动语义`与`右值引用`的介绍与讨论

    本文主要介绍了C++11中的移动语义与右值引用, 并且对其中的一些坑做了深入的讨论. 在正式介绍这部分内容之前, 我们先介绍一下rule of three/five原则, 与copy-and-swap ...

  2. C++ 右值引用与 const 关键字

    C++11 新增了另一种引用:右值引用(rvalue reference),这种引用可指向右值,是使用 && 声明的.使用右值引用可以减少复制操作,延长临时对象生命周期,提升程序性能. ...

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

    Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...

  4. Java Object 引用传递和值传递

    Java Object 引用传递和值传递 @author ixenos Java没有引用传递: 除了在将参数传递给方法(或函数)的时候是"值传递",传递对象引用的副本,在任何用&q ...

  5. Java中的基本类型和引用类型变量的区别

    Java中的基本类型和引用类型变量的区别   学了一年多,说实话你要我说这些东西我是真说不出来是啥意思     基本类型: 基本类型自然不用说了,它的值就是一个数字,一个字符或一个布尔值. 引用类型: ...

  6. Java的引用和C++的指针de区别

    Java的引用和C++的指针都是指向一块内存地址的,通过引用或指针来完成对内存数据的操作,就好像风筝的线轴一样,通过线轴总是能够找到风筝,但是它们在实现,原理作用等方面却有区别. (1)类型:引用其值 ...

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

    Day05_SHJavaTraing_4-8-2017 一.JVM对自己的内存划分为5个区域    1.方法栈:所有的方法运行的时候进入内存    2.堆:存储的是容器和对象    3.方法和数据共享 ...

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

    一.数据类型 Java中的数据类型分为两大类,基本数据类型和引用数据类型. 1.基本数据类型 基本数据类型只有8种,可按照如下分类 ①整数类型:long.int.short.byte ②浮点类型:fl ...

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

    PHP值传递和引用传递的区别.什么时候传值什么时候传引用 (1)按值传递:函数范围内对值的任何改变在函数外部都会被忽略 (2)按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改 (3)优 ...

随机推荐

  1. Redis篇:事务和lua脚本的使用

    现在多数秒杀,抽奖,抢红包等大并发高流量的功能一般都是基于 redis 实现,然而在选择 redis 的时候,我们也要了解 redis 如何保证服务正确运行的原理 前言 redis 如何实现高性能和高 ...

  2. Netty源码分析之Reactor线程模型详解

    上一篇文章,分析了Netty服务端启动的初始化过程,今天我们来分析一下Netty中的Reactor线程模型 在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocke ...

  3. [cf741C]Arpa’s overnight party and Mehrdad’s silent entering

    直接令2i-1和2i的位置不相同,相当于有2n条边,对其进行二分图染色即可(这张图一定不存在奇环). 假设给出的n条关系是A类边,2i-1和2i的边是B类边,可以发现一条路径一定是AB交替(因为A/B ...

  4. Furion分表分库我也要happy coding

    Furion分表分库集成ShardingCore ShardingCore ShardingCore 易用.简单.高性能.普适性,是一款扩展针对efcore生态下的分表分库的扩展解决方案,支持efco ...

  5. 一些需要记住的linux命令

    1. 系统帮助命令                      ----man 2. 数据同步写入磁盘               ----sync 3. 查找文件命令                  ...

  6. 测试平台系列(82) 解决APScheduler重复执行的问题

    大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们编写了在线执行R ...

  7. CF708E Student's Camp

    麻麻我会做*3100的计数了,我出息了 考虑朴素DP我们怎么做呢. 设\(f_{i,l,r}\)为第\(i\)层选择\(l,r\)的依旧不倒的概率. \(q(l,r)\)表示经历了\(k\)天后,存活 ...

  8. CF1036F

    考虑这种一堆数字\(gcd = k\) 有经典做法. 考虑设\(f(x)\)为\(gcd\)是\(x\)的倍数的方案数. \(g(x)\)为\(gcd\)刚好为\(x\)的方案数. 则有 \(f(x) ...

  9. c++STL容器之string容器

    本质:string是c++风格的字符串,而string本质上是一个类 string和char*的区别: char*是一个指针: string是一个类,类内部封装了char*,管理这个字符串,是一个ch ...

  10. CSS3单行文本两端对齐

    CSS3实现单行文本两端对齐 p { height: 24px; text-align: justify; text-last-align: justify; } p::after { display ...