Java特殊类 枚举,接口,抽象类,匿名类

1.枚举
枚举是一种特殊的类,我们之前学的所有类都是继承自Object,但是枚举类继承自Enum类,
定义枚举

// >> TODO 使用enum而非class声明
public enum Category {

    // >> TODO 必须在开始的时候以这种形式,创建所有的枚举对象,枚举的实例是在枚举创建的时候就定义好的,不允许在其他地方定义新的枚举类,所以,枚举的构造函数默认是Private的,写不写private都一样,如果写public就会报错、
    FOOD(1),
    // >> TODO 不可以重名
//    FOOD(1),
    COOK(3),//实例之间用逗号隔开
    SNACK(5),
    CLOTHES(7),
    ELECTRIC(9);//末尾必须是分号

    // 可以有属性
    private int id;

    // >> TODO 构造方法必须是private的,不写也是private的
    Category(int id) {
        this.id = id;
    }

    public int getId() {//定义方法和类方法是一样的
        return id;
    }

//    public void setId(int id) {
//        this.id = id;
//    }


    @Override
    public String toString() {
        return "Category{" +
            "id=" + id +
            '}';
    }

}

枚举的使用:


public class UseEnum {
    public static void main(String[] args) {
        // >> TODO 获取所有枚举,看看枚举实例有哪些方法
        for (Category category : Category.values()) {//可以通过点values的方法,获取枚举定义的实例
            System.out.println("-----------" + category.getId() + "------------");//调用实例方法
            System.out.println(category.ordinal());//实例属性
            System.out.println(category.name());
            System.out.println(category.toString());
        }

        System.out.println();
        // >> TODO 根据名字获取枚举
        System.out.println(Category.valueOf("FOOD"));
//        System.out.println(Category.valueOf("food"));

        Scanner in = new Scanner(System.in);
        System.out.println("请输入枚举的名字:");
        String categoryName = in.next();
        Category enumInput = Category.valueOf(categoryName.trim().toUpperCase());
        System.out.println("枚举的信息:" + enumInput.toString());

        System.out.println("请输入要比较的枚举的名字:");
        String categoryName2 = in.next();
        Category enumInput2 = Category.valueOf(categoryName2.trim().toUpperCase());
        System.out.println("第二次输入的枚举的信息:" + enumInput2.toString());

        System.out.println(enumInput == enumInput2);


    }
}

2.接口


// >> TODO 接口的定义使用interface,而非class
// >> TODO 接口中的方法,就是这个类型的规范,接口专注于规范,怎么实现这些规范,它不管
// >> TODO 接口无法被实例话,也就是不可以new一个接口的实例。
public interface ExpireDateMerchandise {

    // >> TODO 接口里的方法都是public abstract修饰的,方法有名字,参数和返回值,没有方法体,以分号;结束,
    // TODO 接口注释最好写一下
    boolean notExpireInDays(int days);

    // >> TODO 因为接口里的方法都是且只能用public abstract修饰,所以这俩修饰符可以省略
    // >> TODO abstract就是抽象方法的修饰符,没有方法体,以分号结束
    Date getProducedDate();
    public abstract Date getExpireDate();
    double leftDatePercentage();
    double actualValueNow(double leftDatePercentage);

    // >> TODO 接口里不能定义局部变量,定义的变量默认都是public static final的,这三个修饰符同样可以省略

    public static final int VAL_IN_INTERFACE = 999;

}


// >> TODO 接口甚至可以没有任何方法的定义,只是规定一种类型
public interface VirtualMerchandise {
}

``

```java
在这里插入代码片
public interface Intf1 {
    void m1();
}


public interface Intf2 {
    void m1();

    void m2();

}


package com.geekbang.intf;

// >> TODO 接口也可以继承接口。接口可以继承多个接口,接口之间的继承要用extends
// >> TODO 接口不可以继承类
// >> TODO 继承的接口,可以有重复的方法,但是签名相同时,返回值必须完全一样,否则会有编译错误
public interface Intf3 extends Intf1, Intf2{
    void m3();
}

接口的使用:

public class INterface implements ExpireDateMerchandise
TODO 可以用实现接口的类的引用,给接口的引用赋值。类似于可以使用子类的引用给父类赋值
INterface iNterface=new INterface();
ExpireDateMerchandise expireDateMerchandise1=iNterface;



接口也可以有方法体:

// >> TODO 缺省的实现方法,用default修饰,可以有方法体
public interface ExpireDateMerchandise {

    // >> TODO 缺省的实现方法,用default修饰,可以有方法体
    default boolean notExpireInDays(int days) {
        return daysBeforeExpire() > days;
    }
    Date getProducedDate();
    public abstract Date getExpireDate();
    default double leftDatePercentage() {
        return 1.0 * daysBeforeExpire() / (daysBeforeExpire() + daysAfterProduce());
    }
    double actualValueNow(double leftDatePercentage);

    // >> TODO 接口中可以有私有方法,不需要用default修饰
    // >> TODO 接口里的私有方法,可以认为是代码直接插入到使用的地方
    private long daysBeforeExpire() {
        long expireMS = getExpireDate().getTime();
        long left = expireMS - System.currentTimeMillis();
        if (left < 0) {
            return -1;
        }
        // 返回值是long,是根据left的类型决定的
        return left / (24 * 3600 * 1000);
    }

    private long daysAfterProduce() {
        long produceMS = getProducedDate().getTime();
        long left = System.currentTimeMillis() - produceMS;
        if (left < 0) {
            return -1;
        }
        // 返回值是long,是根据left的类型决定的
        return left / (24 * 3600 * 1000);
    }

在这里插入图片描述


// >> TODO 有方法的接口,并不是多继承。接口不可以继承类,这一点就打破了
// >> TODO 同样,接口不可以声明实例变量。其方法是有限制的,比如这个接口,因为不能声明实例变量,
// >> TODO 只能通过getProducedDate和getExpireDate,间接通过实现接口的类,获取数据
// >> TODO 和抽象方法不同,如果一个类实现了两个接口,并且两个接口里有相同的缺省方法,编译器会报错
public interface ExpireDateMerchandise {

    // >> TODO 缺省方法,也有this自引用,但是只能调用接口里的方法,或者继承的接口里的方法
    // >> TODO 因为能new出实例来的,肯定是实现了所有方法的,this自引用就是指向那个对象,所以使用起来不会有问题


    // >> TODO 接口中可以有静态方法,不需要用default修饰。静态方法可以被实现接口的类继承
    public static long daysBetween(long from, long to) {
        long gap = to - from;
        if (gap < 0) {
            return -1;
        }
        return gap / (24 * 3600 * 1000);
    }

3.抽象类:接口和类的混合体


// >> TODO 抽象类用abstract修饰,抽象类可以继承别的类或者抽象类,也可以实现接口
// >> TODO 抽象类可以有抽象方法,抽象方法可以来自实现的接口,也可以自己定义
// >> TODO 抽象类不可以被实例化
// >> TODO 抽象类也可以没有抽象方法,没有抽象方法的抽象类,也不可以被实例化。
// >> TODO 简单来说,抽象类就两点特殊:1)被abstract修饰,可以有抽象方法 2)不可以被实例化
public abstract class AbstractExpireDateMerchandise extends MerchandiseV2 implements ExpireDateMerchandise {

    private Date produceDate;
    private Date expirationDate;

    // >> TODO 抽象类里构造方法的语法和类一样。
    public AbstractExpireDateMerchandise(String name, String id, int count, double soldPrice, double purchasePrice, Date produceDate, Date expirationDate) {
        super(name, id, count, soldPrice, purchasePrice);
        this.produceDate = produceDate;
        this.expirationDate = expirationDate;
    }

    public AbstractExpireDateMerchandise(String name, String id, int count, double soldPrice, Date produceDate, Date expirationDate) {
        super(name, id, count, soldPrice);
        this.produceDate = produceDate;
        this.expirationDate = expirationDate;
    }

    public AbstractExpireDateMerchandise(Date produceDate, Date expirationDate) {
        this.produceDate = produceDate;
        this.expirationDate = expirationDate;
    }

    // >> TODO @ 是Java中的注解(annotation),后面我们会详细讲述
    // >> TODO @Override代表此方法覆盖了父类的方法/实现了继承的接口的方法,否则会报错
    public boolean notExpireInDays(int days) {
        return daysBeforeExpire() > 0;
    }

    public Date getProducedDate() {
        return produceDate;
    }

    public Date getExpireDate() {
        return expirationDate;
    }

    public double leftDatePercentage() {
        return 1.0 * daysBeforeExpire() / (daysBeforeExpire() + daysAfterProduce());
    }

//    @Override
//    public double actualValueNow(double leftDatePercentage) {
//        return 0;
//    }

    // >> TODO 抽象类里自己定义的抽象方法,可以是protected,也可以是缺省的,这点和接口不一样
//    protected abstract void test();


    // TODO 这俩方法是私有的,返回值以后即使改成int,也没有顾忌
    private long daysBeforeExpire() {
        long expireMS = expirationDate.getTime();
        long left = expireMS - System.currentTimeMillis();
        if (left < 0) {
            return -1;
        }
        // 返回值是long,是根据left的类型决定的
        return left / (24 * 3600 * 1000);
    }

    private long daysAfterProduce() {
        long produceMS = produceDate.getTime();
        long past = System.currentTimeMillis() - produceMS;
        if (past < 0) {
            // 生产日期是未来的一个时间?315电话赶紧打起来。
            return -1;
        }
        // 返回值是long,是根据left的类型决定的
        return past / (24 * 3600 * 1000);
    }
}


抽象类可以被继承,继承他的可以是具体的类,也可以是抽象类。

匿名类
在这里插入图片描述


    // >> TODO 对于抽象类,也可以给构造方法传递参数
    private UnitSpecAbs anywhereAbs = new UnitSpecAbs(1.2, "default") {
        @Override
        public double getNumSpec() {
            return Math.max(Phone.this.speed, this.getSpec());
        }




        this.screenSize = screenSize;
        // >> TODO 可以像平常的类一样使用局部内部类
        this.speed = cpuHZ;
        this.cpu = new UnitSpec() {
            @Override
            public double getNumSpec() {
                // >> TODO 实际用的比较多的是匿名类和静态内部类(为了单例),成员内部类和局部内部类用的比较少
                // >> TODO 同样的,方法里的匿名类在访问局部变量和参数时,它们也必须是实际final的
                return Math.max(Phone.this.speed, Math.max(cpuHZ, localCPUHZ));
            }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值