static
那天我朋友问了我个问题,static和单例模式有什么区别,所以我觉得static可以讲一下
他的问题是,把对象弄成static是不是就不变了
显然,这是还没弄清楚引用和对象的区别
其实存放在静态区中的是引用,而不是对象。而对象是存放在堆中的。如果有这样一句话
public static final Book book = new Book();
意思就是book这个引用,指向了这个new出来的对象。
static的引用和正常的引用有什么区别?
当你加载了这个类的时候(第一次使用这个类的时候会加载这个类到jvm),这个static引用会率先被加载。所以,当我们第一次调用Book.book的时候,这个静态的book引用就会一直存放在静态区里了(当fullGC回收整个类才会销毁这个引用)。
而正常的引用,只能通过new出一个对象后才能使用,所以当对象被回收了,这个引用自然也回收了(而且非静态引用如果是方法中的引用,会存放在函数的栈里;如果是对象的引用,会和对象一起存放在heap里)。
final
final定义了之后,你就必须在一开始就需要赋值,所以上面那行代码就必须在一开始就赋值。而如果你想延迟加载,提高性能,那么就不可以用final。
单例模式
单例模式是如果实现的,就是通过调用这个类里的一个静态方法,弄一个if语句判断一下,如果有实例了,就返回这个实例,如果没有,就创建这个实例。其实并没有多大的技术含量。
第一种,最基本的思维。
public class Book { private static Book book = new Book(); private Book() {} public static Book getInstance() { if (book == null) { book = new Book(); } return book; } }
这里为什么要判空呢?因为你这个是静态的,所以其他地方完全有Book.getInstance = null;的可能。
第二种,这里使用final,让引用的指向不可变,这样就不需要判空了
public class Book { private static final Book book = new Book(); private Book() {} public static Book getInstance() { return book; } }
第三种,延迟加载(线程不安全,假如有多个同时发现是空的,会创建出好多实例)
public class Book { private static Book book; private Book() {} public static Book getInstance() { if (book == null) { book = new Book(); } return book; } }
第四种,添加线程安全功能,加一个关键字就可以
public class Book { private static Book book; private Book() {} public static synchronized Book getInstance() { if (book == null) { book = new Book(); } return book; } }
这个方法在多线程下的工作表现很出色
第五种,规避不需要的同步,因为上面的同步范围太大,有点浪费性能,在引用有指向的时候,是不需要同步的
public class Book { private static Book book; private Book() {} public static synchronized Book getInstance() { if (book == null) { synchronized (Book.class) { book = new Book(); } } return book; } }
第六种,静态内部类
public class Book { private Book() {} public static synchronized Book getInstance() { return BookHolder.book; } private static class BookHolder { private static final Book book = new Book(); } }
第七种,枚举单例
public class Book { private Book(){} public static Book getInstance() { return BookEnum.BOOK.getInstance(); } private static enum BookEnum { BOOK; private Book book; private BookEnum() { book = new Book(); } public Book getInstance() { return book; } } }
最优,但是枚举这个东西可读性不高