第五周总结
1.TreeSet集合
TreeSet集合:
本质基于TreeMap的底层实现(红黑树结构---->自平衡"的二叉树结构")
有两种排序方式:
自然排序
选择器排序
取决于创建当前Set集合对象的时候的构造方法
public TreeSet():默认的自然顺序排序
TreeSet<Integer>
由于TreeSet属于Set集合(本身保证元素唯一,不重复的元素!),还可以将元素按照自然顺序排序
TreeSet集合源码
结论:
如果使用TreeSet集合存储自定义对象,那么要进行自然排序?
那么该自定义对象所在的类必须实现Comparable接口,重写Comparaeable接口中
CompareTo(T t)方法!
刚才存储TreeSet<Integer>: TreeSet() :空参构造(默认自然排序)
由于Integer类它已经实现了Compareable接口中的compareTo方法
使用三元运算符进行判断
如果要使用比较器排序,那么自定义对象所在的类必须实现comparator接口,
重写接口中:compare方法
2.Map集合
Map集合:
java.util.Map<K,V>:接口
需求:学生有姓名和年龄,通过学生的学号查询学生的姓名
Java提供了集合:双列集合
键:K 学号:String "班级+学号id" 键的特点:必须唯一的!
值:V 学生Student
Map集合的特点: 一个键值对元素(一个键对应一个值,值是可以重复,但是键必须唯一)
只针对键有效,跟值无关! (看成是:夫妻对)
Map<String,Student>
学生学号 学生的姓名
1 马伊琍
2 李四
3 王五
1 姚笛
面试题:
Map和Collection集合的区别?
Map<K key,V value>集合:双列集合,键映射到值的对象 ,键必须保证唯一,可以看成是一个(夫妻对)
遍历方式和Collection集合遍历方式不同
Collection<E>集合:
单列集合:只能存储一种引用类型,里面的set集合依赖于Map集合的实现 (理解为:光棍)
HashSet---->HashMap里面put方法
TreeSet---->TreeMap里面的put方法
Map集合的功能:
添加功能
V put(K key, V value) :添加一个键值对元素
问题:返回值是什么意思
//如果当前键是一次存储的时候,返回的结果null
//如果键是不是第一次存储,后面重复,将当前对应的值把以前的值覆盖掉并保存下来,返回以前的值!
刪除功能:
V remove(Object key):刪除指定的键,返回的是跟键关联的值,如果没有映射关系,则返回null
void clear():删除全部的键以及值
判断功能
boolean containsKey(Object key):是否包含指定的键
boolean containsValue(Object value):是否包含指定的值
boolean isEmpty():判断Map集合是否为空
高级功能:
方式1:(推荐的方式:Map常用的方式)
Set<K> keySet():获取所有的键的集合
V get(Object key):通过键获取对应的值
方式2遍历
Set<Map.Entry<K,V>> entrySet():获取当前Map集合中所有的键值对对象
K getKey() :通过键值对对象获取键
V getValue():通过键值对对象获取值
3.HashMap
HashMap<K,V>是Map集合的子实现类,里面哈希表结构,保证(键唯一)
Map集合只只针对键有效
HashMap<Integer,String>键:Integer
HashMap<String,Student> :键:String
HashMap<Student,String>:键是自定义对象
HashMap<Student,String>:键是自定义对象
键:学生:自定义对象
值:String:朝代
自定义的对象存储在值的位置,是可以重复的!,如果是在键位置,不能重复!!!
对于Map存储的键如果是自定义对象:该自定义对象的所在类必须重写Object:equals()和hashCode()
会依赖于HashMap的put方法
hash()---->依赖于hashCode():算出每一个对象哈希码值一样
putValue()---->equals()方法:哈希码值一样,还有比较每一个成员信息是否相同!
4.TreeMap:红黑树结构
TreeMap:红黑树结构
构造方法:
public TreeMap():默认的自然顺序排序
public TreeMap(Comparator<? super K> comparator):是一种比较器排序(推荐)
TreeMap<Student,String> / TreeSet<Studdent>: 一定要有条件进行排序!
按照主要条件:学生的年龄从小到进行排序!
面试题:
TreeSet集合存储自定义类型,什么情况下自然排序(Comparable),什么情况下是选择器排序(Comparator)?
执行无参构造方法:TreeSet<Student>():无参构造----是自然排序:
要求当前自定义类型需要实现Comparable接口,重写comparesTo方法
执行有参构造方法:TreeSet<Student>(Comparator<Student> com):
方式1:自定义一个类实现Comparator接口中 的compare(T t1,T t2)方法
方式2:通过接口匿名内部类实现
5.针对Collection集合进行操作的工具类!
Collections:java.util.Collections 类
可以针对Collection集合进行操作的工具类!
public static <T> int binarySearch(List<?> list,T key):针对集合的二分查询方法:
查询key在集合中出现的索引值
public static <T> T max(Collection<? extends T> list):获取集合中最大值
public static <T> T min(Collection<? extends T> list):获取集合中最小值
public static <T> void sort(List<T> list):针对List集合进行排序:升序排序
public static <T> void sort(List<T> list,Comparator<T> com):比较器排序
public static void shuffle(List<?> list):针对List集合的元素进行随机置换
6.异常
什么是异常
程序出现了问题,使用"异常"来描述问题
举例:
生活中一些问题
班长骑车去旅行
1)在骑行的过程中,路面塌陷了,导致不能骑行了!----- 不可抗力的因素!(严重问题)
2)在准备骑行的时候,车胎没气了,导致不能骑行了!----
在骑行前应该检查的工作(可以检查维修,可以解决的)
3)在骑行过程中,中间路面是平坦的,两边是石子,就在两边上骑行,导致车胎没气了
-----
在骑行的时候,no zuo no die (自己的原因导致)
java.lang.Throwable:异常类( Java 语言中所有错误或异常的超类(父类))
error:严重错误(严重问题)
比如:内存异常!OOM(Out Of Memory)
通过加入内存条...或者将Linux虚拟机的内存空间设置小一点!
Exception: 可以捕获合理的程序!
编译时期异常:只要不是RuntimeException中的子类都是属于编译时期
必须要处理的,不处理编译通不了,没有办法运行的!
运行时期异常RuntimeException:
程序在执行过程中出现的问题
代码逻辑不够严谨导致的!
异常的处理方案有哪些:
异常的处理方案有哪些:
1)try...catch...finally:标准格式 捕获异常
2)throws:抛出异常 (抛出到方法上)
方式1:捕获异常的变形格式
try...catch...
try...catch...catch...
try...finally... (线程中:Lock锁)
格式:流程
try{
...
...
可能出现问题代码
}catch(异常类名 变量名){//具体异常的类
//处理异常
//自己手动处理
//Throwable类中一些方:处理方式(jvm将异常信息输出在控制台并且可以跟踪异常类源码)
}
一旦try中的代码出现问题了,就会
执行到catch语句,具体执行处理异常的代码
如果try中存在多个异常,如何处理
如果try中存在多个异常,如何处理
1)一个一个try...catch...
2)一个try多个catch...
try...catch...finally(标准格式)
变形格式:
try...catch...
try...catch...catch...(推荐)
JDK7以后:提供一种处理方式
try{
可能出现问题的代码
..
}catch(异常类名1 | 异常类名2 | 异常类名3 ...... 变量名){ //平级关系
//处理异常
}
注意事项:
如果使用try...catch...catch...catch...
那么后面的catch语句中的异常类要么是同级关系要么是前面异常的类父类!
捕获的标准格式
捕获的标准格式
try{
//可能出现问题的代码
}catch(异常类名 对象名){
对象名.printStackTrice() ;
}finally{
//释放相关系统资源close()
//举例:IO流中: createNewfile():创建文件的方法
//举例:JDBC:java 连接数据库
//Connection: 连接对象---- 使用完毕需要关闭相关的系统资源!
//Statement:执行对象(增删查改的操作):---使用完了也需要释放系统资源
}
try中代码如果不存在问题,代码正常执行,需要执行finally语句,释放系统资源!
finally特点:
释放相关的系统资源,而且finally中的代码一定会执行的;除非在执行finally语句之前
JVM退出了! System.exit(0) ;
针对异常处理的另一种方式:
针对异常处理的另一种方式:
throws:抛出异常
抛出在方法声明上,如果方法中的语句体出现了异常,将异常交给jvm,jvm将异常信息输出
控制台上...
面试题
throws和throw的区别
throws:抛出
1)书写位置是在方法声明上
2)throws的后面跟的异常类名,而且可以跟多个异常类名,中间使用逗号隔开
3)对于throws它是由调用者进行处理,必须要对带throws的方法进行处理!
4)throws表示抛出异常的一种肯能性(这个方法可能出现问题/可能没有问题!)
throw:抛出
1)书写位置是在方法体中
2)throw的后面跟的异常对象,一般都是匿名对象 new XXXException()
而且只能跟一个异常对象
3)由方法中逻辑判断进行处理(由方法体中语句进行处理)
4)throw:表示抛出异常一种肯定性(执行到逻辑的时候,一定会执行这个异常!)
异常的注意事项:
1)子类继承父类的时候,对父类的成员方法进行重写,如果父类的成员方法有异常
那么子类的该方法针对异常处理,要么是跟父类的异常类名一致,要么是父类异常类的子类
2)子类继承父类重写父类的方法的时候
父类的成员方法没有抛出异常,子类的该方法不能抛出异常,只能try...catch...
编译时期异常和运行时期的区别
编译时期异常和运行时期的区别?
编译时期的异常:
举例:
String---Date---解析的方法parse(String source) throws ParseException{}
IO流:IOException
...
开发者必须要进行显示处理,否则编译通过不了!
运行时期异常:
1)代码逻辑的问题,不进行显示处理,在代码中加入一些逻辑判断
2)也可以进行显示处理:try...catch...
关于Throwable中的一些方法
关于Throwable中的一些方法
public String getMessage():获取异常的消息字符串
public String toString():获取异常信息的简单描述
异常的全限定名称:包名.类名: 调用该异常对象的getMessage()详细的消息字符串
public void printStackTrace():
将此对象的信息追踪到堆栈中,具体获取到具体源码中哪一块出问题了
自定义的异常!
1)自定义一个类,继承自Exception或者RuntimeException
2)提供无参构造方法 /有参构造 传递String参数(消息字符串)
面试题
如果捕获异常的时候,
try...catch...finally,catch中如果有return语句,那么finally中的代码还会执行吗?
在return之前执行还是return之后执行
会执行,除非Jvm退出了不执行!
return 之前
7.线程
如何实现一个多线程程序?
要实现多线程---线程是依赖于进程,创建进程---->创建系统资源
但是Java语言不能够直接创建系统的,JDK提供一个类:Thread
线程类
jvm是可以运行多个线程并发的执行
并发:在同一个时间点同时发生的!
方式1:
1)自定义一个类 继承Thread类 :线程类
2)重写Thread类中的run方法
3)在当前用户线程中(main)中创建该类对象,
启动线程 :start()方法
设置线程的名称
public final void setName(String name)
获取线程的名称
public final String getName()
实现方式
1)自定义类,继承自Thread类
2)重写Thread类中run方法
3)在主线程中创建该类对象,启动线程
Java能够开启线程吗?
Java不能够直接开启线程的!
start方法方法---通过JVM调用
start方法本身就是同步方法----线程安全的方法
将所有的开启的线程(在运行之前),将线程添加到线程组中:ThreadGroup:一个线程组中包含多个线程
调用start0():间接实现的
本地方法----C++语言实现 !
public final void setDaemon(boolean on):设置守护线程
在启动线程之前,调用这个方法才能设置为守护线程 (注意事项!)
(如果当前运行中线程都是守护线程,JVM退出)
举例:
坦克大战游戏
两个玩家---看成两个线程,如果老巢不存在了,这个两个线程就挂了!
如何获取主线程中名称呢?
public static Thread currentThread():表示当前正在运行的线程
getName():获取线程名称
setName(String name):设置当前线程名称
public final void join() throws InterruptedException:等待该线程终止
public final void setPriority(int newPriority)
设置线程的优先级
public final int getPriority():获取线程的优先级
线程的优先级: 常量值
public static final int MAX_PRIORITY:最大优先级 10
public static final int MIN_PRIORITY:最小优先级 1
public static final int NORM_PRIORITY:默认优先级 5
优先级越大的线程抢占CPU的执行权几率大
优先级越小的线程抢占CPU的执行几率小
符号线程的执行具有随机性
public static void sleep(long millis) throws InterruptedException
线程睡眠 (阻塞式方法!)
参数为时间毫秒值!
线程的生命周期/线程的状态
State:线程的状态:是Thread类内部枚举
public enum State {
NEW, 线程新建状态 ---->public static final...
RUNNABLE,线程运行状态
BLOCKED,线程阻塞状态(sleep(),等待)
WAITING,//死死等待
TIMED_WAITING,//超时等待 等待到一定时间,不等了
TERMINATED;//线程终止!
}
@Deprecated:JDK提供内置注解:标记方法是否以过时!
public final void stop():已过时的方法,但是可以使用!强迫线程停止执行
public void interrupt():中断线程 :中断线程的一种状态!(6种状态),
打破了状态之后,继续执行程序!
面试题:
sleep(long time)和wait()的区别 (等待唤醒机制:wait方法+notify方法)
public static void yield():暂停当前正在执行的线程对象,并执行其他线程!
理解为"谦让"
线程的执行随机性
多线程的实现方式2(推荐)
1)自定义一个类(资源类),这个类实现接口:Runnable接口---用到了Java设计模式之代理模式!
2)重写Runnable接口中的run方法
3)在主线程中main
3.1)创建当前资源类对象,
3.2)在创建Thread类对象,将3.2中的资源类对象作为参数进行传递
4)启动线程 start方法启动
7.1多线程实现方式1和实现方式2对比
方式1:
1)自定义一个类MyThread,继承自 Thread
2)重写Thread类中run方法
3)在main中,创建该线程类对象
MyThread my1 = new MyThread() ;
MyThread my2 = new MyThread() ;
MyThread my3 = new MyThread() ;
my1.start();
my2.start() ;
my3.start() ;
my1,my2在并发的执行
继承关系的弊端:
局限性
它不能够体现出"数据共享"的概念!
电影卖票:100张票 三个窗口
每一个窗口可能都在卖自己的100张票
线程的执行 "随机性"
原子性操作:
100张: 变量tickets (tickets--) 100 --- 99
栈内存 堆内存
MyThread my1 new MyThread() ;
MyThread my2 new MyThread() ;
MyThread my3 new MyThread() ;
第二种方式
优势:静态代理
能够体现出 "资源共享"
1)自定义一类MyRunnable implements Runnable
2)重写run方法
3)创建资源类对象,创建线程类对象,将资源类对象当做参数传递
MyRunnable my = new MyRunnable() ;
// public Thread(Runnable target, String name) :创建线程类对象并同时给线程设置名称
Thread t1 = new Thread(my, "窗口1") ;
Thread t2 = new Thread(my, "窗口2") ;
Thread t3 = new Thread(my, "窗口3") ;
//启动线程
t1.start();
t2.start();
t3.start();
栈内存中 堆内存中
Thread t1 new Thread(0x01) Thread(Runnable runable)
Thread t2 ....
Thread t3 ...
MyRunnable my(0x01) ------> new MyRunnable()
7.2多线程的安全问题
多线程的安全问题如何解决呢?
检验多线程安全问题的标准是什么?
1)查看当前环境是否是多线程环境 是
2)当前程序中是否存在共享数据 门票 (存在)
3)是否有多条语句对共享数据进行操作 存在
针对上面1),2),3)哪一个解决
1)不能动,现在就使用多线程环境
2) 不能动,因为使用方式2实现,当前类都是共享数据!
3)可以解决呢! 优化
为了解决这个问题:Java提供了一个关键字:synchronized
同步代码块
synchronized(锁对象){ //门的开/关
多条语句对共享数据进行操作
}
锁对象:多个线程应该使用的是通一把锁!
举例:
火车上排队上厕所
t1,t2,t3 ---门(厕所门)
t1进去,t1将门关了;t2/t3进不来
t2进来,t2将门关了;t1/t3进不来
...
7.3代理
代理: 让别人帮助我们完成一些事情!
举例:
过年回家买火车票(别人代买)
代理分类:
静态代理
动态代理
JDK动态代理
Cglib动态代理
静态代理
1)真实角色只专注于自己的事情
2)找一个代理类---代理角色来完成真实角色完成不了的事情
代理角色和真实角色都需要实现同一个接口 (Thread类:多线程的实现方式2)
Tread类:真实角色----启动线程(完成自己的事情):系统资源启动
自定义类:MyRunnable implements Runnable{} 代理角色
代理角色重写run方法()
完成代理的业务...
结婚这个事情
1)我们自己操办整个结婚的过程
2)找婚庆公司操办
private synchronized void sellTickt() :锁对象是谁
非静态的同步方法的锁对象:this--- 当前这个所在类的对象的地址值引用!
静态的同步方法的锁对象是谁呢?
静态的同步方法和反射相关-----跟类的字节码文件对象 xxx.class
static随着类的加载而加载 :锁对象:当前类名.class
SellTicket.class------ class com.qianfeng_thread_01.SellTicket
Lock锁
java.util.concurrent.locks.Lock
juc包下的接口
Lock接口提供一些相关的功能,比synchronized有具体的锁定操作(具体的功能
获取锁/释放锁)
Lock不能直接实例化:
具体的子实现类ReentrantLock
功能:
public void lock():获取锁
public void unlock():试图释放锁
面试题:Syncrhonized和Lock的区别
//面试题:Syncrhonized和Lock的区别!
public class SellTicket implements Runnable {
private static int tickets = 100 ;
//具体的锁对象:
Lock lock = new ReentrantLock() ; //lock
@Override
public void run() {
//一只有票
while(true) {
//异常的处理方式:
//try...catch...finally(释放相关系统资源):标准格式
//变形格式:try...catch...catch...
//try...finally
//t1,t2,t3
try {
//加入锁:获取锁
lock.lock(); //---- synchronized(锁对象){}
if(tickets>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+
(tickets--)+"张票");
}
}finally {
//释放锁----
//释放相关的系统资源
lock.unlock();
}
}
}
}
7.4死锁
如果通用的方式:synchronized同步代码块/同步方法解决线程安全问题
但是可能会出现一种死锁!
死锁:加入同步之后,两个或者两个以上的线程在互相抢占资源的时候出现一种互相等待的情况!
解决:
加入生产者消费者模式
定义三个类
DieLockDemo:主线程所在的类
MyDieLock : 创建两把锁 两个Object对象
DieLock(资源类) 实现 Runnable接口
定义四个类
StudentDemo类:用户线程
Student: 学生数据 姓名和年龄(暂时不加入私有化)
SetThread:生产者资源类
不断的去产生学生数据
GetThread:消费者资源类
不断的使用学生数据
按照上面方式:
问题:
null---0
在生产者资源类和消费者资源类操作的数据----->不是同一个数据!
生产者消费模式: 需要让多个线程针对同一个(资源数据)进行操作
优化:
生产者不断的去产生数据
消费者不断的使用数据
为了场景适合----生产者提供while循环,消费者中也提供while
问题2:学生数据出现紊乱------ 加入锁:同步代码块
在给当前设置生产者资源类以及 消费者中加入了同步,解决了安全问题,学生数据不会出现紊乱
但是数据打印的---一次性打印很多个
打印大片----->某个线程抢占到CPU权,它一点时间片执行很多次
优化:
在上面代码的基础上,想让结果出现"依次打印"数据
高圆圆41
张冲26
高圆圆41
....
生产者资源类所在的这个生产者线程中---->需要不断产生数据---->
等待 消费者资源类所在的线程将数据使用掉
消费资源所在的线程不-----> 不断使用数据--->
等待 生产资源类所在的线程不断产生数据
问题:
当生产者资源类所在的线程 产生数据需要等待消费消费,(生产者线程不知道消费者线程是否将数据使用完毕)
消费者资源类所在的线程 不断使用完毕数,需要等生产者线程产数据,(消费者线程不知道当前生产者线程是否产生数据了)
8.线程组:ThreadGroup:
线程组:ThreadGroup:
一个线程的集合!
Thread类中:
public final ThreadGroup getThreadGroup():获取当前线程所属的线程组
Thread类中
Thread(ThreadGroup th,String name)
ThreadGroup
public final String getName() :获取线程组名称
线程组中包含很多个线程,每一个线程默认的线程组名称:main
线程启动过程: start()---->当前所有启动的线程添加到线程组中了
将所有的线程添加线程组之后,线程执行完毕了,变成垃圾--->被回收
9.线程池----多线程的第三种实现方式
线程池----多线程的第三种实现方式
创建一个固定的可重用的线程数,当这些线程使用完毕终止了,它(线程对象)不会被回收掉
归还到线程池中,下次在利用!
ExecutorService 接口:不能实例化
间接通过:
java.util.concurrent 类 Executors :线程池的工厂类
23种设计模式(思想)---- 创建型设计模式中一种 "静态工厂方法模式"
工厂类中一些静态功能:返回值 ExecutorService
public static ExecutorService newFixedThreadPool(int nThreads)
提交异步任务(执行)
<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable<T> task)
Future:
V get():获取当前计算结果的值
返回值:表示异步计算的结果
void shutdown()启动一次顺序关闭,执行以前提交的任务,但不接受新任务
数据库--连接池
后面: 每次连接数据库的时候---产生Connection:连接对象
提供一些第三方:德鲁伊(druid:阿里的),cp30,dbcp
当前创建一个连接池:固定的可重复利用的Connection对象,每次使用完毕close()--
将它归还到连接池中(参数:最大连接数量10,最小连接数量,
数据库连接对象查过最大连接数量的超时间,数据库的密码,用户名,连接url地址...)
池化技术!
10.插入排序:直接插入
使用1角标对应的元素和前面的元素比较,如果本身值大,比较结束;如果小于前面的值,
将当前元素插入该元素前面;依次这样比较,2,3,4...角标元素比较....
//插入排序:直接插入
private static void insertSort(int[] arr) {
for(int x = 1 ; x < arr.length ; x ++) {
for (int y = x; y > 0; y--) {
// 满足条件:
if (arr[y] < arr[y - 1]) {
// 定义中间变量
int temp = arr[y];
arr[y] = arr[y - 1];
arr[y - 1] = temp;
} else {
// 如果当前arr[y]> arr[y-1] 比较结束
break;
}
}
}
}
11.等待唤醒机制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1YJXpKZH-1604126579922)(D:\Documents\Desktop\02_等待唤醒机制引入.bmp)]
12.线程匿名内部类的方式
线程匿名内部类的方式
new 类名/接口名(){
重写方法
};
匿名内部类的本质:
继承了该类或者实现了该接口子类的对象
匿名内部类的好处----降低了耦合性!(解耦)
13.Timer: 定时器工具
java.util.Timer: 定时器工具
可以重复执行某个任务/或者执行一次任务
构造方法
public Timer():构造一个新的计时器
成员方法:
public void cancel():终止定时器
String日期文本--->Date日期格式:
public void schedule(TimerTask task,Date time)
在指定日期时间内容将执行这个 任务!
public void schedule(TimerTask task, long delay):在指定时间后执行当前这个task任务
需求:18:00将某个目录下(存在多级目录)中的所有带.java文件删除掉!(timer定时器+递归删除+File类的操作)
java.util.Date---long ---->long getTime()
public void schedule(TimerTask task, long delay,long period):
在某个时间内容执行这个任务,然后每经过period时间毫秒值后重复执行任务!
TimerTask:由定时器Timer来安排是执行一次/重复执行当前任务
public abstract void run():任务要执行的操作
14.设计模式:
14.1简单工厂模式—“静态工厂方法模式”
设计模式:
创建型模式
简单工厂模式---"静态工厂方法模式"
1)需要提供一个工厂类: ------线程池:ExecutorsService
xxxFactory --工厂类:Exectors
构造方法是私有的,不能直接实例化
2)需要在工厂类中提供具体对象的创建---功能是一个静态的
工厂类.静态方法名()-----创建某个对象
14.2工厂方法模式
创建型模式
工厂方法模式
1)需要抽象类的子类对象的创建需要 对应的工厂类实现对象的创建过程!
抽象的动物类:Animal
子类:Cat/Dog ----- 有自己的工厂类
弊端
//新的类型:Pig 类继承自Animal(抽象类)
---需要提供当前类的工厂类:PigFactory: 代码量增加了
14.3单例模式:
单例模式:
保证 在内存中始终只有一个该类对象,该类对象的创建时自动创建!
具体分为:
饿汉式
懒汉式
饿汉式:是不会出现任何安全问题的单例模式!
1)创建一个类,这个类成员位置:定义静态实例变量:创建该类对象
2)无参构造方法私有化
3)提供对外的公共静态功能:获取该类对象
代表:
java.lang.Runtime:表示与Java应用程序相关的运行环境!
获取/执行相关的系统软件/查看系统变量...
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
14.4单例模式之懒汉式
单例模式之懒汉式
当前类中
1)构造方法私有化
2)在成员位置,并不是一开始就直接创建该类实例
而是声明当前类型的变量
3)在当前类定义一个公共的静态功能,返回值是该类本身
判断当前变量是否为空,
若为null,直接创建该类对象
返回该类实例
懒汉式:可能会出现问题的单例模式
1)延迟加载
2)线程的安全问题
解决线程安全问题:
使用同步代码块将多条对共享数据的操作包裹起来
!
抽象的动物类:Animal
子类:Cat/Dog ----- 有自己的工厂类
弊端
//新的类型:Pig 类继承自Animal(抽象类)
—需要提供当前类的工厂类:PigFactory: 代码量增加了
#### 14.3单例模式:
```java
单例模式:
保证 在内存中始终只有一个该类对象,该类对象的创建时自动创建!
具体分为:
饿汉式
懒汉式
饿汉式:是不会出现任何安全问题的单例模式!
1)创建一个类,这个类成员位置:定义静态实例变量:创建该类对象
2)无参构造方法私有化
3)提供对外的公共静态功能:获取该类对象
代表:
java.lang.Runtime:表示与Java应用程序相关的运行环境!
获取/执行相关的系统软件/查看系统变量...
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
14.4单例模式之懒汉式
单例模式之懒汉式
当前类中
1)构造方法私有化
2)在成员位置,并不是一开始就直接创建该类实例
而是声明当前类型的变量
3)在当前类定义一个公共的静态功能,返回值是该类本身
判断当前变量是否为空,
若为null,直接创建该类对象
返回该类实例
懒汉式:可能会出现问题的单例模式
1)延迟加载
2)线程的安全问题
解决线程安全问题:
使用同步代码块将多条对共享数据的操作包裹起来