单例设计模式、多例设计模式和枚举类型
一、单例设计模式
1.含义
一个类只能产生一个实例对象。
2.饿汉式实现方法
特点:不管是否使用单例对象,只要该类加载了,那么一定会自动创建一个公共的instance对象。
package com.xunpu.singleAndMulti;
//饿汉式
class Singleton1{
//1.属性静态化、不可修改化
// static :解决必须先创建对象后才可以为属性分配空间的问题
//final :只能有一个实例化对象
private final static Singleton1 instance=new Singleton1();
//2.构造方法私有化,避免外界创建多个对象。
private Singleton1(){
}
//2.获取对象用static修饰,静态方法,便于在不产生对象时调用。
public static Singleton1 getInstance(){
return instance;
}
}
public class Singleton {
public static void main(String[] args) {
Singleton1 singleton1=Singleton1.getInstance();
Singleton1 singleton2=Singleton1.getInstance();
System.out.println(singleton1==singleton2);
}
}
结果为true,说明这两个对象指向同一块内存空间,单例实现。
3.懒汉式实现方法
特点:当第一次使用Singleton对象的时候才会为其产生实例化对象的操作。
package com.xunpu.singleAndMulti;
//懒汉式
class Singleton2{
//1.属性静态化,便于后面的获取单例对象的调用。
private static Singleton2 instance = null;
//2.构造方法私有化
private Singleton2(){
}
//3.获取实例化对象方法静态化,便于再不产生对象的情况下调用。
public static Singleton2 getInstance() {
if (instance == null) {//此时还没有实例化
instance = new Singleton2();
}
return instance;
}
}
public class Singleton {
public static void main(String[] args) {
Singleton2 singleton1=Singleton2.getInstance();
Singleton2 singleton2=Singleton2.getInstance();
System.out.println(singleton1==singleton2);
}
}
懒汉式会存在线程安全问题,而饿汉式不会存在。
改进的懒汉式(线程安全):
//3.懒汉式双重检查
class Singleton3{
private static volatile Singleton3 instance;
private Singleton3(){
}
public static Singleton3 getInstance(){
if(instance==null){
synchronized (Singleton3.class){
if(instance==null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
懒汉式(双重检查):
/**
* 懒汉式(双重检查)
*/
public class Singleton {
private volatile static Singleton instance;//使用volaitle修饰,防止指令重排,对象一定是属性全部初始化后的对象。保证可见性。
//构造方法私有化
private Singleton(){
}
//外界调用静态方法实例化对象
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null){//再次判断是为了防止在此期间,其它线程已经创建好了对象。
instance=new Singleton();
}
}
}
return instance;
}
}
有关单例的更好分析请参见:手写单例,不心慌。
二、多例设计模式
要描述一周的类,只有七个对象;要描述性别,只有两个对象。这些都是多例设计模式。多例只是比单例追加了更多个实例化对象而已。其实,多例就是多个单例对象。
package com.xunpu.singleAndMulti;
class Sex{
private String str;
//属性被final static修饰
private final static int MALE=1;
private final static int FEMALE=2;
private final static Sex male=new Sex("男");
private final static Sex female=new Sex("女");
//构造方法私有化
private Sex(String str){
this.str=str;
}
//取得对象方法用static修饰
public static Sex getInstance(int flag){
switch (flag){
case 1:
return male;
case 2:
return female;
default:
return null;
}
}
}
public class MultiTest {
public static void main(String[] args) {
Sex male=Sex.getInstance(1);
Sex male2=Sex.getInstance(1);
Sex female1=Sex.getInstance(2);
Sex female2=Sex.getInstance(2);
System.out.println(male==male2);
System.out.println(female1==female2);
}
}
多例设计模式现在已经被枚举所代替。
三、枚举类型(JDK1.5开始)
1.特点
它的实例个数是有限的,而且这些实例是枚举类的静态常量。
2.枚举类型的定义和方法
定义:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable
这说明Enum类是抽象类,<E extends Enum<E>>为泛型标记,表示Enum类拥有的静态变量也是Enum类型或者其子类型。
方法:
构造方法:
protected Enum(String name, int ordinal)
其它方法:
public final String name();//返回当前枚举类型的名称
public final int ordinal();//返回当前枚举常量的序数
public final int compareTo(E o);//比较当前枚举常量与指定对象的顺序。
public final Class<E> getDeclaringClass();//返回表示当前枚举常量的枚举类型的Class对象
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name);//根据指定的枚举类型和名称返回相应的枚举常量实例。
public static Enum[] values();//以数组的形式返回该枚举类型的所有枚举常量实例。
3.自定义枚举类型
用户定义的枚举类只需要继承Enum类就行了。
//方式一:直接继承Enum类
public class Gender extends Enum{
public static final Gender FEMALE;
public static final Gender MALE;
......
}
//方式二:使用enum类型(简单)
public enum Gender{FEMALE,MALE}
package com.xupu;
public class GenderTest {
//在内部定义Gender枚举类
enum Gender{
FEMALE,
MALE
}
public static void main(String[] args) {
//遍历Gender类的所有常量
for(Gender g:Gender.values()){
System.out.println(g.ordinal()+" "+g.name());
}
Gender g=Gender.FEMALE;
switch (g){
case FEMALE:
System.out.println("女");
break;
case MALE:
System.out.println("男");
break;
default:
System.out.println("未知的性别");
}
}
}
由此可知,枚举类型默认从0开始。
4.自定义构造方法
在自定义的枚举类中也可以自定义构造方法和属性,这个方法必须是private修饰的。
package com.xupu;
public class GenderTest {
//在内部定义Gender枚举类
enum Gender{
FEMALE("女性"),
MALE("男性");
private String des;
//构造方法私有化
private Gender(String des){
this.des=des;
}
public String getDes(){
return des;
}
}
public static void main(String[] args) {
//遍历Gender类的所有常量
for(Gender g:Gender.values()){
System.out.println(g.ordinal()+" "+g.name()+" "+g.getDes());
}
Gender g=Gender.FEMALE;
System.out.println(g.getDes());
}
}
FEMALE和MALE这两个常量通过Gender(String des)构造方法来创建。
在枚举类中声明多个枚举常量时,常量之间用","隔开,最后一个常量用";"结尾。
5.EnumSet类和EnumMap类
在Java API中,还为Enum类提供了两个适配器:
java.util.EnumSet类:把枚举类型转换为集合类型。它的静态的allOf()能把枚举类的所有常量实例存放在一个EnumSet集合中,然后返回这个集合。
java.util.EnumMap类:把枚举类型转换为映射类型。它的EnumMap(Class<K> keyType)构造方法用来指定具体的枚举类型。枚举常量以key的形式存放在map中。
下面是使用:
需求:定义一个表示不同颜色的枚举类,现在要求把枚举类对应的常量和颜色打印出来。
思路:使用EnumMap,将常量和颜色放入map中;然后将map再转化为set集合,集合中的元素变为键值对对象,然后通过获取key和value打印出结果。
package com.xupu.testinnerclass;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
public class ColorTest {
//表示颜色的枚举类
enum Color{
RED,
GREEN,
BLUE,
YELLOW,
PINK
}
public static void main(String[] args) {
EnumMap<Color,String> colormap=new EnumMap<Color, String>(Color.class);
colormap.put(Color.RED,"红色");
colormap.put(Color.GREEN,"绿色");
colormap.put(Color.BLUE,"蓝色");
colormap.put(Color.YELLOW,"黄色");
colormap.put(Color.PINK,"粉色");
Set<Map.Entry<Color,String>> set=colormap.entrySet();
for(Map.Entry entry:set){
System.out.println(entry.getKey()+"="+entry.getValue());
}
}
}
上一篇: iOS面试题-Swift篇