《疯狂Java讲义》学习笔记(五)面向对象

初始化块总在构造器执行前被调用

1、类
  • 类是某一批对象的抽象,对象才是一个具体存在的实体
  • 类包含:构造器、成员变量和方法
  • 成员变量:用于定义该类或该类的实例所包含的状态数据
    方法:用于定义该类或该类的实例的行为特征或者功能实现
    构造器:用于构造该类的实例,通过new关键字来调用,返回该类实例
  • 成员变量
    修饰符:public、protected、private、省略(四选一)、static、final(两个可以同时)
    类型:任何类型
    名称:首字母小写,后面每个单词首字母大写,其它字母小写,单词之间不要有分隔符
  • 方法
    修饰符:public、protected、private、省略(四选一)、abstract、final(两选一)、static可以与前二组合
    返回值:任何类型,用return返回,没有则方法名前需要用void关键字来修饰
    名称:首字母小写,后面没个单词首字母大写,其它字母小写,单词之间不要有分隔符
    参数:0至多个参数组成,英文逗号隔开
  • static用于修饰方法、成员变量等,static修饰的成员表明它属于这个类本身,而不属于该类的单个实例,非static修饰的普通方法、成员变量则属于该类的单个实例,不属于该类。
  • 构造器:不能有返回值,也不能用void修饰,否则被认为是方法
    修饰符:public、protected、private、省略(四选一)
    名称:必须与类名相同
    参数:和定义方法格式相同
  • Java的对象引用就是C里的指针,只是Java把这个指针封装起来了
  • this关键字总是指向调用该方法的对象
    构造器中引用该构造器正在初始化的对象
    在方法中引用调用该方法的对象
  • static修饰的方法中不能使用this引用
  • 静态方法无法直接访问非静态方法
2、方法
  • 函数和方法的区别:结构化编程是由函数组成,面向对象编程是由类组成,类包含方法。
  • 方法的所属性主要体现:
    方法不能独立定义,方法只能在类体里定义
    方法要么属于类,要么属于实例
    方法不能独立运行,执行方法时必须使用类或对象来作为调用者(类.方法或实例.方法)
  • 方法的参数采用复制值的方式传递,即原先的值不会被改变,但如果参数是引用对象则会被改变,如:对象、数组等
  • 可变形参可以用String… strs来表示,参数也可以用数组来传递new String[]{“aa”,”bb”}
  • 方法重载:同一个类中,方法名相同,形参不同(数量或类型不同),但和返回值、修饰符无关
  • Java中确定一个方法的3个要素:
    调用者:类或实例对象
    方法名:方法的标识
    形参列表:当调用方法时,系统将会根据传入的实参列表匹配
  • 成员变量:实例变量或类变量
    局部变量:形参、方法局部变量、代码块局部变量
  • 必须先给方法局部变量和代码块局部变量指定初始化值,否则不能访问它们,但全局变量可以
  • 定义局部变量后,系统并未为这个变量分配内存空间,直到等到程序为这个变量赋初始化值时,系统才会为局部变量分配内存,并将初始化值保存到这块内存中
  • 不应把所有变量都定义成全局变量:
    增大了变量的生存时间,导致更大的内存开销
    扩大了变量的作用域,不利于提高程序内聚性
3、封装
  • 封装是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问
  • 封装的好处
    隐藏类的实现细节
    让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对成员变量的不合理访问
    可进行数据检查,从而有利于保证对象信息的完整性
    便于修改,提高代码的可维护性
  • 封装的原则
    将对象的成员变量和实现细节隐藏起来,不允许外部直接访问
    把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作
  • 作用域修饰符
    private:只能本class能访问
    default:同一个package下都可以访问
    protected:同一个package下都可以访问,子类可以访问
    public:全可以访问
  • 对于外部类而言,可以用pubulic和default来修饰,但不能用protected和private,因为没有存在类的内部,也就没有其所在类子类和没有所在类内部的范围
  • 没有用public修饰的类,文件名与类名可以不同,否则,必须相同
  • 作用域修饰符的使用原则
    类中的大部分成员变量应该使用private来修饰,只有一些static修饰的、类似全局变量的成员变量,才考虑使用public修饰
    用于辅助实现该类的工具方法,应该使用private修饰
    如果方法仅希望被子类重写,而不想被外界直接调用,应该使用protected来修饰
4、包package
  • package机制提供了类的多层命名空间,用于解决类的命名冲突、类文件管理等问题
  • 一般在类文件的第一行需要标注package
  • 同一个包的类不必于相同的目录下
  • 为Java类添加包必须在Java源文件中通过package语句指定,单靠目录名是没法指定的
  • package用小写字母命名,建议用公司域名倒写来作为包名,如:com.shuiwujia
  • 可以使用improt static导入静态类,此后不用类.方法(),直接使用方法()即可
  • Java源文件大体结构
package语句 -0个或1个,必须放在文件开始
imporm | import static语句 -0个或多个,必须放在所有类定义之前
public classDefinition | interfaceDefinition | enumDefinition  -0个或1个
classDefinition | interfaceDefinition | enumDefinition
  • 默认已导入java.lang包,不需要显式import
  • 常用Java包
java.lang:核心类,如:String、Math、System和Tread等
java.util:大量工具类/接口和集合框架类/接口,如:Arrays和List、Set等
java.net:网络编程相关的类/接口
java.io:输入/输出编程相关的类/接口
java.text:格式化相关的类
java.sql进行JDBC数据库编程的相关类/接口
5、构造器
  • 构造器最大的用处就是在创建对象时执行初始化,是创建对象的重要途径(即使使用工厂模式、反射等方式创建对象,其实质依然是依赖于构造器),Java类必须包含一个或一个以上的构造器
  • 在构造器中调用其他构造器要使用this关键字,this(name,color)
6、继承
  • 子类不能获得父类的构造器
  • Java只有一个直接父类,但可以有无限个间接父类
  • 子类包含与父类同名方法的现象被称为方法重写(Override),也叫覆盖
  • 重写要遵循“两同两小一大“规则
    两同:方法名相同,形参列表相等
    两小:子类方法返回值类型应比父类返回值类型更小或者相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等
    一大:子类方法的访问权限应比父类方法的访问权限更大或相等
  • 覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,必须同类
  • 当子类覆盖了父类方法后,子类的对象将无法访问父类中被覆盖的方法,但可以在方法中调用父类中被覆盖的方法,使用super(实例方法)或父类类名(类方法)
  • 当父类的方法用private修饰时,子类无法覆盖,即使子类定义一样的方法,也不属于覆盖
  • 子类定义一个与父类方法有相同的方法名,但参数列表不同的方法,就会形成父类方法和子类方法的重载
  • 子类查找变量的顺序:
    局部变量
    成员变量
    父类的成员变量
    java.lang.Object类
  • 当程序创建一个子类对象时,系统不仅会为该类中定义的实例变量分配内存,也会为它从父类继承得到的所有实例变量分配内存,即使子类定义与父类中同名的实例变量。
  • 当系统创建对象F时,如果该类有两个父类(直接父类A和间接父类B),假设F有两个实例变量,A有两个实例变量,B有三个实例变量,那么F对象将会保存2+3+2个实例变量
7、多态
  • Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定,如Person person = new girl();
  • 如果编译时类型和运行时类型不一致,就可能出现多态。
  • 多态:相同类型的变量、调用同一个方法时呈现出多种不同的行为特征
  • instanceof:判断前面对象是否是后面的类,或者其子类、实现类的实例,如果是返回true,否则返回false
8、继承与组合
  • 继承是实现类复用的重要手段,但继承会破坏封装。而组合方式实现类复用则能提供更好的封装性
  • 为了保证父类有良好的封装性,设计父类通常应遵循如下原则:
    尽量隐藏父类的内部数据,把父类的所有成员变量都设置成private访问类型,不要让子类直接访问父类的成员变量
    不要让子类可以随意访问、修改父类的方法,父类中的工具方法,应该使用private修饰,让子类无法访问;需要被外部类调用的方法,但又不希望被子类重写,可以使用public final修饰;只希望某个方法被子类重写而不希望被其它类自由访问,可以使用protected来修饰
    尽量不要在父类构造器中调用将要被子类重写的方法,否则可能会造成报错,父类构造器中调用被子类重写的方法时,是直接调用子类的方法,如果方法中含有子类的实例编程时,有可能会报空指针异常
  • 使用继承的条件:
    子类需要额外增加属性,而不仅仅是属性值的改变,如:Student需要grade属性,而Person不一定需要
    子类需要增加自己独有的行为方式,包括增加新方法或重写父类的方法,如:Teacher需要Teaching方法,而Person不一定需要
  • 继承要表达的是一种(is-a)的关系,而组合表达的是(has-a)的关系
    Student之于Person用继承
    Arm之于Person用组合
9、初始化块
  • 初始化块是构造器的补充,初始化块总是在构造器执行之前执行,实际上编译后的代码不存在初始化块,而会还原到每个构造器中,且位于构造器所有代码的前面
  • 静态初始化块也叫类初始化块,先于初始化块运行
  • 如果两个构造器中有相同的初始化代码,且这些初始化代码无须接收参数,就可以把它们放在初始化块中定义,提高代码复用,提高应用的可维护性
10、包装类
  • 包装类的比较需要使用compare(val1,val2)来进行
Boolean.compare(true,false)输出1
Boolean.compare(true,true)输出0
Boolean.compare(false,true)输出-1
  • 包装类的缓存有限,-128~127
Integer ina = 2;
Integer inb = 2;
ina == inb 输出true
Integer biga = 128;
Integer bigb = 128;
biga == bigb输出false
  • 因为包装类是引用类型,只有包装类指向同一个引用时以下才相等
new Integer(2) == new Integer(2)
11、 ==和equals方法
  • 除基本类型外,只有引用对象相同==才返回true,比对内容是否相等应当使用equals
  • 常量池专门用于管理在编译时被确定并保存在已编译的.class文件中的一些数据,包括关于类、方法、接口的常量,还包括字符串常量
  • String str1 = "hello"与String str2 = new String("hello")的区别
    前者称为直接量,会保存在常量池,并不会产生多个副本,所以用==比对的时候,返回true
    后者是运行时创建出来的,被保存在堆内存中,不会放入常量池,所以用==比对的时候,返回false
String s1 = "疯狂Java"String s2 = "疯狂";
String s3 = "Java";
String s4 = "疯狂" + "Java";
String s5 = s2 + s3;
s1 == s4; //返回true
s1 == s5; //返回false,因为s5是运行时确定
  • 对于对象而言,使用equals方法与使用==方法一样,都需要指向同一个对象才会返回true
  • 比较两个对象需要重写equals方法
public boolean equals(Object obj){
    if(this == obj){
        return true
    }else if(obj != null && obj.getClass == Person.class){
        Person p = (Person)obj;
        if(this.getId.equals(p.getId)){
            return true;
        }
    }
}
12、类成员
  • Java类里只能包含成员变量、方法、构造器、初始化块、内部类(包括接口、枚举)5种成员,以static来修饰的成员就是类成员(构造器除外),类成员属于整个类,而不属于单个对象(即使new的对象=null,也可以正常调用)
  • 单例类
    如果一个类始终只能创建一个实例,则这个类被称为单例类
    第一:构造器使用private修饰,从而把所有构造器隐藏起来
    第二:需要提供一个public方法作为该类的访问点,且方法必须使用static修饰,因为调用该方法前还不存在对象,只能是类方法
    第三:还必须缓存已经创建的对象,保证只创建一个对象,所以需要使用static成员变量
class Singleton{
    private static Singleton instance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton()
        }
        return instance;
    }
}
13、final修饰符
  • final修饰的变量不可被改变,一旦获得了初始值,该final变量的值就不能被重新赋值
  • 与普通成员变量不同,final修饰的成员变量必须由程序员显式地指定初始值,否则不通过编译:
    类变量:必须在静态初始化块中指定初始值或声明类变量时指定初始值,而且只能在两个地方的其中之一指定
    实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定
    如果以上不指定,此后该变量将一直是系统默认分配的0、false、null或’\u0000’
  • 系统不会对局部变量进行初始化,局部变量必须由程序员显式初始化,final修饰的局部变量在定义时没有指定默认值,则可以在后面代码中对该final变量赋初始值,但只能赋值一次,不能重复;如果已经指定默认值,则后面代码中不能再赋值。
  • final修饰基本类型变量,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final只保证这个引用类型变量所引用的地址不会改变,但这个对象完全可以改变。
final Person p = new Person(45);
正确:p.setAge(23);
错误:p = null
  • 当定义final变量时就为该变量指定了初始值,而且该初始值可以在编译时就确定下来,那么这个final变量本质上就是一个“宏变量”
  • 当父类方法使用public final修饰时,子类重写该方法会出现编译时错误,原因是final方法不允许子类重写;但父类方法使用private final修饰时,子类可以重写该方法(其实不是重写,只是定义了一个新的方法)
  • 当子类继承父类时,将可以访问到父类内部数据,并可以通过重写父类方法来改变父类方法的实现细节,这可能导致一些不安全的因素。为了保证这个类不可被继承,可以使用final修饰这个类
14、不可变类(创建该类的实例后,该实例的实例变量是不可改变的)
  • 创建了该类的实例后,该实例的实例变量不可改变,成为不可变类
  • 不可变类遵守的规则:
    使用private和final修饰符来修饰该类的成员变量
    提供带参数构造器,用于根据传入参数来初始化类里的成员变量
    仅提供getter方法,不系统setter方法
    如果有必要,重写hashCode()和equals()方法
public class Address {
    private final String detail;
    private final String postCode;
    public Address() {
        this.detail = "";
        this.postCode = "";
    }
    public Address(String detail, String postCode) {
        this.detail = detail;
        this.postCode = postCode;
    }
    public String getDetail() {
        return detail;
    }
    public String getPostCode() {
        return postCode;
    }
    @Override
    public int hashCode() {
        return detail.hashCode() + postCode.hashCode() * 31;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj != null && obj.getClass() == Address.class) {
            Address ad = (Address) obj;
            if (this.getDetail().equals(ad.getDetail())) {
                return true;
            }
        }
        return super.equals(obj);
    }
}
15、抽象类
  • 抽象类与抽象方法的规则:
    抽象类和抽象方法必须使用abstract修饰符来修饰,抽象方法不能有方法体
    抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例
    抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)5种成分
    抽象类的构造器不能用于创建实例,主要是被用于被子类调用
    含有抽象方法的类只能被定义成抽象类
    抽象类可以不含有抽象方法,但即使没有抽象方法的抽象类也不能创建实例
  • 当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类重写
  • final修饰的类不能被继承,final修饰的方法不能被重写,所以final和abstract永远不能同时使用
  • 由于抽象方法没有方法体,所以abstract也不能与static同时使用
  • 抽象方法必须被其子类重写才有意义,所以abstract也不能与private同时使用
  • 抽象类的作用
    抽象类是从多个具体类中抽象出来的父类,具有更高层次的抽象
    从多个具有相同特征的类中抽象出一个类,作为子类的模版,从而避免了子类设计的随意性
    子类在抽象类的基础上进行扩展、改造,但子类总体会大致保留抽象类的行为方式
16、接口(interface)

特殊的抽象类,不包含普通方法,接口里的所有方法都是抽象的
- 接口定义的是多个类共同的公共行为规范,这些行为是与外部交流的通道,意味着接口里通常是定义一组公用方法
- 接口的基本语法

[修饰符]interface 接口名 extends 父接口1,父接口2...{
    零个到多个常量定义
    零个到多个抽象方法定义
    零个到多个内部类、接口、枚举定义
    零个到多个默认方法或类方法定义(Java- 
}
  • 接口定义的是一种规范,接口不能包含构造器和初始化块定义
  • 接口里可以包含成员变量(只能是静态常量)、方法(只能是抽象实例方法、类方法和默认方法)、内部类(包含内部接口、枚举)定义
  • 在接口中定义的成员变量,无论是否使用public static final修饰符,接口都总是使用这三个修饰符修饰
  • 接口里没有构造器和初始化块,因此接口里定义的成员变量只能在定义时指定默认值
  • 接口里的普通方法不管是否使用public abstract修饰,接口总是使用public abstract来修饰
  • 接口里的普通方法不能有方法体,但类方法、默认方法都必须有方法体
  • 接口里定义的内部类、内部接口、内部枚举默认都采用public static来修饰,不管是否显式写出
  • Java8默认方法使用default来修饰,默认是public,不管是否显式写出(不能用static修饰)
  • Java8允许在接口中定义类方法,类方法必须用static修饰,不能与default同时使用,且默认一顶是public的
  • public接口的类名与文件名必须相同
  • 接口支持多继承,子接口继承父接口,将会获得父接口里定义的所有抽象方法、常量
  • 接口的主要用途
    定义变量,也可以用于进行强制转换
    调用接口中定义的常量
    被其他类实现
  • 接口和抽象类相似之处:
    都不能被实例化,都位于继承树的顶端,用于被其它类实现和继承
    都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法
  • 接口和抽象类的不同之处:
    接口体现一种规范,一般不能随意修改,修改后对其它类影响很大
    抽象类所体现的是一种模版式设计,是系统实现过程的中间产品
    接口里只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类则完全可以包含普通方法
    接口里不能定义静态方法;抽象类里可以定义静态方法
    接口里只能定义静态常量,不能定义普通成员变量;抽象类则两者都可以定义
    接口里不包含构造器;抽象类里可以包含构造器,其构造器不是用于创建对象,而是让其子类调用这些构造器来完成抽象类的初始化操作
    接口里不能包含初始化块;抽象类则可以
    一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足
  • 接口体现的是一种规范和实现分离的设计哲学,充分利用接口可以极好地降低程序各模块之间的耦合,从而提高系统的可扩展性和可维护性
  • 简单工厂模式
    简单来说就是用接口替代实现类,用实现类去实现,称为接口的引用,当后续要更换实例是,仅仅只修改工厂类即可,而无须修改大量的类
    接口已经将需要用到的规范(方法)全部定义好,实现类实现接口并实现抽象方法,所以无论谁去实现,只要符合接口的规范即可
public class OutputFactory{
    public Output getOutput(){
        // 下面既可以是Printer也可以是PrinterBetter,只要实现了Output接口即可
        return new Printer();
    }
}
  • 命令模式
    某个方法需要完成某一个行为,但这个行为的具体实现无法确定,必须等到执行该方法是才能确定,叫做命令模式
    实际上命令模式就是将接口作为参数来传递给方法,在方法体中调用接口的方法,当调用该方法时,传递进去的是不同的接口实现类
public interface Command{
    void process(int[] target){
    }
    public class ProcessArray{
        public void process(int[] target,Command cmd){
        cmd.process(target);
    }
    public static void main(String[] args){
        ProcessArray pa = new ProcessArray();
        int[] target = {2,4,6,8};
        pa.process(target,new PrintCommand());
        pa.process(target,new AddCommand())
    }
}
17、内部类
  • 把一个类放在另一个类的内部定义,这个定在在其他类内部的类被称为内部类,包含内部类的类称为外部类
  • 内部类的作用
    提供更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包的其它类访问该类。如:CowLeg之于Cow,离开了Cow就没有意义
    内部类成员可以直接访问外部类的私有数据
    匿名内部类适合于创建那些仅仅需要一次使用的类
  • 内部类比外部类可以多使用三个修饰符:private、protected、static,非静态内部类不能拥有静态成员
  • 非静态内部类
    没有用static修饰的内部类叫非静态内部类
    当在非静态内部类的方法内访问某个变量时,查找顺序是:本方法内->内部类成员变量->外部类成员变量
    若出现同名情况,访问内部类成员变量可以使用:this.变量名,访问外部类成员变量可以使用:外部类.this.变量名
    内部类可以访问外部类的成员变量,private修饰的也可以,但外部类就不能直接访问内部类的成员变量,需要通过创建非静态内部类对象来调用访问其实例成员变量
  • 静态内部类
    用static来修饰的内部类叫做静态内部类
    静态内部类可以包含静态成员,也可以包含非静态成员
    接口里定的内部类默认使用public static修饰
  • 使用内部类
    在外部类中使用内部类与普通类无差别
    在外部类以外使用非静态内部类
    new OuterClass().new InnerClass()
    在外部类以外使用静态内部类
    new OuterClass().InnerClass();
  • 把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类仅在方法里有效,不能使用访问控制符和static修饰符
  • 匿名内部类
    匿名内部类适合创建那种只需要一次使用的类
new实现接口() | 父类构造器(实参列表){
    类体部分
}
  • 匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类或实现一个接口
    规则:
    匿名内部类不能是抽象类,因为创建时系统会创建对象
    匿名内部类不能定义构造器,因为没有类名,但可以定义初始化块
    创建匿名内部类时,必须实现接口或抽象父类里的所有抽象方法,也允许重写父类中的普通方法
    Java8开始,允许局部内部类、匿名内部类访问的局部变量不使用final修饰,但系统默认还是带有final,因此还是不能重新对变量赋值
  • Lambda表达式
    Java8的新特性,主要作用就是代替匿名内部类的繁琐语法
    Lambda表达式由三部分组成:
    形参列表、箭头、代码块
    Lamba表达式的两个限制:
    目标类型必须是明确的函数式接口
    只能实现一个方法
    函数式接口代表只包含一个抽象方法的接口,函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法
  • Lambda表达式实例
// 引用类方法:
interface Converter{
    Integer convert(String from)
}
Converter converter1 = from -> Integer.valueOf(from);
Integer val = converter1.convert("99");
System.out.println(val);
可以写成:
Converter converter1 = Integer::valueOf;

// 引用特定对象的实例方法
Converter converter2 = from -> "fkit.org".indexOf(from);
Integer value = converter2.convert("it");
System.out.println(value);
可以写成:
Converter converter1 = "fkit.org"::indexOf;

// 引用某类对象的实例方法
interface MyTest{
    String text(String a,int b,int c)
}
MyTest mt = (a,b,c) -> a.substring(b,c)
String str = mt.test("java hello my word",2,9);
可以写成:
MyTest mt = String::substring

// 引用构造器
interface YourTest{
    JFrame win(String title);
}
YourTest yt = (String a) -> new JFrame(a);
JFrame jf = yt.win("my win");
可以写成:
YourTest yt = JFrame::new;
  • Lambda表达式与匿名内部类的联系与区别
    • 联系:
      都可以直接访问final局部变量,以及外部类的成员变量
      都可以直接调用从接口中继承的默认方法
    • 区别:
      匿名内部类可以为任意接口创建实例-不管接口包含多少个抽象方法,只要匿名内部类实现所有抽象方法即可;Lambda表达式只能为函数式接口创建实例
      匿名内部类可以为抽象类甚至普通类创建实例;但Lambda表达式只能为函数式接口创建实例
      匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法;但Lambda表达式代码不允许调用接口中的默认方法
  • Lambda表达式与Arrays
String[] arr1 = new String[]{"java","faka","kkth","sdkjfei"};
Arrays.parallelSort(arr1,(o1,o2)->o1.length()-o2.length());
int[] arr2 = new String[]{12,-3,76,9,0};
// 前一个元素乘以后一个,[12,-36,...]
Arrays.parallelSort(arr2,(left,right)->left*right);
long[] arr3 = new long[5];
// 填充5的倍数
Arrays.parallelSetAll(arr3,operand->operand*5)
18、枚举类
  • 一个类的对象是有限而且固定的,这种实例有限而且固定的类,叫做枚举类
  • 枚举类是一种特殊的类,它可以有自己的成员变量、方法,可以实现一个或者多个接口,可以定义自己的构造器
  • 与普通类的区别:
    枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显式继承其它父类;java.lang.Enum类实现了java.langSerializable和java.lang.Comparable两个接口
    使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类
    枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符,也是默认使用private修饰
    枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例;列出这些实例时,系统会自动添加public static final修饰,无须显式添加
  • values()方法可以遍历所有枚举值
for(SessonEnum s:SeasonEnum.values()){}
  • swicth支持枚举类
int compareTo(E o):对比两个枚举值的顺序
String name():返回实例名称
String toString():同上
int ordinal():返回索引值
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name):用于返回指定枚举类中指定名称的枚举值
Gender g = Enum.valueOf(Gender.class,"FEMALE");

6)将枚举类设计成不可变类

public enum Gender{
    MALE("男"),FEMALE("女");
    private final String name;
    private Gender(String name){
        this.name = name
    }
    private String getName(){
        return this.name;
    }
}
  • 实现接口的枚举类(匿名内部类)
public interface GenderDesc{
    void info();
}
public enum Gender implements GenderDesc{
    MALE("男"){
        public void info(){
            System.out.println("男");
        }
    },
    FEMALE("女"){
        public void info(){
            System.out.println("女");
        }
    };
    private final String name;
    private Gender(String name){
        this.name = name
    }
    private String getName(){
        return this.name;
    }
}
  • 包含抽象方法的枚举类
public enum Operation {
    PLUS{
        public double eval(double x,double y) {
            return x + y;
        }
    },
    MINUS{
        public double eval(double x,double y) {
            return x - y;
        }
    },
    TIMES{
        public double eval(double x,double y) {
            return x * y;
        }
    },
    DIVIDE{
        public double eval(double x,double y) {
            return x / y;
        }
    };
    public abstract double eval(double x,double y);
    public static void main(String[] args) {
        System.out.println(Operation.PLUS.eval(3, 4));
        System.out.println(Operation.MINUS.eval(3, 4));
        System.out.println(Operation.TIMES.eval(3, 4));
        System.out.println(Operation.DIVIDE.eval(3, 4));
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值