Java学废之路05——枚举类、注解与比较器

05 JAVA枚举类、注解与比较器

5.1 枚举类

类的对象只有有限个,确定的。当需要定义一组常量时,强烈建议使用枚举类。

  • JDK1.5之前需要自定义枚举类
  • JDK 1.5 新增的 enum 关键字用于定义枚举类
5.1.1 属性
  • 枚举类对象的属性不应允许被改动,所以应该使用 private final 修饰

  • 枚举类的使用 private final 修饰的属性应该在构造器中为其赋值

  • 若枚举类显式的定义了带参数的构造器,则在列出枚举值时也必须对应的传入参数

5.1.2 自定义枚举类
  • 私有化类的构造器,保证不能在类的外部创建其对象
  • 在类的内部创建枚举类的实例。声明为: public static final
  • 对象如果有实例变量,应该声明为private final,并在构造器中初始化
class Season{
    private final String SEASONNAME;//季节的名称
    private final String SEASONDESC;//季节的描述
    // 定义私有化的构造器,对final的常量进行初始化
    private Season(String seasonName,String seasonDesc){
        this.SEASONNAME = seasonName;
        this.SEASONDESC = seasonDesc;
    }
    // 枚举类
    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("冬天", "白雪皑皑");
}
5.1.3 enum关键字

使用enum关键字定义枚举类。定义的枚举类默认继承于 java.lang.Enum 类。

  • 在枚举类的最开始要提供当前枚举类的对象
  • 在对象之间使用逗号隔开,最后一个对象使用分号结束
  • 其他定义与自定义实现枚举类相同
interface Info{
    void show();
}

//使用enum关键字枚举类并实现接口
enum Season1 implements Info{
    //1.提供当前枚举类的对象,多个对象之间用","隔开,末尾对象";"结束
    SPRING("春天","春暖花开"){
        @Override
        public void show() {
            System.out.println("春天在哪里?");
        }
    },
    SUMMER("夏天","夏日炎炎"){
        @Override
        public void show() {
            System.out.println("宁夏");
        }
    },
    AUTUMN("秋天","秋高气爽"){
        @Override
        public void show() {
            System.out.println("秋天不回来");
        }
    },
    WINTER("冬天","冰天雪地"){
        @Override
        public void show() {
            System.out.println("大约在冬季");
        }
    };

    //2.声明Season对象的属性:private final修饰
    private final String seasonName;
    private final String seasonDesc;

    //3.私有化类的构造器,并给对象属性赋值
    private Season1(String seasonName,String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //4.其他诉求1:获取枚举类对象的属性
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
}

5.2 注解

5.2.1 概述

从 JDK 5.0 开始,Java 增加了对元数据(MetaData) 的支持,也就是Annotation(注解)

  • Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。 代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署

  • Annotation 可以像修饰符一样被使用, 可用于修饰包,类, 构造器, 方法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在 Annotation的 “name=value” 对中

  • 在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面, 代替JavaEE旧版中所遗留的繁冗代码和XML配置等。

  • 未来的开发模式都是基于注解的, JPA是基于注解的, Spring2.5以上都是基于注解的, Hibernate3.x以后也是基于注解的,现在的Struts2有一部分也是基于注解的了,注解是一种趋势,一定程度上可以说: 框架 = 注解 + 反射 + 设计模式。

5.2.2 自定义注解
  • 定义新的 Annotation 类型使用 @interface 关键字

  • 自定义注解自动继承了 java.lang.annotation.Annotation 接口

  • Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明。 其方法名和返回值定义了该成员的名字和类型。 我们称为配置参数。 类型只能是八种基本数据类型、 String类型、 Class类型、 enum类型、 Annotation类型、以上所有类型的数组。

  • 可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始值可使用 default 关键字

  • 如果只有一个参数成员, 建议使用参数名为value

  • 如果定义的注解含有配置参数, 那么使用时必须指定参数值, 除非它有默认值。 格式是“参数名 = 参数值” , 如果只有一个参数成员, 且名称为value,可以省略“value=”

  • 没有成员定义的 Annotation 称为标记; 包含成员变量的 Annotation 称为元数据 Annotation

注意: 自定义注解必须配上注解的信息处理流程才有意义

5.3 比较器

在 Java 中经常会涉及到对象数组的排序问题,那么就会涉及到对象之间的比较问题。正常情况下,会使用 == 或 != 进行比较,而不能使用大于或小于号进行比较。在实际的开发场景中,我们需要对多个对象进行排序,此时就需要对多个对象的大小进行比较,此时就需要使用比较器:

  • 自然排序:Comparable【默认实现】
  • 定制排序:Comparator
5.3.1 自然排序

Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序叫做类的自然排序。

(1)比较规则

image-20210414145020682

实现 Comparable 的类必须重写 compareTo(obj) 方法,两个对象通过 compareTo(obj) 方法的返回值来比较大小:

  • 如果当前对象this大于形参对象obj,则返回正整数
  • 如果当前对象this小于形参对象obj,则返回负整数
  • 如果当前对象this等于形参对象obj, 则返回零
(2)具体实现类

Comparable 的典型实现: (默认都是从小到大排列的)

  • String:按照字符串中字符的Unicode值进行比较
  • Character:按照字符的Unicode值来进行比较
  • 数值类型对应的包装类以及BigInteger、 BigDecimal:按照它们对应的数值大小进行比较
  • Boolean: true 对应的包装类实例大于 false 对应的包装类实例
  • Date、 Time等:后面的日期时间比前面的日期时间大

像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,就可以实现对两个对象的从小到大的排序。

// 具体实现类——String类
@Test
public void test1(){
    String[] arr = new String[]{"AA","RR","FF","GG","BB"};
    // 排序sort()方法会调用String类中的比较器
    Arrays.sort(arr);
    // 输出:[AA, BB, FF, GG, RR]
    System.out.println(Arrays.toString(arr));
}

image-20210414145529674

(3)自定义实现类

自定义商品类,但是未实现Comparable接口,此时去对商品对象进行排序时,将会报类型转换异常:

image-20210414151150348

因为在调用sort()方法时,系统将会默认去调用自然排序比较器,但是由于未对其进行重写,所以会报异常转换错误。对于自定义类而言,若需要排序,则需要让自定义类实现Comparable接口,并重写其中的compareTo()方法,在compareTo()方法中指明如何排序。

// 重写:指明商品按照商品价格的大小进行排序
@Override
public int compareTo(Object o) {
    // 判断对象的类型【此时与重写equals()方法相似】
    if (o instanceof Goods){
        Goods goods = (Goods) o;
        if (this.price>goods.price) return 1;
        else if (this.price<goods.price) return -1;
        else {
            // 当商品的价格相同时,再按照name进行排序【直接调用String类的compareTo()方法】
            return this.name.compareTo(goods.name);
        }
    }
    // 抛出运行时异常,此时就不需要处理异常
    throw new RuntimeException("对象类型不一致!");
}
5.3.2 定制排序

当元素的类型没有实现 Comparable 接口而且又不方便修改代码时,或者实现了 Comparable 接口的排序规则又不适合当前的操作,那么可以考虑使用定制排序 Comparator 的对象来实现,强行对多个对象进行整体排序。

(1)比较规则

重写compare(o1,o2)方法,比较o1和o2的大小:

  • 返回正整数,表示o1大于o2
  • 返回0,表示相等
  • 返回负整数,表示o1小于o2
(2)具体实现类

定制排序的参数有两个,而自然排序的参数只有一个。对String具体实现类的定制排序如下:

// 定制排序:使用匿名内部类实现
@Test
public void test3(){
    String[] arr = new String[]{"AA", "RR", "FF", "GG", "BB"};

    // 使用匿名内部类进行重写Comparator
    Arrays.sort(arr, new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            // 实现从大到小排序,调用String内已经实现的Comparable接口的方法compareTo()
            return -o1.compareTo(o2);
        }
    });
	// 输出:[RR, GG, FF, BB, AA]
    System.out.println(Arrays.toString(arr));
}
// 定制排序:lambda表达式
@Test
public void test3(){
    String[] arr = new String[]{"AA", "RR", "FF", "GG", "BB"};
    // 使用lambda表达式进行重写Comparator
    Arrays.sort(arr, (o1, o2) -> -o1.compareTo(o2));
    System.out.println(Arrays.toString(arr));
}
(3)自定义实现类
@Test
public void test4() {
    Goods[] arr = new Goods[5];
    arr[0] = new Goods("z11", 511);
    arr[1] = new Goods("z21", 211);
    arr[2] = new Goods("z31", 311);
    arr[3] = new Goods("z41", 411);
    arr[4] = new Goods("z41", 311);

    // 定制排序:价格从高到低,name从低到高
    Arrays.sort(arr, new Comparator<Goods>() {
        @Override
        public int compare(Goods o1, Goods o2) {
            if (o1.getPrice() > o2.getPrice()) return -1;
            else if (o1.getPrice() < o2.getPrice()) return 1;
            else return o1.getName().compareTo(o2.getName());	//compareTo是String类的
        }
    });
    // lambda表达式
    //Arrays.sort(arr, (o1, o2) -> {
    //    if (o1.getPrice() > o2.getPrice()) return -1;
    //    else if (o1.getPrice() < o2.getPrice()) return 1;
    //    else return o1.getName().compareTo(o2.getName());
    //});
    System.out.println(Arrays.toString(arr));
}
5.3.3 总结
  • 左大右小返回正数【正数为几都可以】;左小右大返回负数;左右相等返回0
ComparableComparator
使用范围由某一个具体的类去实现Comparable方法,并重写其compareTo(obj)方法只在实际运用比较器时,临时去实现一个定制比较器Comparator,并重写其中的compare(obj1,obj2)方法
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我姓弓长那个张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值