美文网首页
Java 中为什么枚举类只能有私有构造函数?

Java 中为什么枚举类只能有私有构造函数?

作者: flyjar | 来源:发表于2023-03-05 15:01 被阅读0次

1、先说一下枚举类型的前世今生,为什么会有枚举呢?

单例设计模式:在一些系统中,有的类被规定只能提供一个实例化对象,这时就可以使用单例设计模式。这时就可以将构造方法私有化进行封装使得在类的外部无法实例化新的对象,而在类的内部进行实例化对象的创建,并且提供共有的getInstance方法返回固定的实例化对象。类的这种设计模式就称为单例设计模式。单例设计模式分为饿汉式和懒汉式。

  • 饿汉式单例设计模式,在类中定义成员属性时直接进行了对象的实例化:
public class SingleObject {
    private final String name = "阿里云";
    private static final SingleObject SINGLE = new SingleObject();//只产生一份实例化对象
    private SingleObject() {}   //构造方法私有化,再类的外部无法new新对象
 
    /**
     * 获取本地实例化对象,使用static修饰不收实例化对象的限制
     * @return  SINGLE内部实例化对象
     */
    public static SingleObject getInstance() {
        return SINGLE;  //返回单一对象SINGLE
    }
    @Override
    public String toString() {
        return name;
    }
}
public class SingleObjectTestDrive {
    public static void main(String[] args) {
        SingleObject singleObject = SingleObject.getInstance();
        System.out.println(singleObject);
    }
}
  • 懒汉式单例设计模式,在第一次使用类的时候在进行对象的实例化:
private static final SingleObject INSTANCE;
......
public SingleObject getInstance() {
    if(INSTANCE == null) {
        INSTANCE = new SingleObject;
    }
    return INSTANCE;
}

多例设计模式:类似于单例设计模式在一个系统中,有的类可能需要固定个数的特定的实例化对象,如四季,只有春夏秋冬,这个时候就应当限制对象的实例化,而不是由用户随意的实例化对象。这是就可以使用多例设计模式在类的内部提供好实例化对象后进行类的封装,然后提供给用户固定的实例化对象。

多例设置模式的实例:

public class Season {
    private String season;
    private String desc;
    public static final Season SPRING = new Season("春天","温暖");
    public static final Season SUMMER = new Season("夏天","炎热");
    public static final Season AUTUMN = new Season("秋天","凉爽");
    public static final Season WINTER = new Season("春天","寒冷");
    private Season(String season,String desc) {//构造方法私有化,在类的外部无法进行对象的实例化
        this.season = season;
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Season{" +
                "season='" + season + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

2、枚举
为了解决单例设计模式和多利设计模式的缺陷问题,自JDK1.5之后,Java提供了通过enum关键字定义的枚举结构,对多例设计模式进行简化。
使用enum关键字定义枚举类时的注意事项:

  • 枚举对象以及属性必须放在枚举类内容的首部定义
  • 枚举对象的命建议采用大写,多个单词采用'_'连接,如INT_MAX
  • 枚举对象的创建需要对应相应的构造器
  • 当枚举类型为无参时,可以省去实参列表和括号的书写
  • 每一个枚举类型都默认为public static final类型,所有可以直接通过类名.属性访问枚举对象
  • 使用enum关键字定义的枚举类默认继承自Enum父类,且被final关键字修饰
  • 由于继承自父类且被关键字final修饰,由Java中的单继承机制和final关键字的作用可以知道enum定义的枚举类不能再继承其他类同时不能被子类继承。但是eunm关键字定义的枚举类可以用于实现接口

使用枚举实现多例设计模式中的类体:

public enum Season {
   //枚举对象必须定义在枚举类的行首
   SPRING("春天","温暖"),//这里相当于将public static final Season season = new Season("春天","温暖")进行了简写
   SUMMER("夏天","炎热"),
   AUTUMN("秋天","凉爽"),
   WINTER("冬天","寒冷");
   private String season;    //描述季节的属性
   private String desc;       //描述季节的特征的属性
   //提供对应枚举类定义的构造方法
   private Season(String season,String desc) {
       this.season = season;
       this.desc = desc;
   }
   @Override   //覆写父类中的toString方法
   public String toString() {
       return "Season{" +
               "season='" + season + '\'' +
               ", desc='" + desc + '\'' +
               '}';
   }
}
class TestsMain() {
   public static void main(String[] args) {
       Season spr = Season.SPRING;
       System.out.println(spr);//输出:Season{season='春天', desc='温暖'}
       System.out.println(Arrays.toStirng(Season.values()));//values方法返回所有的枚举对象,于一个Season[]数组中
   }
}

对于通过enum关键字定义的枚举类默认继承自Enum类可以通过反编译进行证明:

对上述的Seaon枚举类进行反编译:

26a949c0e3c14e37a7c44a8521817ece.png

Enum类
使用enum关键字定义的枚举类,是默认被final关键字修饰并且继承自Enum父类的,观察Enum父类,可以知道通过在enum关键字定义的枚举类中的枚举对象的名称存在于Enum父类的name属性中的:

cd6ab52eb31b4a48b2a57aed87ae50ea.png

Enum父类中提供了很多操作枚举对象的方法:

  • toString()
    在Enum类中的toString()已经覆写自Object父类,用于输出当前枚举对象的名称;使用enum关键字定义的枚举子类可以对该方法进行重写,用于输出子类对象的属性信息:
@Override   //覆写父类中的toString方法,用于输出当前枚举对象的信息
    public String toString() {
        return "Season{" +
                "season='" + season + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
  • name()

返回当前的枚举对象名称。该方法在父类中通过final关键字修饰,子类中不能进行覆写。

//创建了一个枚举类Season,四个枚举对象SPRING,SUMMER,AUTUMN,WINTER
Season spring = Season.SPRING;
System.out.println(spring.name());//调用当前枚举对象的name方法,输出SPRING
  • ordinal()
    返回当前枚举对象在枚举体系中的位置号,枚举体系位置号默认从0开始
//创建了一个枚举类Season,四个枚举对象SPRING,SUMMER,AUTUMN,WINTER
for (Season temp : Season.values()) {    //for each遍历Season类型的枚举对象
   System.out.println(temp.ordinal());   //输出每一个枚举对象的编号
}
//输出:0 1 2 3
  • values()
    返回当前枚举类中的所有枚举对象组成的一个枚举类型的数组。
//创建了一个枚举类Season,四个枚举对象SPRING,SUMMER,AUTUMN,WINTER
System.out.println(Arrays.toString(Season.values()));
//输出:[Season{season='春天', desc='温暖'}, Season{season='夏天', desc='炎热'}, Season{season='秋天', desc='凉爽'}, Season{season='冬天', desc='寒冷'}]
  • valueOf()
    静态方法,将一个字符串转换为枚举对象,返回该枚举对象供后续使用。要求字符串必须为已有常量名,否则将抛出
//创建了一个枚举类Season,四个枚举对象SPRING,SUMMER,AUTUMN,WINTER
System.out.println(Season.valueOf("SUMMER").ordinal());
//输出:1
  • compareTo()
    观察Enum类可以发现该类实现了Comparable接口,所以可以进行枚举对象之间的比较,两个枚举之间比较的是两个枚举常量的位置号,返回调用该方法的枚举常量的位置号和进行比较的枚举常量的位置号的差值。
//创建了一个枚举类Season,四个枚举对象SPRING,SUMMER,AUTUMN,WINTER
System.out.println(Season.AUTUMN.compareTo(Season.SPRING));
//输出:2

总结

  • JDK自1.5之后推出了枚举结构,用来简化多例设计模式的缺陷。在枚举类中对构造方法私有化,可以防止在类的外部进行对象的实例化
  • 枚举对象的定义必须放在枚举类的首行
  • 枚举类中的枚举对象默认被public static final修饰,枚举对象的名称存在于父类Enum的name属性中。
  • 因为通过enum关键字定义的枚举类默认继承自Enum父类,由于Java的单继承机制,所以enum关键字定义的枚举类不能再继承其他类。同时该枚举类默认被final关键字修饰,所以不能被子类继承,但是可以实现接口。
  • 在枚举类内进行枚举对象的定义是,要有相关属性的设置,同时应提供相应类型的构造方法
  • 如果枚举对象没有属性值,通过无参构造器创建对象时,实参列表和小括号可以省略
  • Java 中的枚举包含固定的常量值。因此,没有理由使用公共或受保护的构造函数,因为您无法创建枚举实例。此外,请注意,内部枚举被转换为类。由于我们不能显式创建枚举对象,因此我们不能直接调用枚举构造函数。

相关文章

  • Dart 中的单例模式

    单例类: 调用: TIPS : java 中的单例是需要将构造函数定义为私有,在dart中不提供默认构造函数,这一...

  • 枚举

    从JDK 5开始,枚举被添加到Java语言中。在Java中,枚举被定义为类,可以具有构造函数,方法以及实例变量。 ...

  • 2020-03-30 自定义枚举和异常问题

    自定义枚举类问题 对于枚举常量的定义,枚举类中的私有变量(对应关系),一般对于私有变量只有get方法,此外就是构造...

  • Dart中的类——初始化列表、命名构造器、factory构造器、

    Dart中的类——初始化列表、命名构造器、factory构造器、常量构造器、构造器私有化、get和set方法、枚举...

  • C# 构造函数总结

    构造函数 构造函数分为:实例构造函数,静态构造函数,私有构造函数。 实例构造函数 1、构造函数的名字与类名相同。 ...

  • Kotlin面向对象 (6)枚举类

    枚举类构造函数枚举常用属性和函数 kotlin 中使用 enum 和 class 两个关键词声明枚举类。 枚举类使...

  • 【Dart】Dart类与对象

    类与对象 类 继承 抽象类 接口 混入 泛型 枚举类类-简介 构造器 (构造函数) 默认构造函数与类同名的函数,在...

  • 枚举

    定义枚举类 可以在枚举中定义普通方法和抽象方法. 也同样可在枚举类中定义属性,构造方法. 实现原理 Java文件在...

  • 枚举使用笔记

    1、遍历枚举、枚举在switch case中的使用 首先创建一个常用格式的枚举类。如下,注意枚举类的构造函数不能是...

  • C++学习心得

    私有构造函数类的特点 不能实例化,因为实例化时类外部无法访问类的私有构造函数; 不能被继承,因为派生类无法调用类的...

网友评论

      本文标题:Java 中为什么枚举类只能有私有构造函数?

      本文链接:https://www.haomeiwen.com/subject/ifnuldtx.html