类与方法的常见概念:重载、重写、多态、抽象类、接口、final、static、权限修饰符、枚举类

类与方法的常见概念

重载@Overload

为什么要有重载

摄像这样一个场景,如有有公司做活动,如果你能集齐一块石头,会给你10积分,如果你集齐一把剪刀,给你20积分,集齐了一把剪刀一块石头,给你100积分。只有这三种场景,集齐不同物件的人要去不同的地方领奖,那我们可以不可以让大家去同一个地方领奖呢。方法就是重载。

重载的实现

package com.daylywork.study.NewLearn;
/**
 *假设String 代表石头,int代表剪刀
 */
public class LingJiangTai {
    public int getMyJiangPin(String string,Integer integer){
        System.out.println(string+integer.toString());
        return 100;
    }
    public int getMyJiangPin(String s){
        System.out.println(s);
        return 10;
    }
    public int getMyJiangPin(Integer i){
        System.out.println(i.toString());
        return 20;
    }

    public static void main(String[] args) {
        LingJiangTai lingJiangTai=new LingJiangTai();
        /**
         * 我有石头和剪刀,我要获取奖品
         * */
        lingJiangTai.getMyJiangPin("hello",2);
        /**
         * 我只有石头,我要领取奖品
         * */
        lingJiangTai.getMyJiangPin("hello");
        /**
         * 我只有剪刀,我要领取奖品
         * */
        lingJiangTai.getMyJiangPin(2);
        /**
         * 这样的话是不是说我只要记住getMyJiangPin这一个方法就行了,不管你带什么来我都能给你兑换奖品,而不用带着
         * 不同的物件去不同的地方兑换奖品,在代码里就是不用设计很多不同命的方法,既方便了自己,又方便了调用我们的人。
         * */
    }
}

重载的要求

1、方法名一定要相同

2、各自的参数不一样(可以个数不同,可以参数一样但是顺序不同,可以参数不同)

3、返回值类型应该是一样的

重写-@Override

为什么要有重写

比如说我有一个QA的类,表达测试人员,有一个自我介绍的方法,你传给我名字,我输出一段自我介绍文案,并再次把名字return返回出去,那这个时候来了一个性能测试继承了QA类,他想要自我介绍的时候特意强调自己是性能测试人员,怎么办,我们需要再给他写一个自我介绍的方法吗?不要吧,那以后想要自我介绍的时候,岂不是新来一个测试分类人员就要新建一个方法,好麻烦,那我们就需要重写父类的方法。

重写的实现

首先定义父类QA

package com.daylywork.study.NewLearn;

public class MyQA {
    public String forMe(String name){
        System.out.println("我是一个测试,名字是:"+name);
        return name;
    }
    public void jiNeng(){

    }
}

再来定义一个子类性能测试

package com.daylywork.study.NewLearn;

public class XingNengCeShi extends MyQA{
    @Override
    public String forMe(String name){
        System.out.println("我是一个性能测试,名字是:"+name);
        return name;
    }
}

重写在要求

1、返回值要相同,父类是String子类也要是String类型

2、入参要相同,父类是String,子类也要是String,如果有多个如惨,顺序也要相同才可以。

3、方法名相同

@Override的作用

你也可以不写,只不过写了之后会自动帮你校验子类重写的方法是不是符合要求,而且别人看起来也知道是你重写的父类的方法,推荐写

重载和重写的不同

1、发生的位置不一样,重载是发生在同一个类里的,而重写是发生在子类和父类中

2、发生的时机不一样,重载是在编译的时候,重写是运行时候的

3、参数的不通,重载必须参数不一样,重写必须一样

多态

package com.daylywork.study.NewLearn;

public class QAOrXingNeng {
    public static void getWho(MyQA myQA){
        myQA.forMe("猜猜我是谁");
    }
}

上面这种方法getWho,参数是一个MyQA,我们不知道到时候调用是传入父类还是子类,也就是在执行之前我们是不知道结果是什么的,只有执行的时候才知道

package com.daylywork.study.NewLearn;

public class QAOrXingNeng {
    public static void getWho(MyQA myQA){
        myQA.forMe("猜猜我是谁");
    }

    public static void main(String[] args) {
        MyQA myQA=new MyQA();
        MyQA myQA1=new XingNengCeShi();
        getWho(myQA);
        getWho(myQA1);
    }
}

结果

我是一个测试,名字是:猜猜我是谁
我是一个性能测试,名字是:猜猜我是谁

引申出多态的定义

多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法

⚠️:多态的特性就是,运行期才能动态决定调用的子类方法

抽象类

为什么要有抽象类

我们已经知道子类可以继承父类,而且拥有父类所有的方法,但是比如说有一种方法,例如自我介绍,每一个子类都想拥有自己独特的自我介绍的方式,那在父类里实现这个方法其实就很没必要,对不对。

抽象类的实现

如果我这样写

package com.daylywork.study.NewLearn;

public class MyChouXiang {
    public void getFind();
}

是会报错,无法通过编译的,必须写上{}写它的实现内容,哪怕时空的,但是我不想实现他啊,怎么办,加一个abstract

package com.daylywork.study.NewLearn;

public  class MyChouXiang {
    public abstract void getFind();
}

但是,现在还是会报错,为什么,因为你有一个未实现的方法,那你就没办法实例化这个类,也就是不能new出一个对象来,因为你的方法有不能用的啊,你有一个抽象方法,那你这个类就是抽象类了,必须在类上也新增abstract关键字才可以

package com.daylywork.study.NewLearn;

public abstract class MyChouXiang {
    public abstract void getFind();
}

这样就不会报错了。

那么问题来了,抽象类不可以实例化,那还有谁很么用!答案是它只可以被用来被继承。子类必须实现它的抽象方法才可以。相当于给子类做了一系列的规范,你必须有什么功能。

抽象类的继承

那抽象类该如何继承呢

一、在子类中实现父类的抽象方法
package com.daylywork.study.NewLearn;

public  class MyChouXiangTwo extends MyChouXiang{
    public void getNew(){
        System.out.println("hello");
    }
    @Override
    public void getFind(){
        System.out.println("儿子实现了,孙子就不用麻烦了");
    }
}
二、子类不实现,但子类也必须为抽象类,交给子子类来实现,往复循环

子类

package com.daylywork.study.NewLearn;

public abstract class MyChouXiangTwo extends MyChouXiang{
    public void getNew(){
        System.out.println("hello");
    }
}

子子类

package com.daylywork.study.NewLearn;

public class MyChouXiangLeiThree extends MyChouXiangTwo{
    @Override
    public void getFind(){
        System.out.println("儿子不实现,孙子来实现,孙子不实现,重孙组实现,愚公移山一般");
    }
}

接口

接口的目的

比如说,我们想要创建老师对象,但是你想想,是不是老师都有教学任务,都需要查作业,那我们把这些老师共有的特性抽离出来,写成一个接口,然后每个老师去实现这个接口不就好了,这样的话每个老师的行为都是规范的,而且你还可以在某一个老师的类里定义一些独有的特性。

总结说来,接口的意义就是说你实现了我,相当于遵守了一种规范,未来新开了一门课,新的老师来了,也是要遵守查作业、教学这种约定的。

是不是和抽象类很像?对,如果一个抽象类没有字段,所有方法全部都是抽象方法:就可以把该抽象类改写为接口:interface,

接口的定义

package com.daylywork.study.NewLearn;

public interface MyTeacher {
     void teach();
     void chaZuoYe();
}

别看我们的方法是没有public abstract的,其实是系统默认为我们添加上了这两个关键字的。

接口的实现

一个类,只能继承自一个类,但是可以实现N个接口,比如说,想要统计已育女老师,那这个女老师要有什么特性呢,首先老师的特性得有吧,然后还要有妈妈的特性。所以我们再来定义一个妈妈的接口

package com.daylywork.study.NewLearn;

public interface MyMother {
    void buRu();
    void taiJiao();
}

下面我们来实现已育女老师的类

package com.daylywork.study.NewLearn;

public class MotherTeacher implements MyTeacher,MyMother{
    @Override
    public void buRu() {
        System.out.println("1");
    }

    @Override
    public void taiJiao() {
        System.out.println("2");
    }

    @Override
    public void teach() {
        System.out.println("3");
    }

    @Override
    public void chaZuoYe() {
        System.out.println("4");
    }
}

两个接口的所有方法,MotherTeacher都必须要实现

抽象类和接口的区别

1、抽象类中可以有非抽象类方法。但是接口不可以

2、接口的实现用implements,而继承抽象类使用extends

3、类当然也包括抽象类,只能继承一个,但是接口可以实现多个

final

为什么要有final

假设你想创建一个自己的类,有姓名有年龄,但是你又想永远18岁怎么办,你不想让别人来修改你的年龄,你是不是想有一个不可以变更的参数,那这个时候final就又用了。

修饰变量

final修饰基本类型变量,表示该变量只有一次赋值机会,并不是说这个变量是不能变化的,因为不能变化的并没有限制住不能再次赋值

package com.daylywork.study.NewLearn;

public class NewMe {
    public  int age;
    public String name;

    public  int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        final int age=18;
        NewMe newMe=new NewMe();
        newMe.setAge(age);
        System.out.println(newMe.getAge());
//        age=20;
//        System.out.println(newMe.getAge());
        /**
         * 上面被注释掉的两行如果不注释的话是会报错的,根本通不过编译,报错内容为
         * Cannot assign a value to final variable 'age'
         * 翻译过来就是"无法为最终变量“age”赋值"
         * */
    }
}

结果

18

修饰方法

那变量可以final,方法也可以final,修饰方法的作用就是,我这个方法不可以被重写,就好像说一个QA父类有一个自我介绍,说的是大家好,我是一个测试,别管你是性能测试、安全测试还是什么测试,都别整花里胡哨的,统统自我介绍为大家好,我是一个测试,别想重写我的自我介绍方法,想标新立异,你自己去新建一个方法去,别用爸爸的。

父类

package com.daylywork.study.NewLearn;

public class MyQA {
    public final String forMe(String name){
        System.out.println("我是一个测试,名字是:"+name);
        return name;
    }
}

子类

package com.daylywork.study.NewLearn;

public class XingNengCeShi extends MyQA{
    @Override
    public String forMe(String name){
        System.out.println("我是一个性能测试,名字是:"+name);
        return name;
    }
    /**
     * 上面这个方法是不能通过编译的,会报错
     * 'forMe(String)' cannot override 'forMe(String)' in 'com.daylywork.study.NewLearn.MyQA'; overridden method is final
     * 翻译过来就是
     * “forMe(String)”不能覆盖“com.daylywork.study.NewLearn.MyQA”中的“forMe(String)”;重写的方法是最终的
     * */
}

修饰类

final修饰类的话,就是说,我是一个大富豪,有888万亿,但我就是立了个遗嘱,谁也别想继承我的遗产,我所有的财产都在这里,我的每一笔钱(方法),你们都是没办法用的。

父类

package com.daylywork.study.NewLearn;

public final class MyQA {
    public  String forMe(String name){
        System.out.println("我是一个测试,名字是:"+name);
        return name;
    }
}

子类

静态 static

为什么要有静态

设想这样一个场景,你是一个学校的老师,你想创建一个学生类,但是学校规定,所有的孩子都必须是本省的,我们先来创建一个学生类,并创建学生的实体类

package com.daylywork.study.NewLearn;

import lombok.Data;

@Data
public class MyStudent {
    public int age;
    public String name;
    public String city;

    public static void main(String[] args) {
        MyStudent zhangsan = new MyStudent();
        zhangsan.setAge(18);
        zhangsan.setName("zhangsan");
        zhangsan.setCity("hebei");
        MyStudent lisi=new MyStudent();
        lisi.setAge(17);
        lisi.setName("lisi");
        lisi.setCity("hebei");
        MyStudent wangwu = new MyStudent();
        wangwu.setAge(16);
        wangwu.setName("wangwu");
        wangwu.setCity("hebei");
    }
}

我们发现一个问题,所有的学生的籍贯由于学校的规定,都是河北的。每创建一个实体类都需要设置一遍这个相同的city,是不是很麻烦,所以有了static这个字段。我们可以修改成这样

静态变量

package com.daylywork.study.NewLearn;

import lombok.Data;

@Data
public class MyStudent {
    public int age;
    public String name;
    public static String city;

    public static void main(String[] args) {
        /**
         * 推荐用类名来为静态字段赋值。可以把静态字段理解为描述class本身的字段(非实例字段)。
         * */
        MyStudent.city="hebei";
        MyStudent zhangsan = new MyStudent();
        zhangsan.setAge(18);
        zhangsan.setName("zhangsan");
        MyStudent lisi=new MyStudent();
        lisi.setAge(17);
        lisi.setName("lisi");
        MyStudent wangwu = new MyStudent();
        wangwu.setAge(16);
        wangwu.setName("wangwu");
        System.out.println(zhangsan.city);
        System.out.println(lisi.city);
        System.out.println(wangwu.city);
        /**
         * 上面这三种通过实例.静态参数 的取值方式不推荐,为什么
         * 因为虽然实例可以访问静态字段,但是它们指向的其实都是Person class的静态字段。所以,所有实例共享一个静态字段。
         * 因此,不推荐用实例变量.静态字段去访问静态字段,因为在Java程序中,实例对象并没有静态字段。在代码中,
         * 实例对象能访问静态字段只是因为编译器可以根据实例类型自动转换为类名.静态字段来访问静态对象。
         * 上面这么写只是为了更直观的展示出来
         * */
        System.out.println(MyStudent.city);
        /**
         *上面这种方式才是被推荐的访问静态字段的方式:类.静态变量
         * */
        zhangsan.city="henan";
        /**
         * 同样的,通过实例.静态变量的方式来为静态变量赋值,也是不被推荐的,为什么
         * 对于静态字段,无论修改哪个实例的静态字段,效果都是一样的:所有实例的静态字段都被修改了,原因是静态字段并不属于实例
         * */
        System.out.println(MyStudent.city);
        System.out.println(zhangsan.city);
        System.out.println(lisi.city);
        System.out.println(wangwu.city);
    }
}

结果

hebei
hebei
hebei
hebei
henan
henan
henan
henan

静态方法

有静态变量,也有静态方法

调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用

因为静态方法属于class而不属于实例,因此,静态方法内部,无法访问实例字段(就是不带static的参数),它只能访问静态字段。

package com.daylywork.study.NewLearn;

import lombok.Data;

@Data
public class MyStudent {
    public int age;
    public String name;
    public static String city;
    public static void setCity(String cityo){
        city=cityo;
    }

    public static void main(String[] args) {
        MyStudent.setCity("hebei");
        MyStudent zhangsan = new MyStudent();
        zhangsan.setAge(18);
        zhangsan.setName("zhangsan");
        MyStudent lisi=new MyStudent();
        lisi.setAge(17);
        lisi.setName("lisi");
        MyStudent wangwu = new MyStudent();
        wangwu.setAge(16);
        wangwu.setName("wangwu");
        System.out.println(zhangsan.city);
        System.out.println(lisi.city);
        System.out.println(wangwu.city);
        System.out.println(MyStudent.city);
    }
}

结果

hebei
hebei
hebei
hebei

静态变量在接口中的使用

因为interface是一个纯抽象类,所以它不能定义实例字段。但是,interface是可以有静态字段的,并且静态字段必须为final类型:

public interface Person {
    public static final int MALE = 1;
    public static final int FEMALE = 2;
}

实际上,因为interface的字段只能是public static final类型,所以我们可以把这些修饰符都去掉,上述代码可以简写为:

public interface Person {
    // 编译器会自动加上public statc final:
    int MALE = 1;
    int FEMALE = 2;
}

权限修饰符

如果我们写了一个类或者一个变量,我不想让别人用,或者说我只想让我的子类用,怎么办呢,就需要用到权限控制的作用域。

private

定义为private的field、method无法被其他类访问

实际上,确切地说,private访问权限被限定在class的内部,而且与方法声明顺序无关。推荐把private方法放到后面,因为public方法定义了类对外提供的功能,阅读代码的时候,应该先关注public方法

注:private是不能修饰类的

package com.packageone;

/**
 * 会在private处报错:Modifier 'private' not allowed here
 * */
private class MyPrivate {
}

为什么不能修饰类呢,private的意思是私有的,那如果一个类是私有的,别人无法访问,那这个类有什么意义呢?

但是我们可以修饰方法和变量哇

package com.packageone;

public class MyPrivate {
    public int i;
    private int j;
    private String s;
    public int getPublicI(){
        /**
         * public方法访问public参数,没问题
         * */
        i=10;
        return i;
    }
    public String getPrivateMethod(){
        /**
         * class内部的public方法访问private方法,没问题
         * */
        int f=getPrivateJ();
        return String.valueOf(f);
    }
    public String getPrivateS(){
        s="hello";
        return s;
        /**
         * public方法访问private参数,没问题
         * */
    }
    private int getPrivateJ(){
        /**
         * private方法访问private属性,没问题
         * */
        j=20;
        return j;
    }
    /**
     * 推荐把private方法放到后面,因为public方法定义了类对外提供的功能,阅读代码的时候,应该先关注public方法
     * private方法的用处主要是为了提供功能给class内部其他public方法的,舍己为人,但是只为自己人。
     * 综上所述,可以证明,private在自己的class内部是可以被访问到的,不管是什么限制的方法,但是无法证明外部不能访问。
     * */

}
package com.packageone;

public class MyPrivateTwo {
    public void getMyPrivateTwo(){
        MyPrivate myPrivate=new MyPrivate();
        System.out.println(myPrivate.getPublicI());//其他类可以访问到公共方法
        System.out.println(myPrivate.getPrivateMethod());//其他类可以访问到公共方法
        System.out.println(myPrivate.getPrivateS());//其他类可以访问到公共方法
        //System.out.println(myPrivate.getPrivateJ());
        /**
         * 上面被注释的这一行,在getPrivateJ处报错
         * 'getPrivateJ()' has private access in 'com.packageone.MyPrivate'
         * 翻译过来就是'getPrivateJ()'在'com.packageone.MyPrivate'中具有私有访问权限
         * 综上所述,private的方法是无法在class之外被访问到的。
         * */
        MyPrivate myPrivate1=new MyPrivate();
        myPrivate1.i=20;
        System.out.println(myPrivate1.i);
        //myPrivate1.j=10;
        //myPrivate1.s="hello";
        /**
         * 上面被注释掉的两行,分别会报错
         * 'j' has private access in 'com.packageone.MyPrivate'
         * 's' has private access in 'com.packageone.MyPrivate'
         * 翻译过来就是
         * “j”在“com.packageone.MyPrivate”中具有专用访问权限
         * “s”在“com.packageone.MyPrivate”中具有专用访问权限
         * 综上所述,private的变量,也是无法在class之外被访问到的。
         * */
    }

    public static void main(String[] args) {
        MyPrivateTwo myPrivateTwo=new MyPrivateTwo();
        myPrivateTwo.getMyPrivateTwo();
    }
}

结果

10
20
hello
20

public

首先我们需要两个包来演示:com.packageone和com.packagetwo

最大的权限,就是别人可以随便访问你,哪怕不在一个包里

但,话是这么说,其实修饰类的只能是public

package com.packageone;

public class MyPublic {
    public String one;
    public int two;
}
package com.packagetwo;

import com.packageone.MyPublic;

public class MyPublicTwo {
    public void getPublic(){
        MyPublic myPublic=new MyPublic();
    }
}

MyPublicTwo 和 MyPublic分别在不同的包里,但还是可以访问到。

protected

protected作用于继承关系。

1、父类的protected成员是包内可见的,并且对子类可见;

2、若子类与父类不在同一包中,那么在子类中,子类实例可以访问其从父类继承而来的protected方法,而不能访问父类实例的protected方法。

和private一样,是没办法修饰类的

package com.packageone;

/**
 * 会在private处报错:Modifier 'protected' not allowed here
 * */
protected class MyPrivate {
}

那我们来试一下继承的关系

父类
package com.packageone;

public class MyF {
    public String ja;
    protected int anInt;
    public int getPublicThree(){
        return 10;
    }
    protected int getProtected(){
        return 20;
    }
}
非同包子类
package com.packagetwo;

import com.packageone.MyF;

public class MyFF extends MyF {
    public static void main(String[] args) {
        MyFF myFF=new MyFF();
        System.out.println(myFF.getProtected());
        System.out.println(myFF.getPublicThree());
        myFF.anInt=10;
        myFF.ja="hello";
        System.out.println(myFF.anInt);
        System.out.println(myFF.ja);
        /**
         * 综上所演示,可以明确
         * 若子类与父类不在同一包中,那么在子类中,子类实例可以访问其从父类继承而来的protected方法
         * */
        MyF myF=new MyF();
        myF.ja="nice";
        //myF.anInt=200;
        /**
         * 上面被注释的一行在anInt处会报错
         * 'anInt' has protected access in 'com.packageone.MyF'
         * 翻译过来就是
         * “anInt”在“com.packageone.MyF”中具有受保护的访问权限
         * */
        //System.out.println(myF.getProtected());
        /**
         * 上面被注释的一行在getProtected处会报错
         * 'getProtected()' has protected access in 'com.packageone.MyF'
         * 翻译过来就是
         * “getProtected()”在“com.packageone.MyF”中具有受保护的访问权限
         * */
        System.out.println(myF.getPublicThree());
        /**
         * 综上所演示,可以证明
         * 若子类与父类不在同一包中,那么在子类中,不能访问父类实例的protected方法。
         * */
    }
}

结果

20
10
10
hello
10
同包非子类
package com.packageone;

public class MyFFF {
    public static void main(String[] args) {
        MyF myF=new MyF();
        System.out.println(myF.getProtected());
        System.out.println(myF.getPublicThree());
        myF.anInt=10;
        myF.ja="hello";
        System.out.println(myF.anInt);
        System.out.println(myF.ja);
        /**
         * 同包非子类可以正常访问protected的参数和方法
         * */
    }
}

结果

20
10
10
hello

就是方法或者类或者参数,我啥修饰字段都没有,我们就称之为包作用域

包作用域是指一个类允许访问同一个package的没有public、private修饰的class,以及没有public、protected、private修饰的字段和方法。

主类
package com.packageone;

 class MyNo {
     int ab;
     String cc;
     void getNO(){
         System.out.println("no");
     }
}
同包类
package com.packageone;

public class MyNoTwo {
    public static void main(String[] args) {
        MyNo myNo=new MyNo();
        myNo.ab=20;
        myNo.cc="to";
        myNo.getNO();
        System.out.println(myNo.ab);
        System.out.println(myNo.cc);
    }
}

结果

no
20
to
非同包类
package com.packagetwo;

import com.packageone.MyNo;

public class MyNoThree {
    public static void main(String[] args) {
        MyNo myNo=new MyNo();
        /**
         * 就算我们引入了MyNo ,import com.packageone.MyNo,但还是在每一个MyNo处都会报错
         * 'com.packageone.MyNo' is not public in 'com.packageone'. Cannot be accessed from outside package
         * 翻译过来就是
         * “com.packageone.MyNo”在“com.packageone”中不是公共的。无法从包外部访问
         * */
    }
}

default

default是java8才加入的,是针对接口的

为什么要加入default

这是我抄来的答案

首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。

default的实现

接口

package com.packageone;

public interface MyDefault {
    int a=10;
    String name="zhaoliu";
    default void getDefault(){
        System.out.println(name);
        System.out.println(a);
    }
}

实现接口的类

package com.packageone;

public class MyDefaulttwo implements MyDefault{
    public static void main(String[] args) {
        MyDefaulttwo myDefaulttwo=new MyDefaulttwo();
        myDefaulttwo.getDefault();
    }
}

结果

zhaoliu
10

总结

修饰词本类同一个包的类继承类其他类
private×××
无(默认)××
protected×
public

枚举类

为什么要有枚举类

最简单的例子,也是最常见的例子,就是一年只有四季,你想把四季封装成一个类,方便使用。

四季类

package com.packagetwo;

public class MySeason {
    public static final int Spring=1;
    public static final int Summer=2;
    public static final int Autumn=3;
    public static final int Winter=4;
}

四季类的使用

package com.packagetwo;


public class MySeasonUse {
    public static void getSeason(){
        int a=5;
        if (a==MySeason.Autumn){
            System.out.println("秋天");
        }else if (a==MySeason.Spring){
            System.out.println("春天");
        }else if (a==MySeason.Summer){
            System.out.println("夏天");
        }else if (a==MySeason.Winter){
            System.out.println("冬天");
        }
    }
    public static void main(String[] args) {
        MySeasonUse.getSeason();
        /**
         * 无法阻止一个不属于MySeason里的常量的参数来与MySeason的常量做对比
         * */
    }
}

枚举类的定义

package com.packagetwo;

public enum MySeasonEnum {
    SPRING,SUMMER,AUTUMN,WINTER
    /**
     * 习惯将常量全部写成大写
     * */
}

枚举类的使用

package com.packagetwo;

public class MySeasonEnumUse {
    public static void main(String[] args) {
        /**
         * 每一个枚举类都有一个values()方法,会返回所有的值,方便于遍历
         * */
        for (MySeasonEnum mySeasonEnum : MySeasonEnum.values()){
            /**
             * 枚举类的每一个值都有ordinal()和name()方法,分别用于返回定义的常量的顺序,从0开始计数和返回对应的常量名
             * 思考一下,为什么参数会有方法,其实每一个参数都是MySeasonEnum的实体类
             * */
            System.out.println(mySeasonEnum.ordinal());
            System.out.println(mySeasonEnum.name());
        }
        int a=10;
//        if (a==MySeasonEnum.AUTUMN){
//            System.out.println("Operator '==' cannot be applied to 'int', 'com.packagetwo.MySeasonEnum'");
//        }
        /**
         * 上面被注释的这一段,会报错
         * Operator '==' cannot be applied to 'int', 'com.packagetwo.MySeasonEnum'
         * 翻译过来就是
         * 运算符“==”不能应用于“int”、“com.packagetwo.MySeasonEnum”
         * 说明Enum枚举类是做了类型校验的,不可以使用非MySeasonEnum类型的参数去==MySeasonEnum类型的参
         * */
    }
}

结果

0
SPRING
1
SUMMER
2
AUTUMN
3
WINTER

枚举类的特性

无法被实例话

我们在来看一下这个类对应生成的class文件

package com.packagetwo;

public enum MySeasonEnum {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;

    private MySeasonEnum() {
    }
}

发现多了一个private MySeasonEnum(),ohhhh,构造方法是private的,那外部根本没办法实例化它。

定义的每个实例都是引用类型的唯一实例

引用类型比较,要使用equals()方法,如果使用==比较,它比较的是两个引用类型的变量是否是同一个对象。因此,引用类型比较,要始终使用equals()方法,但enum类型可以例外。

这是因为enum类型的每个常量在JVM中只有一个唯一实例,所以可以直接用==比较:

package com.packagetwo;

public class MySeasonEnumUseTwo {
    public static void main(String[] args) {
        MySeasonEnum mySeasonEnum=MySeasonEnum.SPRING;
        if (mySeasonEnum == MySeasonEnum.SPRING){
            System.out.println("可以使用==。而且更方便");
        }
        if (mySeasonEnum.equals(MySeasonEnum.SPRING)){
            System.out.println("也可以使用equals,但是相对来说没那么简洁");
        }
    }
}
switch

把switch放在这里是因为枚举类常常与switch一起使用,就很搭配

package com.packagetwo;


public class MySeasonEnumUseThree {
    public static void main(String[] args) {
        MySeasonEnum mySeasonEnum=MySeasonEnum.SPRING;
        switch (mySeasonEnum){
            case SPRING:
                System.out.println("春天");
                break;
            case SUMMER:
                System.out.println("夏天");
                break;
            case AUTUMN:
                System.out.println("秋天");
                break;
            case WINTER:
                System.out.println("冬天");
                break;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值