面向对象三特性

封装

打包例如 :类 方法数组

属性的封装

原因:公开的属性 即可访问 也可修改 不利于控制

如果一个公开的属性 后期有些特定的要求 会导致所有已编写好代码需要重新处理 很麻烦

也要封装 成为 get set方法 当有需求时 只需要修改方法体即可

操作:1.属性私有化2.根据需求 提供get set方法

ALT+SHIFT+S GET/SET

案例

class User类中

封装属性

姓名 可看不可改

密码 可改不可看

年龄 可看可改

创建空参构造

创建三参构造

创建toString()

class Test类中

User[] us = new User[3];

录入三个对象

展示三个对象

输入姓名 修改该姓名用户的密码和年龄属性

要求要修改密码的用户输入用户名和密码 验证成功后 修改成新密码

修改用户输入的姓名的用户的密码和年龄

public class User{
    private String name = "张三"; //只能看
    private String pwd;         //只能改不能看
    private int age;
  
    public User(String name,String pwd,int age){
        this.name = name;
        this.pwd = pwd;
        this.age = age;
    }
  
    public String getName(){
        return name;
    }
  
    public void setPwd(String pwd){
        this.pwd = pwd;
    }
  
    public int getAge(){
        return this.age;
    }
    public void setAge(int age){
        if(age<=0||age>=150){
            syso("年龄输入有误 修改失败");
            return;
        }
        this.age = age;
    }
  
    public boolean checkPwd(String pwd){
        return this.pwd.equals(pwd);
    }
  
    public String toString(){
        return name+" "+pwd+" "+age;
    }
}
​
//测试类中
    User u = new User();
    syso(u.getName());  //查看name
    syso(u.getName().length()); //查看姓名长度
    if(u.getName().equals("张三")){
      
    }
​
    syso("请输入用户名");
    String name = input.next();
    syso("请输入密码");
    String pwd = input.next();
    //if(u.getName().equals(name)&&u.getPwd().equals(pwd)){
    //}
    if(u.getName().equals(name) && u.checkPwd(pwd)){
        syso("登录成功");
    }else{
        syso("用户名或密码有误 登录失败");
    }
​
    //syso(u.pwd);          私有 不可访问
    //syso(u.getPwd());     没有编写查看方法
    //syso(u.setPwd());     该方法没有返回值 不能做展示
    u.setPwd("111");//密码属性只能通过方法 修改 
​
    syso(u.getAge());
    u.setAge(18);
    syso(u.getAge());
    if(u.getAge()>18){
        syso("成年人");
    }

标准实体类

1.属性私有化

2.空参构造多参构造 根据参数从少到多

3.根据需求 编写属性的get set方法

4.编写toString()

案例

class User

Sting name 可看不可改 String pwd 可改不可看 int age 可看可改 double score 可看可改

要求 封装所有属性 根据需求提供get set 方法

提供空参 带参构造

提供toString()

public boolean checkPwd(String pwd){

return this.pwd.equals(pwd);

}

class Impl

User user = null;//用于保存登录成功后的用户对象

public User[] addUser(int num){

该功能为接收一个人数 创建这个长度的数组 循环存满用户 返回这个数组

}

public void login(User[] us ,String name ,String pwd){

功能为 接收用户输入的用户名和密码 登陆成功 将这个用户对象保存入全局u

}

public void setPwd(User[] us,String name,String oldPwd,String newPwd){

判断老密码是否正确 正确则更新为新密码

}

public void showAll(User[] us){

展示数组所有用户信息

}

class Util

class Test

继承extends

抽取出一个类 来作为要操作的实体对象的模板第一次抽象

从无数对象中 提出共有属性和方法 第一次抽象 ===》自定义类型

将多个实体类的共有属性和方法 第二次抽象===》父类

java中的继承 遵守单继承继承原则:一个类最多只有一个父类 一个类 可以有多个子类

User [] us

us[0] = new User();

us[0].name="";

us[0].age = 18;

us[0].gender = '男';

class Dognameagebrand

eat()lookDoor()

class Cat name age color

eat()playXian()

class Pet

name ageeat()

Pet[] ps = new Pet[3];

ps[0] = new Dog();

if(ps[0] instanceOf Dog){

Dog dd = (Dog)ps[0];

dd.lookDoor();

}else if(ps[i].getClass() == Cat.class){

Cat cc = (Cat)ps[0];

cc.playXian();

}

Dog dd = (Dog)ps[0];

dd.lookDoor();

ps[0].eat();

ps[0] = new Cat();

ps[0].eat();

测试类中 创建一个父类数组 循环存储用户选择的宠物对象

循环展示每个宠物的属性

循环调用每个宠物的功能

案例

尝试完成商店项目 三类商品需要保存处理

SportString buildDate doSport()

FoodString liveDateeatFood()

StudyString brandgoStudy()

extends Goodsint typeString namedouble priceshow()

Sport s0 = new Sport();//Sport的一个引用名s0 指向 堆中创建的一个Sport的对象地址

Goods g0 = new Sport();

//先创建父类对象

g0 = new Food();

g0 = new Study();

Goods[] gs = new Goods[10];

gs[0] = new Sport();

gs[1] = new Food();

gs[2] = new Study();

gs[3] = new Food();

1.子类可以访问 父类 非私有资源 super.this.//super()

2.父类的引用 可以指向 任意子类的对象

重载

在同一个类中 方法名相同 参数列表不同 完全不关心返回值

重写

在子父类中子类与父类的 方法名相同 参数列表相同 方法体不同

子类重写方法的返回值类型 一般与父类相同 或者 是父类原始方法返回值类型的子类类型

为什么要在父类中 存放一个将来会被重写的方法呢??

因为 如果父类或者更高级没有这个方法 则该方法成为了子类特有的方法 不能使用多态调用

多态

父类引用 表现 不同子类状态 的能力

***核心:==> 父类的引用 指向 子类对象

Dog d = new Dog();

d.equals()

Pet p0 = new Dog();

p0.show();//Dog类重写的show()

p0 = new Cat();

p0.show();//Cat类重写的show()

//如果子类没有重写show() 则调用父类自己的show()

***条件:

1.父类的引用 指向子类对象

2.子类重写父类的方法

Object[] oo = new Object[3];

调用逻辑

当使用多态时==》使用父类的引用 指向 子类的对象

1.用父类的引用 调用【方法】的逻辑

1.先判断父类或者更高级类是否有该方法

1.如果没有 直接报错(父类不能调用子类特有资源)

2.如果存在 会再判断 父类所指向的子类中 是否重写了该方法

1.如果重写了 则执行重写后的方法

2.如果没重写 则执行父类或更高级类的该方法

如果调用的是子类特有的资源 必须要强转回子类本身引用 去调用

    void show()  父类中 存在   各子类中有重写
    Goods g1 = new Sport();
    g1.show();  //会执行Sport类重写的show()
​
    Goods g2 = new Goods();  g2.show();
    for(Goods g : gs){  //每个房间 有不同子类类型的对象
        g.show();
    }
​
​
    Goods g0 = new Food();
    if(g0.getClass() == Food.class){
        Food f = (Food)g0;
        f.特有资源;
    }else if(g0 instanceof Food){   //返回true、false
        Food f = (Food)g0;
        f.特有资源;
    }

2.继承关系中 调用属性的逻辑

对于属性 使用哪个【类的引用】调用 则去该类或更高级类查找该属性 而不会像调用方法一样 去判断子类是否重写

public class Animal {
    String name = "动物";
}
public class Pet extends Animal{
    String name = "宠物";
}
public class Dog extends Pet{
    String name = "小狗";
}
​
    //测试类中
    Pet p = new Dog();
    syso(p.name);   //宠物
    Dog d = new Dog();
    syso(d.name);   //小狗
    Animal a = new Dog();
    syso(a.name);   //动物
  

abstract 抽象

需求:

1.父类只是存储子类相同属性和方法的一个容器 不应该被实例化 但是构造方法必须可调用

2.父类中某些方法 如何保证 子类必须重写

》修饰类

变成抽象类不能被实例化可以存放抽象方法

public abstract class Pet{
  
}

》修饰方法

成为抽象方法没有方法体只能存放于抽象类中子类必须重写该方法

public abstract class Pet{
    public abstract void show();
}
​
​
public class Dog extends Pet{
    public void show(){
        //必须重写 来自于父类的抽象方法
    }
}

final 最终的

float 单精度浮点型false 假

》修饰属性(变量)

变为常量如果修饰引用数据类型 则不可再指向新的地址

    final int a = 5;
    a = 100;//报错
    final int[] nums = {4,5,7};
    nums = new int[3];//报错
    nums[0] = 100;//元素值可变
    final User u = new User("aa");
    u = new User();//报错
    u.name = "bb";

》修饰类

最终类不能有子类

》修饰方法

最终方法 (可以出现在任何类中 通常写在父类中)必须有完整方法体 且不能被重写

protected

受保护的 主要用于继承关系中的资源保护

public可跨类 可跨包

protected可跨类 半可跨包不可跨包

什么都不写可跨类 不可跨包

private不可跨类 不可跨包

demo1包中
    public class Pet{
        protected String n1 = "aaa";    //受保护的
        String n2 = "bbb";              //缺省
    }
    public class Cat extends Pet{
        public void show(){
            syso(this.n1);
            syso(super.n1);
        }
    }
    public class Test{
        main(){
            Pet p = new Pet();
            syso(p.n1);
            Cat c = new Cat();
            syso(c.n1);
        }
    }
​
demo2包中
    public class Dog extends Pet{
        public void show(){
            Pet p = new Pet();
            syso(p.n1);//报错
            syso(p.n2);//报错
          
            syso(super.n1);//可以访问 展示 aaa
            syso(this.n1);
        }
    }
​
    public class Bird{
        public void show(){
            Pet p = new Pet();
            syso(p.n1);//报错
        }
    }

接口interface

表示一种能力 设定一个规范 是特殊的抽象类(不能实例化)

主要存放抽象方法 因此 类 和方法 都可以省略abstract

extendsimplements

一个类 最多只能【继承】【 一个父类】 可以【实现】【多个】【接口类】

接口类 不能【实现】其他类 但可以【多】【继承】其他【接口类】

案例

机器猫 类 希望获取 机器的相关特性 又希望获取 猫的相关特性

因为单继承原则 机器猫 不能 同时继承机器 和 猫这两个类 只能先让机器和猫产生子父类关系

机器猫 继承 机器 继承 猫===》发现 继承有一些短板

对比

继承is a子类extends父类抽象类最多一个父类

一个父类 可以有多个子类

接口has a 实现类implements接口类特殊抽象类 可以实现多个接口

一个接口 可以有多个实现类

面试

1.一个类可以实现多个接口

2.一个接口类 永远不可能实现其他任何类 可以继承extends 多个 【接口类】

java是单继承语言么?

是 但是可以通过接口实现多继承

一个类 只能【继承】一个父类 可以【实现】多个接口类

一个接口类 只能【继承】 【多个】【接口类】

多态

接口的引用 指向 实现类对象

不建议使用接口定义数组 来存放实现类对象

​
//接口类
public interface USB extends 其他多个接口{  //特殊抽象类 省略了abstract
    String name;//报错  默认是静态常量 必须赋值
    public void show(); //抽象方法 省略abstract
    public default void show1(){
        //可以编写带方法体的方法 一般方法添加default关键字
    }
}
public class Mouse implements USB{
    public void show(){
        syso("鼠标");
    }
    //show1()可重写 也可不重写
}
public class KeyBoard implements USB{
    public void show(){
        syso("键盘");
    }
    //show1()可重写 也可不重写
}
​
​
Test类中
    USB u = new Mouse();
    u.show();   //Mouse的show()
    u = new KeyBoard();
    u.show();   //KeyBoard的show()
​
​
//抽象父类
public abstract class Pet{
  
    String name;    //默认值null
    int age;        //默认值0
  
    public abstract void show();//编写抽象方法 必须使用abstract
    public void show1(){
        //可以编写带方法提的方法 无需关键字
    }
}
public class dd extends Pet{
    public void show(){
        syso("叮当猫");
    }
    //show1()可重写 也可不重写
}
public class dog extends Pet{
    public void show(){
        syso("机器狗");
    }
}
​
//都不能实例化
//都可以存放抽象方法
    //抽象父类中的抽象方法 需要添加abstract 子类必须实现
    //接口类中的抽象方法 默认就是abstract   实现类必须实现
//都可以使用多态
    //父类的引用 可以 指向 子类对象  调用方法时 自动判断指向的子类并执行该子类重写的方法或原始方法
    //接口类的引用 可以 指向 实现类对象 调用方法时 自动判断指向哪个实现类并执行该实现类实现的方法
//接口类中 带方法体的方法 需要添加default 特殊情况可使用, 
        //static方法 必须带方法体 只能使用接口类名调用 且不能重写
        //private方法 必须带方法体 只能在本类中被调用 只能在JDK10以上的版本使用
//抽象类中 直接可以编写带方法体的方法
        //static方法 可以父类类名、子类对象、多态都可调用 不能重写
        //private方法 只能在本类中被调用
//抽象类中声明的变量 属于正常全局变量(每个子类对象都可调用赋值)
//接口类中声明的"全局变量" 默认都是静态常量  必须赋值 且不可更改  
    //可以使用接口类名、实现类对象、多态 调用
​
父类作为返回值 ===》可以返回任意子类对象
​
父类作为方法的形参 ===》可以接收任意子类对象作为实参
​
接口作为返回值 ===》可以返回任意实现类对象
​
接口作为方法的形参===》可以接收任意实现类对象作为实参==>传入一个算法
​
​
​
以接口作为形参的意义==》传入一种算法

案例

class Mechine

String name

int price

必须重写的 sell()

public interface Print{

public void print();

}

interfaceTelephonetel()

interface Copycopy()

interface Faxfax()

Mechine_I extends Mechine implements Print,Telephone{

打印彩色打电话

public void print(){

syso("我可以打印彩色");

}

public void tel(){

}

}

Mechine_II

打印黑白传真 复印

Mechine_III

打印黑白+彩色打电话 复印 传真

测试类 创建合适的数组 存储两台I型 一台II型 三台III型

展示所有打印机所有功能

练习

interface USB 接口 提供有一个接入设备的标准

标准为 String usb(double money)

classFan设备 实现该接口 展示 money+"元买的风扇转转转"

classKeyBoard设备 实现该接口 展示 money+"元买的键盘敲敲敲"

classMouse设备实现该接口 展示money+"元买的鼠标点点点"

class Impl

方法 USB getMechine()询问用户 接入什么设备 返回对应的设备

方法 doMechine(USB u,double money)接收上一个方法返回的设备 及询问一个价钱 作为参数 调用接口功能

测试类中 调用以上两个方法

组成

抽象方法可以省略abstract

默认方法返回值前添加default 必须编写方法体

静态方法添加sataic 必须编写方法体只能通过接口类的类名调用 不能被重写

私有方法jdk10以上 可以使用 必须编写方法体 一般是将接口中多个默认方法共同的代码提取出来

属性默认都是静态常量 必须赋初始值(命名规范:全大写 Math.PI)

接口优化

案例

charcharAt(int index)

boolean equals(Object o)

Imp类中 有一个方法game() 通过某种游戏规则 返回true、false

1.输入两个数字 产生一个随机数 偶数返回true 奇数返回false

2.输入两个数字 判断平均数 偶数返回true 奇数返回false

3.输入两个数字 判断和偶数返回true 奇数返回false

结论:如果影响方法运算结果的因素 不再是简单的值 而是一套算法 则可以使用接口作为形参

而接口 负责设计算法的架构 具体实现就是不同的算法

public interface Number{
    public int getNum(int n1,int n2);
}
public class N1 implements Number{
    public int getNum(int n1,int n2){
        Random r = new Random();
        return r.nextInt(n2-n1+1)+n1;
    }
}
public class N2 implements Number{
    public int getNum(int n1,int n2){
        return (n1+n2)/2;
	}
}
public class N3 implements Number{
    public int getNum(int n1,int n2){
        return n1+n2;
    }
}



Number n = (o1,o2)->{return o1+o2;};


public class Impl{
    public boolean game(Number n,int n1,int n2){
        int num = n.getNum(num1,num2);
        return num%2==0; 

    }
}

//测试类
	Impl i = new Impl();
	boolean b = i.game(new N2());	//以接口作为形参 就以接口实现类对象作为实参


int[] nums = new int[]{23,67,12,89,33}
Arrays.sort(nums);

class User{
    String name;
    int age;
    double score;
}

User[] us = new User[10];
//录入十个对象 
Arrays.sort(us);//报错  没有给sort提供算法
Arrays.sort(数组名,Comparator接口)

for(int i = 0;i<us.length-1;i++){
    for(int j = i+1;j<us.length;j++){
        if(us[i].age>us[j].age){
            User u = us[i];
            us[i] = us[j];
            us[j] = u;
        }
    }
}

比较器 接口

案例

每个元素都是字母 的String类型的集合 希望升序排列 再 【降序排列】

优先根据姓名的升序 姓名相同 根据年龄的降序 给用户添加排序的选项 【1. 2.年龄升序 姓名降序】

内部比较器

ComparablecompareTo(E o)

要比较的实体类直接实现

//内部比较器==》写在要排序的实体类中的
public class User implements Comparable<User>{

	String name;//全英文
	int age;
	double score;

	public User(String name, int age, double score) {
		super();
		this.name = name;
		this.age = age;
		this.score = score;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", score=" + score + "]";
	}

	@Override
	public int compareTo(User o) {
		// TODO Auto-generated method stub
		//return this.age-o.age;	//this-o 升序  反之降序
		//return o.age-this.age;
		//return o.name.compareTo(this.name);
	
		//return (int)(o.score-this.score);//会损失精度
		//return this.score-o.score>0?1:-1;
		//return Double.compare(o.score, this.score);
	
		//谁优先 先相等
		if(this.name.equals(o.name)) {
			if(this.age==o.age) {
				return Double.compare(this.score, o.score);
			}
			return this.age-o.age;
		}
		return this.name.compareTo(o.name);
	}

}

//测试类中
		User[] us = new User[15];
		us[0] = new User("cba",18,78.5);
		us[1] = new User("bac",18,78.3);
		us[2] = new User("bba",18,78.1);
		us[3] = new User("bba",19,78.5);
		us[4] = new User("bac",17,78.5);
		us[5] = new User("bac",18,78.2);
		us[6] = new User("cba",18,78.7);
		us[7] = new User("cba",18,78.4);
		us[8] = new User("abc",18,78.5);
		us[9] = new User("abc",18,78.3);
		us[10] = new User("abc",17,78.7);
		us[11] = new User("abc",16,78.1);
		us[12] = new User("cba",19,78.1);
		us[13] = new User("bba",17,78.6);
		us[14] = new User("bba",18,78.3);
	
		//如果数组中元素类型 没有实现内部比较器 则该方法执行会报错
		Arrays.sort(us);//sort 负责冒泡 将两两元素调用写好的排序规则 实现交换或者不交换
	
		for(User u : us) {
			System.out.println(u);
		}

外部比较器

Comparatorcompare(E o1,E o2)

单独创建一个类来实现

1.外部比较器可以有多个 随意选择

2.不影响实体类结构

3.外部比较器优先级更高 可以覆盖内部比较器

//单独创建一个类 实现外部比较器 编写排序规则
public class Com_1 implements Comparator<User> {

	@Override
	public int compare(User o1, User o2) {
		// TODO Auto-generated method stub
		if(o1.name.equals(o2.name)) {
			if(o1.age==o2.age) {
				return Double.compare(o1.score, o2.score);
			}
			return o1.age-o2.age;
		}
		return o1.name.compareTo(o2.name);
	}

}

//测试类中
	Arrays.sort(us,new Com_1());//有外部比较器 则优先按照外部比较器排序

//Com_1这个类 除了实现Comparator接口外 没有其他任务 可以使用局部内部类 优化掉

//测试类中排序之前 直接编写外部比较器的实现类 同时获取其对象
			Comparator<User> cu = new Comparator<User>() {
				@Override
				public int compare(User o1, User o2) {
					// TODO Auto-generated method stub
					if(o1.name.equals(o2.name)) {
						if(o1.age==o2.age) {
							return Double.compare(o2.score, o1.score);
						}
						return o2.age-o1.age;
					}
					return o2.name.compareTo(o1.name);
				}
			};
			Arrays.sort(us,cu);

//因为Comparator接口是一个函数式接口 可以使用lambda表达式 继续优化
			Comparator<User> cu = (o1, o2)->{
				if(o1.name.equals(o2.name)) {
					if(o1.age==o2.age) {
						return Double.compare(o1.score, o2.score);
					}
					return o2.age-o1.age;
				}
				return o1.name.compareTo(o2.name);
			};
			Arrays.sort(us,cu);
//再借助于三元运算符
			Comparator<User> cu = (o1,o2)-> o1.age==o2.age?  o1.score==o2.score? o1.name.compareTo(o2.name)   : Double.compare(o2.score,o1.score)    :  o2.age-o1.age;
			Arrays.sort(us,cu);

单例模式

效果:一个类 有且只有一个对象

public class Impl{
    //1.构造方法私有化
    private Impl(){

    }

    //静态常量命名规范  全大写字母
   //public static final Impl IMPL = new Impl();

    //2.做一个标记 用于判断是否已经存在该类的对象
    private static Impl impl;//null

    //3.创建一个方法 返回该类唯一的对象
    public static Impl getImpl(){
		if(impl==null){
            impl = new Impl();
        }
        return impl;
    }
}


	Impl impl1 = Impl.getImpl();
	Impl impl2 = Impl.getImpl();

枚举类

效果:一个类 允许有某几个对象

User 张三 18李四 22王五 20

public class User{
    String name;
    int age;

    private User(String name,int age){
        this.name = name;
        this.age = age;
    }

    public static final User USER1 = new User("张三",18);
    public static final User USER2 = new User("李四",22);
    public static final User USER3 = new User("王五",20);


   // public static final User[] us = new User[3];
   // static{
   //     us[0] = new User("张三",18);
   //     us[1] = new User("李四",22);
   //     us[2] = new User("王五",20);
   // }

    public String toString(){
        return "sdgagaga";
    }
}
	//测试类
	syso(User.USER1);
	syso(User.USER2.name+" "+User.USER2.age);
	User[] us = new User[]{User.USER1,User.USER2,User.USER3};
public enum User{

    //0.枚举值 只能是 符合变量名命名规则的名称 同时因为是static final  因此全字母大写
    //1.第一行 必须存放 枚举值  使用,隔开 末尾不加符号  如果后续有代码 末尾加;
    USER1("张三",18),
    USER2("李四",22),USER3("王五",20);

    String name;
    int age;

    //2.枚举类中的构造方法 必须是私有的
    private User(String name,int age){
        this.name = name;
        this.age = age;
    }

    //3.枚举类 不是直接继承自Object  而是继承自Enum 该类已经重写了Object的toString()
    public String toString(){
        //return super.toString();//父类(Enum)的toString()方法默认展示每个对象的名字
        return this.name+" "+this.age;
    }
}

	//测试类中
	User[] us = User.values();
	for(User u : us){
        syso(u);
    }
	syso();
	User u1 = User.valueOf("USER1");//如果不存在 直接报错 需要通过异常处理
	syso(u1); //张三 18
public enum Gender{
    男,女
}

public enum Gender{
    男(),女();
    private Gender(){

    }
    public String toString(){
        return this.name;//枚举值的名字
    }
}

public class Gender{
    char gender;
    private Gender(char gender){
        this.gender = gender;
    }
    public static final Gender 男 = new Gender('男');
    public static final Gender 女 = new Gender('女');

    public String toString(){
        return this.gender+"";
    }
}

//测试类中
	char g1 = Gender.男;
	char g2 = Gender.女;

注意:

0.枚举值 只能是 符合变量名命名规则的名称 同时因为是static final 因此全字母大写

1.第一行 必须存放 枚举值 使用,隔开 末尾不加符号 如果后续有代码 末尾加;

2.枚举类中的构造方法 必须是私有的

3.枚举类 不是直接继承自Object 而是继承自Enum 该类已经重写了Object的toString() 展示每个对象的名字

常用方法

返回枚举值的数组枚举类类名.values()

返回某个枚举值枚举类类名.valueOf(String name)参数为字符串形式的枚举对象名

练习

enum Gender{

男,女

}

enum User

String nameint age Gender gender

张三 (张三 18 Gender.男)

李四 (李四 20 女)

王五 (王五 22 男)

测试类中 获得枚举值数组 遍历展示

用户输入姓名 展示对应的枚举值信息

enum Weeks{

DAY1(1,"星期一"),DAY2DAY3...;

int idString str

//构造方法

//重写toString() 展示 对象名 id str

}

测试类中

展示七个枚举值

用户输入字符串 例如 "星期一" 展示当前枚举值

用户输入数字 1-7展示对应枚举值

用户输入对象名 例如"DAY1" 展示对应枚举值