Object源码分析(二)
第五个方法:protected native Object clone() throws CloneNotSupportedException;
源码简介:


clone方法首先会判对象是否实现了Cloneable接口,若无则抛出CloneNotSupportedException;
当某个类要复写clone方法时,要继承Cloneable接口。通常的克隆对象都是通过super.clone()方法来克隆对象。
一般的super.clone().getClass=x.getClass()。
clone有浅复制与深复制一说,浅复制与深复制的区别是对引用对象的处理区别:
(1)浅复制:
对于基本数据类型单纯复制值;
对于复合数据类型仅复制该栈值,如数组变量则复制地址,对于对象变量则复制对象的引用。


结果:


所以修改per2的hobby会影响per1,但是对于基本数据类型,age不会受影响。
(2)深复制,就是对于复合类型,重新new出来,给它赋值,然后set到克隆体。
代码同上,只需要将Person的浅复制代码注释,放开深复制代码;
结果:


所以对于深复制,修改per2并不会影响per1。
第六个方法:返回对象的字符串表示。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

第七个方法:protected void finalize() throws Throwable { }
1.执行时机不可预知
当一个对象变得不可触及时,垃圾回收器某个时期会回收此对象。
当回收对象之前会调用finalize方法,这类似于人类临终之前必须做一件事情:写遗言。
因为GC是不确定性的(这跟JVM相关),所以finalize方法的执行具有不可预知性。
2.finalize忽略异常
即finalize代码中若出现异常,异常会被忽略
3.finalize使用
什么时候使用?当一个对象在回收前想要执行一些操作,就要覆写Object类中的finalize( )方法。一般来说,finalize被作为第二种安全网来使用,如FileInputStream类, 当对象回收时,有可能资源为释放,所以这里第二次来确认(那也总比不释放强吧,虽然具体释放时机未定)。
protected void finalize() throws IOException {
if (fd != null) {
if (fd != fd.in) {
close();
}
}
}
最后三个方法:wait(), notify(), notifyAll(),这些属于基本的java多线程同步类的API,都是native实现:
该部分转载于 https://www.cnblogs.com/moongeek/p/7631447.html
public final native void wait(long timeout) throws InterruptedException;
public final native void notify(); public final native void notifyAll();
public class K {
//状态锁
private Object lock;
//条件变量
private int now,need;
public void produce(int num){
//同步
synchronized (lock){
//当前有的不满足需要,进行等待
while(now < need){
try {
//等待阻塞
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我被唤醒了!");
}
// 做其他的事情
}
}
}
显然,只有当前值满足需要值的时候,线程才可以往下执行,所以,必须使用while 循环阻塞。注意,wait() 当被唤醒时候,只是让while循环继续往下走.如果此处用if的话,意味着if继续往下走,会跳出if语句块。但是,notifyAll 只是负责唤醒线程,并不保证条件云云,所以需要手动来保证程序的逻辑。

public interface AbstractStorage {
void consume(int num);
void produce(int num);
}
import java.util.LinkedList; /**
* 生产者和消费者的问题
* wait、notify/notifyAll() 实现
*/
public class Storage1 implements AbstractStorage {
//仓库最大容量
private final int MAX_SIZE = 100;
//仓库存储的载体
private LinkedList list = new LinkedList(); //生产产品
public void produce(int num){
//同步
synchronized (list){
//仓库剩余的容量不足以存放即将要生产的数量,暂停生产
while(list.size()+num > MAX_SIZE){
System.out.println("【要生产的产品数量】:" + num + "\t【库存量】:"
+ list.size() + "\t暂时不能执行生产任务!"); try {
//条件不满足,生产阻塞
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} for(int i=0;i<num;i++){
list.add(new Object());
} System.out.println("【已经生产产品数】:" + num + "\t【现仓储量为】:" + list.size()); list.notifyAll();
}
} //消费产品
public void consume(int num){
synchronized (list){ //不满足消费条件
while(num > list.size()){
System.out.println("【要消费的产品数量】:" + num + "\t【库存量】:"
+ list.size() + "\t暂时不能执行生产任务!"); try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} //消费条件满足,开始消费
for(int i=0;i<num;i++){
list.remove();
} System.out.println("【已经消费产品数】:" + num + "\t【现仓储量为】:" + list.size()); list.notifyAll();
}
}
}
- 生产者
public class Producer extends Thread{
//每次生产的数量
private int num ;
//所属的仓库
public AbstractStorage abstractStorage;
public Producer(AbstractStorage abstractStorage){
this.abstractStorage = abstractStorage;
}
public void setNum(int num){
this.num = num;
}
// 线程run函数
@Override
public void run()
{
produce(num);
}
// 调用仓库Storage的生产函数
public void produce(int num)
{
abstractStorage.produce(num);
}
}
- 消费者
public class Consumer extends Thread{
// 每次消费的产品数量
private int num;
// 所在放置的仓库
private AbstractStorage abstractStorage1;
// 构造函数,设置仓库
public Consumer(AbstractStorage abstractStorage1)
{
this.abstractStorage1 = abstractStorage1;
}
// 线程run函数
public void run()
{
consume(num);
}
// 调用仓库Storage的生产函数
public void consume(int num)
{
abstractStorage1.consume(num);
}
public void setNum(int num){
this.num = num;
}
}
- 测试
public class Test{
public static void main(String[] args) {
// 仓库对象
AbstractStorage abstractStorage = new Storage1();
// 生产者对象
Producer p1 = new Producer(abstractStorage);
Producer p2 = new Producer(abstractStorage);
Producer p3 = new Producer(abstractStorage);
Producer p4 = new Producer(abstractStorage);
Producer p5 = new Producer(abstractStorage);
Producer p6 = new Producer(abstractStorage);
Producer p7 = new Producer(abstractStorage);
// 消费者对象
Consumer c1 = new Consumer(abstractStorage);
Consumer c2 = new Consumer(abstractStorage);
Consumer c3 = new Consumer(abstractStorage);
// 设置生产者产品生产数量
p1.setNum(10);
p2.setNum(10);
p3.setNum(10);
p4.setNum(10);
p5.setNum(10);
p6.setNum(10);
p7.setNum(80);
// 设置消费者产品消费数量
c1.setNum(50);
c2.setNum(20);
c3.setNum(30);
// 线程开始执行
c1.start();
c2.start();
c3.start();
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
p6.start();
p7.start();
}
}
- 输出
【要消费的产品数量】:50 【库存量】:0 暂时不能执行生产任务!
【要消费的产品数量】:20 【库存量】:0 暂时不能执行生产任务!
【要消费的产品数量】:30 【库存量】:0 暂时不能执行生产任务!
【已经生产产品数】:10 【现仓储量为】:10
【要消费的产品数量】:30 【库存量】:10 暂时不能执行生产任务!
【要消费的产品数量】:20 【库存量】:10 暂时不能执行生产任务!
【要消费的产品数量】:50 【库存量】:10 暂时不能执行生产任务!
【已经生产产品数】:10 【现仓储量为】:20
【已经生产产品数】:10 【现仓储量为】:30
【要消费的产品数量】:50 【库存量】:30 暂时不能执行生产任务!
【已经消费产品数】:20 【现仓储量为】:10
【要消费的产品数量】:30 【库存量】:10 暂时不能执行生产任务!
【已经生产产品数】:10 【现仓储量为】:20
【要消费的产品数量】:50 【库存量】:20 暂时不能执行生产任务!
【要消费的产品数量】:30 【库存量】:20 暂时不能执行生产任务!
【已经生产产品数】:10 【现仓储量为】:30
【已经消费产品数】:30 【现仓储量为】:0
【要消费的产品数量】:50 【库存量】:0 暂时不能执行生产任务!
【已经生产产品数】:10 【现仓储量为】:10
【要消费的产品数量】:50 【库存量】:10 暂时不能执行生产任务!
【已经生产产品数】:80 【现仓储量为】:90
【已经消费产品数】:50 【现仓储量为】:40
Object源码分析(二)的更多相关文章
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- 十、Spring之BeanFactory源码分析(二)
Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...
- Vue源码分析(二) : Vue实例挂载
Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...
- 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>
目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...
- Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题
4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...
- Tomcat源码分析二:先看看Tomcat的整体架构
Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...
- spring源码分析(二)Aop
创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...
- ConcurrenHashMap源码分析(二)
本篇博客的目录: 一:put方法源码 二:get方法源码 三:rehash的过程 四:总结 一:put方法的源码 首先,我们来看一下segment内部类中put方法的源码,这个方法它是segment片 ...
- HashMap源码分析(二):看完彻底了解HashMap
上文讲到HashMap的增加方法,现在继续 上文链接 HashMap在上一篇源码分析的文章中,如果使用put的时候如果元素数量超过threshold就会调用resize进行扩容 1.扩容机制 想要了解 ...
- Vue.js 源码分析(二十七) 高级应用 异步组件 详解
当我们的项目足够大,使用的组件就会很多,此时如果一次性加载所有的组件是比较花费时间的.一开始就把所有的组件都加载是没必要的一笔开销,此时可以用异步组件来优化一下. 异步组件简单的说就是只有等到在页面里 ...
随机推荐
- 获取 PHPstorm编辑器 注册码地址
网址: http://idea.lanyus.com/ 注册码有效期为2016年11月24日至2017年11月23日使用前请将“0.0.0.0 account.jetbrains.com”添加到hos ...
- 人工机器:NDC-谷歌机器翻译破世界纪录,仅用Attention模型,无需CNN和RNN
终于找到ML日报的微信链接,抄之...................................... 请拜访原文链接:[谷歌机器翻译破世界纪录]仅用Attention模型,无需CNN和RNN. ...
- js手机移动端选择插件 mobileSelect.js
一.mobileSelect获取方法 mobileSelect支持单选.多级联动.自定义回调函数.二次渲染.最新版本下载地址[2017-09-21更新]: https://github.com/onl ...
- [CodeForces1059E] Split the Tree
树形DP. 用倍增处理出来每个点往上能延伸出去的最远路径,nlogn 对于每个节点,如果它能被后代使用过的点覆盖,就直接覆盖,这个点就不使用,否则就ans++,让传的Max改成dp[x] #inclu ...
- SSH(远程登录)
在linux中SSH服务对应两个配置文件: ssh特点:在传输数据的时候,对文件加密后传输. ssh作用:为远程登录会话和其他网络服务提供安全性协议. ssh小结: 1.SSH是安全的加密协议,用于远 ...
- Dell R720修改远程管理口的密码
今天有个客户需要通过远程管理口来查看系统事件日志,但是他们把初始密码改过并且还给忘记了.后来我决定进操作系统(cent os)进行修改.整个过程很简单,进入系统后只需要三个步骤就解决问题了 1.安装软 ...
- 7.ES几种常见的搜索方式
主要知识点 1, query string search (1) GET /ecommerce/product/_search (2) GET/ecommerce/product/_search? ...
- CodeVS 1013&1029
若干二叉树遍历的数据结构题. Problem 1013 传送门:http://codevs.cn/problem/1013/ 本题是一个数据结构——二叉树遍历问题. 对二叉树,给定中序遍历序列(In- ...
- 《奋斗吧!菜鸟》 第八次作业:Alpha冲刺 Scrum meeting 1
项目 内容 这个作业属于哪个课程 任课教师链接 作业要求 https://www.cnblogs.com/nwnu-daizh/p/11012922.html 团队名称 奋斗吧!菜鸟 作业学习目标 A ...
- 【codeforces 789D】Weird journey
[题目链接]:http://codeforces.com/problemset/problem/789/D [题意] 给你n个点,m条边; 可能会有自环 问你有没有经过某两条边各一次,然后剩余m-2条 ...