由 System.arraycopy 引发的巩固:对象引用 与 对象 的区别
来源:互联网 发布:java resultset 行数 编辑:程序博客网 时间:2024/06/05 20:32
了解这些术语:
- 深复制又称深拷贝,两个变量的内存地址不一样,各自修改不影响对方。
- 浅复制又称浅拷贝,两个变量的内存地址一样,既是同一个变量,仅仅是引用不同罢了,各自修改是会影响对方的,因为本身就是同一个。
这篇文文我要讲的有:
- System.arraycopy 是深复制
- System.arraycopy 的陷阱点
对象引用
与对象
的区别- 简历不要写
精通java
,写熟练
首先明确一点,System.arraycopy 操作的是数组,效果是深复制。 是不是觉得怎么和你印象的中不一样?
重点来了,对于对象数组,例如: User[],这种数组,有一个注意点
,这个点就是:对于数组内的对象是浅拷贝。
一句话:
System.arraycopy 对于数组是深拷贝,对于数组内的对象是浅拷贝。因为操作的传入参数是数组,那么回归本意,效果是深复制。
上面的含义一定要区分清楚! 因为现在网上很多观点是混淆,乱JB写的 。
来看个例子,下面的代码可以自己去运行验证。已经充分验证了上面我的观点。
public class Test { public static void main(String[] args) { User[] users=new User[]{ new User("111"),new User("222"),new User("333") };//初始化对象数组 User[] target=new User[users.length];//新建一个目标对象数组 System.arraycopy(users, 0, target, 0, users.length); // 复制 System.out.println("数组地址是否一样:"+(users == target?"浅复制":"深复制")); System.out.println("数组内对象地址是否一样:"+(users[0] == target[0]?"浅复制":"深复制")); target[0].setEmail("444"); System.out.println("修改后输出 users[0] ,是否和 target[0]一样是444,users[0]:"+users[0].getEmail()); users[0] = null; // -----------------① System.out.println("遍历 users"); for (User user : users){ System.out.println(user); } System.out.println("遍历 target"); for (User user : target){ System.out.println(user); } users = null; if(target == null){ System.out.println("users = null 后是否 target 也变成了 null,是则证明是浅复制"); }else{ System.out.println("users = null 后是否 target 不受任何影响,是则再次证明数组是深复制"); } }}class User{ private String email; public User(String email) { this.email = email; } public String getEmail() { return email;} public void setEmail(String email) { this.email = email; } @Override public String toString() { return "User [email=" + email+ "]"; }}
输出的结果如下:
数组地址是否一样:深复制数组内对象地址是否一样:浅复制修改后输出 users[0],是否和 target[0]一样是444,users[0]:444遍历 usersnullUser [email=222]User [email=333]遍历 targetUser [email=444]User [email=222]User [email=333]users = null 后是否 target 不受任何影响,是则再次证明数组是深复制
上面我的例子还留有一个经典的面试点,既是标号 ① 对应的行:
users[0] = null; // -----------------①
上面我们谈到了,数组内的对象是浅复制,那么在上面这行我把 users[0] 下标为0的对象弄为 null 后。后面再遍历输出:
System.out.println("遍历 users");for (User user : users){ System.out.println(user);}System.out.println("遍历 target");for (User user : target){ System.out.println(user);}
明显地,我们可以容易知道,user[0] 此时输出的肯定是 null。那么 target[0] 呢?浅拷贝的话,target[0] 必然在内存地址和值上面全等于 users[0]
。
但是从 System.out.println("遍历 target");
的结果来看。却发现 target 输出的是:
遍历 targetUser [email=444] // 第一个不是 nullUser [email=222]User [email=333]
这是为什么呢?其实这是最为基础的: 对象引用与对象的区别
,一名合格,仅仅是合格的 Java 语言使用者,这个得知道。下面我们来谈谈它。
有一个类:
public class Demo { //默认构造方法 public Demo{ } }
我们用它创建个对象
Demo fuck = new Demo();
这一条语句,其实包括了四个动作:
- 右边的“new Demo”,是以Demo类为模板,在
堆空间
里创建一个Demo对象。 - 末尾的()意味着,在对象创建后,立即调用Demo类的构造函数,对刚生成的对象进行初始化。
- 左边的“Demo fuck”创建了一个Demo类引用变量,它存放在
栈空间中
。也就是用来指向Demo对象的对象引用。 - “=”操作符使对象引用指向刚创建的那个Demo对象。对象引用的名字叫做
fuck
Demo fuck;//一个对象引用 fuck = new Demo();//一个对象引用指向一个对象
一个对象可以被多个对象引用同时引用。它们操作的始终是同一个。
Demo fuck,fuck2;//创建多个对象引用 fuck = new Demo(); fuck2 = fuck;
好了,回答之前的坑, users[0] = new User("111")
,users[0] = null
,target[0] = users[0]
,users[0] = null 只是把栈中的 users[0] 对象引用弄为了 null,对象 new User("111") 与它无关,自然没影响,target[0] 是另外一个对象引用,也是指向了 new User("111")。
根据 大 Jvm 的 内存回收算法之根搜索,引用链存在、强引用、when 当前应用内存不够了,强制抛出 OOM。那么当 target[0] = null
,new User("111")
对应的这块内存就会进入被回收的队列中,“死去”。
最后这段是不是有点看不懂 ?那证明你要继续努力了。
- 由 System.arraycopy 引发的巩固:对象引用 与 对象 的区别
- 由Equals()引发的对对象的引用与对象(即实例)的关系的思考
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- Java 对象与对象引用的区别
- 对象引用与对象的区别
- 对象引用与对象的区别
- Java对象引用与对象的区别
- 对象与对象引用变量的区别
- 对象引用与对象的区别
- [NLP论文阅读] Learning Paraphrastic Sentence Embeddings from Back-Translated Bitext
- sdut-3332 数据结构实验之栈与队列五:下一较大值(一)
- spring上传文件报错Expected MultipartHttpServletRequest: is a MultipartResolver configured?
- 数人云PaaS Innovation 2017,重新定义PaaS进化
- Java的split详解
- 由 System.arraycopy 引发的巩固:对象引用 与 对象 的区别
- RBAC基于角色的访问控制 thinkphp
- 第五周项目1——建立顺序栈算法库
- java类和对象的联系,区别
- andengine战争迷雾(地图探索)探究
- 如何做好一个网站
- c#读取Excel
- SVN 配置,应用
- 如何解决虚拟机频繁分离和附加磁盘导致的识别错误