Java值引用和对象引用区别Demo
转自:http://blog.csdn.net/gundsoul/article/details/4927404
以前就知道JAVA对象分对象引用和值引用,并且还知道8种基础数据类型,即引用时是值引用的数据类型,比如 int,short,long,byte,float,double,char,boolean,其它都是对象引用。可是其它的对象引用我一直都以为跟c 里面是一样的指针传递,直到今天才发现原来JAVA里面还是别有一番天地的。
1. 方法调用的时候,并不是类似c的指针传递,而是引用的复制
比如代码:
- void func1(List s) {
- s.add("dfdsa");
- }
- void test() {
- List<String> list = new ArrayList<String>();
- list.add("abc");
- func1(list);
- System.out.println(list.size()); // 此处结果为2
- }
以前一直以为在func1里面的s跟外面的list变量是同一个引用(暂且理解为指针好了)即在栈(stack)里面是同一个东东,这个结论无可厚非,可是看代码:
- void func(String s) {
- s += "tail";
- }
- void test() {
- String a = "abc";
- func(a);
- System.out.println(a); // 此处结果为abc
- }
经过讨论才发现,原来在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对象的引用。看代码:
- String s = "abc";
当程序执行该代码的时候,JVM会在String Pool里面通过equal("abc")方法查找有没有现成的String对象引用,如果没有,则在heap里面创建一个String对象并将该对象的 引用保存到String Pool里面;如果有了,那么就直接返回该对象的引用。
再看一段非常类似的代码:
- 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中,最后返回给调用方,看代码:
- String s1=new String("abc");
- String s2=s1.intern();
- String s3="abc";
- System.out.println(s1==s2); //false
- System.out.println(s2==s3); //true
- 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的更多相关文章
- 对C++11中的`移动语义`与`右值引用`的介绍与讨论
本文主要介绍了C++11中的移动语义与右值引用, 并且对其中的一些坑做了深入的讨论. 在正式介绍这部分内容之前, 我们先介绍一下rule of three/five原则, 与copy-and-swap ...
- C++ 右值引用与 const 关键字
C++11 新增了另一种引用:右值引用(rvalue reference),这种引用可指向右值,是使用 && 声明的.使用右值引用可以减少复制操作,延长临时对象生命周期,提升程序性能. ...
- Java中对象、对象引用、堆、栈、值传递以及引用传递的详解
Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...
- Java Object 引用传递和值传递
Java Object 引用传递和值传递 @author ixenos Java没有引用传递: 除了在将参数传递给方法(或函数)的时候是"值传递",传递对象引用的副本,在任何用&q ...
- Java中的基本类型和引用类型变量的区别
Java中的基本类型和引用类型变量的区别 学了一年多,说实话你要我说这些东西我是真说不出来是啥意思 基本类型: 基本类型自然不用说了,它的值就是一个数字,一个字符或一个布尔值. 引用类型: ...
- Java的引用和C++的指针de区别
Java的引用和C++的指针都是指向一块内存地址的,通过引用或指针来完成对内存数据的操作,就好像风筝的线轴一样,通过线轴总是能够找到风筝,但是它们在实现,原理作用等方面却有区别. (1)类型:引用其值 ...
- JVM内存划分以及值传递和引用传递的区别
Day05_SHJavaTraing_4-8-2017 一.JVM对自己的内存划分为5个区域 1.方法栈:所有的方法运行的时候进入内存 2.堆:存储的是容器和对象 3.方法和数据共享 ...
- Java中的基本数据类型和引用数据类型的区别
一.数据类型 Java中的数据类型分为两大类,基本数据类型和引用数据类型. 1.基本数据类型 基本数据类型只有8种,可按照如下分类 ①整数类型:long.int.short.byte ②浮点类型:fl ...
- PHP值传递和引用传递的区别
PHP值传递和引用传递的区别.什么时候传值什么时候传引用 (1)按值传递:函数范围内对值的任何改变在函数外部都会被忽略 (2)按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改 (3)优 ...
随机推荐
- myeclipse trial expired暂时解决办法
运行以下程序,生成key: import java.io.*; public class MyEclipseGen { private static final String LL = "D ...
- banner.txt
Spring Boot Version: ${spring-boot.version} __----~~~~~~~~~~~------___ . . ~~//====...... __--~ ~~ - ...
- Vue 中使用 extent 开发loading等全局 组件
Vue 中使用 extend 开发组件 简介:再开发过程中那面会遇到自定义 loading alert 等全局组件,这里我们可以使用 vue 中的extend 来帮助我们完成 一个简单extend例子 ...
- python 多行对应元素求和
今天有个统计需求,需要对应的元素的列求和,文件示例如下: 1 ID1 0 2 7 2 ID2 1 5 6 3 ID3 2 2 6 4 ID4 1 6 0 5 ID2 3 8 3 6 ID2 0 8 3 ...
- No.2 R语言在生物信息中的应用—模式匹配
目的: 1. 计算自定义模序在所有蛋白质的匹配位点和次数 2. 输出超过阈值的蛋白质序列到Hit_sequences.fasta 3. Hit_sequences.fasta中序列用小写字母,匹配用大 ...
- Git分布式版本控制系统基础
查看创建的账号 下来在该当前的⽬录下创建⽂件,并且进⾏提交 使⽤git log就可以看到最近提交的⽇志记录的信息 查看窗户的状态信息 某些时候我们可能需要回退到之前的版本,那么具体处理的步骤为: 1. ...
- MySQL:事务常用语句
Mysql(版本是8)的事务隔离级别 默认是RR:REPEATABLE-READ:可重复读 查看 当前隔离级别 全局隔离级别 修改 -- 当前修改 -- 设置成可重复读 SET transactio ...
- Spark(十七)【SparkStreaming需求练习】
目录 一.环境准备 1.pom文件 2.bean 3.工具类 JDBCUtils Properties工具类 3.创建BaseApp 需求一:动态添加黑名单 需求二:广告点击量实时统计 需求三:最近一 ...
- Hadoop【Hadoop-HA搭建(HDFS、YARN)】
目录 0.HDFS-HA的工作机制 1. HDFS-HA集群配置 1.1 环境准备 1.2 规划集群 1.3 配置Zookeeper集群 2. 配置HDFS-HA集群 3. 启动HDFS-HA集群 4 ...
- C++ 数组元素循环右移问题
这道题要求不用另外的数组,并且尽量移动次数少. 算法思想:设计一个结构体存储数组数据和它应在的索引位置,再直接交换,但是这种方法不能一次性就移动完成,因此再加一个判断条件.等这个判断条件满足后就退出循 ...