设计模式
1.单例模式的实现方法:
(1)饿汉模式:不管是否使用到该类,都先初始化该类,有可能会造成资源浪费! 线程安全,调用效率高,但是不能延时加载 !
public class Singleton{
//类初始化时,立即加载该对象(没有延时加载的优势)!由于加载类时,天然的线程安全!
private static Singleton instance=new Singleton();
//私有构造器
private Singleton(){
}
public static Singleton getInstance{
return instance;
}
}
(2)懒汉模式:
方式1:
这种写法只能在单线程下使用。如果是多线程,可能发生一个线程通过并进入了 if (singleton == null) 判断语句块,但还未来得及创建新的实例时,另一个线程也通过了这个判断语句,两个线程最终都进行了创建,导致多个实例的产生。所以在多线程环境下必须摒弃此方式。
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
方法2:线程安全,调用效率不高,并且可以延时加载
通过为 getInstence() 方法增加 synchronized 关键字,迫使每个线程在进入这个方法前,要先等候别的线程离开该方法,即不会有两个线程可以同时进入此方法执行 new Singleton(),从而保证了单例的有效。但它的致命缺陷是效率太低了,每个线程每次执行 getInstance() 方法获取类的实例时,都会进行同步。而事实上实例创建完成后,同步就变为不必要的开销了,这样做在高并发下必然会拖垮性能。所以此方法虽然可行但也不推荐。
public class Signalton{
private static Signalton instance;
private Signalton(){
}
public syschronized static getInstance(){
if(instance==null)
instance=new Signalton();
return instance;
}
}
方法3:双重检查锁式:由于JVM底层内部模型原因,偶尔会出问题,不建议使用
public class Signalton{
private static Signalton instance;
private Signalton(){
}
public static Signalton getInstance(){
if(instance==null)
synchronized(Signalton.class){
instance=new Signalton();
}
return instance;
}
}
方法4:静态内部类:线程安全,调用效率高,并且可以延时加载。推荐使用
这种方式是Singleton 类被装载了,instance不一定被初始化。因为SingletonClassGetInstance 类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonClassGetInstance 类,从而实例化instance。
public class Signalton{
//静态内部类
private static class SingletonClassGetInstance{
public static final Signalton instance = new Signalton();
}
// 私有构造器
private Signalton() {
}
public static Signalton getInstance() {
return SingletonClassGetInstance.instance;
}
}
方法5:枚举:线程安全,调用效率高,不能延时加载,但是可以天然的防止反射和反序列化漏洞
这种模式下,线程安全,调用效率高,但是不能延时加载!实际工作中,少有人使用这种方式!
public Enum Signalton{
//这个枚举对象本身就是单例对象
INSTANCE;
//添加自己需要的操作
public void operation(){
}
}
注:单例模式中的存在的问题:如果单例类实现了java.io.Serializable接口,那么这个类可能会被反序列化,并且反序列化多次同一对象时,会得到多个单例类的实例。这样就不是单例了!
枚举单例是如何被保证的:
- 首先,在枚举中我们明确了构造方法限制为私有,在我们访问枚举实例时会执行构造方法。
- 同时每个枚举实例都是 static final 类型的,也就表明只能被实例化一次。
2.工厂设计模式
反射
1.什么是反射?类的反射的安全问题
java特性
1.封装的基本原理
2.多态?多态的好处?
数据内存分配
1.int a=5,a=10,a=15;在内存中产生的数据?
一个。
2.a="Hello";a+="world";a=+"!";产生几个对象?
String 是final,共产生三个对象。
3.String内存分配
- String常量池:存放string对象实例
- 对于String s=“hhh”,首先去常量池中查看是否有string对象的值为“hhh”的实例,如果有直接将s指向该常量池中的对象实例;如果没有,在常量池中创建值为“hhh”的对象实例,并使s指向它。
- 对于String s=new String(“hhh”),首先去常量池中查看是否有string对象的值为“hhh”的实例,如果没有,在常量池中创建值为“hhh”的对象实例;如果有对常量池不做任何操作。然后也在堆中创建一个值为“hhh”的对象实例,并使s指向堆中的实例。
4.基本类型的内存分配以及基本类型的包装类的内存分配
基本类型和基本类型的包装类。基本类型有:byte、short、char、int、long、boolean。基本类型的包装类分别是:Byte、Short、Character、Integer、Long、Boolean。注意区分大小写。二者的区别是:基本类型体现在程序中是普通变量,基本类型的包装类是类,体现在程序中是引用变量。因此二者在内存中的存储位置不同:基本类型存储在栈中,而基本类型包装类存储在堆中。上边提到的这些包装类都实现了常量池技术,另外两种浮点数类型的包装类则没有实现。
- 对于Integer包装类,维护一个常量池
- 当使用Integer a=1时,首先
stringbuffer和stringbuild
Java的值传递和引用传递
java中只有值传递。
参考:https://juejin.im/post/5bce68226fb9a05ce46a0476