你好
单例模式1,饿汉式
package logan.com.singleton; public class Car { private static Car car = new Car(); private Car(){ System.out.println("Car的私有构造函数!"); } public static Car getCar(){ System.out.println("调用静态方法返回实例"); return car; } }
主函数
package logan.com.singleton; public class Main { public static void main(String[] args) { System.out.println("--------开始测试单例模式--------------"); System.out.println("第一次获取实例"); /**Car.getCar()时会先静态获取一个Car,然后调用getCar()方法**/ Car BMW = Car.getCar(); System.out.println("第二次获取实例"); /**第二次时,因为已经有一个静态的Car实例,所以不会调用构造方法**/ Car Audi = Car.getCar(); System.out.println("两次获取的车是否相同?"+(BMW==Audi)); System.out.println("--------结束测试单例模式--------------"); } }
测试结果:
--------开始测试单例模式-------------- 第一次获取实例 Car的私有构造函数! 调用静态方法返回实例 第二次获取实例 调用静态方法返回实例 两次获取的车是否相同?true --------结束测试单例模式--------------
单例模式2,懒汉式:
package logan.com.singleton; public class City { private static City city = null; private City(){ System.out.println("调用构造方法"); } public static City getCity(){ System.out.println("调用单例模式获取实例"); if(city == null){ System.out.println("单例实例未创建,创建单例"); city = new City(); } return city; } }
主函数:
package logan.com.singleton; public class Main { public static void main(String[] args) { System.out.println("--------开始测试单例模式--------------"); System.out.println("第一次获取实例"); City Shanghai = City.getCity(); System.out.println("第二次获取实例"); City Guangzhou = City.getCity(); System.out.println("两次获取的城市是否相同?"+(Shanghai==Guangzhou)); System.out.println("--------结束测试单例模式--------------"); } }
测试结果:
--------开始测试单例模式-------------- 第一次获取实例 调用单例模式获取实例 单例实例未创建,创建单例 调用构造方法 第二次获取实例 调用单例模式获取实例 两次获取的城市是否相同?true --------结束测试单例模式--------------
可以看到懒汉式在多线程中会出现问题,当多个线程过来都判断city为null,就会创建多个city实例。饿汉式就不会有这样的问题,因为第一次过来就会创建一个静态实例。
下面对懒汉式进行改进:
package logan.com.singleton; public class Shoe { private static Shoe shoe = null; private Shoe(){ System.out.println("调用单例的构造方法"); } public static Shoe getShoe(){ System.out.println("调用单例模式获取实例"); synchronized (Shoe.class) { if(shoe!=null){ System.out.println("单例已经存在,直接返回"); return shoe; } System.out.println("单例未创建,创建单例"); shoe = new Shoe(); return shoe; } } }
主函数:
package logan.com.singleton; public class Main { public static void main(String[] args) { System.out.println("--------开始测试单例模式--------------"); System.out.println("第一次获取实例"); Shoe XTEP = Shoe.getShoe(); System.out.println("第二次获取实例"); Shoe ERKE = Shoe.getShoe(); System.out.println("两次获取的鞋子是否相同?"+(XTEP==ERKE)); System.out.println("--------结束测试单例模式--------------"); } }
测试结果:
--------开始测试单例模式-------------- 第一次获取实例 调用单例模式获取实例 单例未创建,创建单例 调用单例的构造方法 第二次获取实例 调用单例模式获取实例 单例已经存在,直接返回 两次获取的鞋子是否相同?true --------结束测试单例模式--------------
内部类只有使用的时候才加载。
1.JVM隐含的同步有哪些?
静态初始化器(在静态字段上或static{}静态代码块的初始化器)初始化数据时
访问final字段时
在创建线程之前创建对象时
线程可以看见它将要处理的对象时
2.什么是类级内部类?
有static修饰的成员式内部类。没有static修饰的成员式内部类叫对象级内部类。
类级内部类相当于其外部类的static成分,他的对象与外部类对象间不存在依赖关系,因此可直接创建,而对象级内部类的实例,是绑定在外部对象实例中的。
类级内部类中,可以定义静态的方法。在静态的方法中只能够引用外部类的中的静态成员方法或者成员变量
类级内部类相当于其外部类的成员,只有在第一次被使用的时候才会被装载
使用内部类对这个懒汉式再进行优化:
package logan.com.singleton; public class Computer { private static class ARM { private static Computer computer; static{ System.out.println("内部类被加载"); computer = new Computer(); } private ARM(){ System.out.println("调用内部类构造函数"); } } private Computer(){ System.out.println("调用构造函数"); } public static Computer getComputer(){ System.out.println("调用方法返回实例"); Computer computer; System.out.println("------分隔符-------"); computer = ARM.computer; System.out.println("返回实例"); return computer; } }
主函数:
package logan.com.singleton; public class Main { public static void main(String[] args) { System.out.println("--------开始测试单例模式--------------"); System.out.println("第一次获取实例"); Computer Acer = Computer.getComputer(); System.out.println("第二次获取实例"); Computer DELL = Computer.getComputer(); System.out.println("两次获取的电脑是否相同?"+(Acer==DELL)); System.out.println("--------结束测试单例模式--------------"); } }
测试结果:
--------开始测试单例模式-------------- 第一次获取实例 调用方法返回实例 ------分隔符------- 内部类被加载 调用构造函数 返回实例 第二次获取实例 调用方法返回实例 ------分隔符------- 返回实例 两次获取的电脑是否相同?true --------结束测试单例模式--------------