文章目录
- CH6.接口、lambda表达式与内部类
- 1.接口基本
- 2.常用接口
- 3.lambda表达式
- 4.内部类
- 5.服务加载器与代理
前章: 第三章~第五章的学习笔记
CH6.接口、lambda表达式与内部类
1.接口基本
- 接口基本——interface声明,方法无需指明public(默认都是public),继承时使用implements关键字,接口支持多继承。接口可以看做一个c++中纯虚的抽象基类,它代表的含义是:继承自这个接口的类应该具有某些行为(接口的函数),而不在乎具体这些行为怎么实现的
- 接口中不能包含实例字段,但是可以包含常量(字段也都是默认public)
- 接口可以继承接口
- 接口中同样可以定义静态方法、私有方法(不知道为什么这么做)
- 接口的方法可以有默认实现,需要有关键字default——可以用于接口演化,比如接口新增一个方法,原来实现这个接口的类就编不过了,如果新增的方法加default给一个默认的实现,则原来的代码可以编过(会使用这个新方法的默认实现)
- 同名函数冲突——类与接口中有同名函数,同时继承自该类与该接口的类会“优先类”;接口与接口有同名函数,看继承者实现谁,如果两个接口有一个有默认实现,继承者必须定义同名函数,可以通过
接口名.super.同名方法
指定调谁的实现=>因为类优先,super
含义就是父类(因为单继承,父类只可能有一个),而父接口应该用接口名.super
代表 - 一种特殊的接口,标记接口,没有任何方法的接口,只是作为标记作用,使其子类可以使用instanceof判定是否有该标记,如
cloneable
就是标记接口——每个类继承自Object,都有Object.clone方法,但是这个方法是protected的,无法使用,需要在子类中声明为public,并调用super.clone的实现;但是这样会抛出CloneNotSupportedException
,这是因为Object.clone的实现中判断了this instanceof Cloneable
,不是的话会抛出异常 - 匿名接口——可以直接new一个接口,然后在
{}
中写实现,这个接口实现类是匿名的,无法再生成该类的一个实例
2.常用接口
Comparable<Type>
或者Comparable
——Array的比较要求比较的元素有实现该接口(这也是函数式接口)- Cloneable——可克隆的接口
- Predicate——专门用来接受判断lambda表达式的函数式接口
- Supplier——供应者接口(函数式接口,有一个
T get()
函数),用于懒加载,如Object.requireNonNullElseGet(T,Supplier<T>)
可以在传入T类型的参数为null时利用Supplier生成一个默认的实例(为null的情况可能比较少,所以传入一个将来要调的方法而不是传入一个实例,以实现懒计算 Comparator<T>
接口——用于比较,其中的一些静态/成员方法用于生成Comparator
,如comparing
,thenComparing
,naturalOrdr
,reverOrder
,reversed
等;额外的一个小点,Comparator
中有两个抽象函数但是依然是函数式接口,这是因为,其中一个是从Object
继承来的重写的equals
函数(接口也继承自Object
类)
3.lambda表达式
-
lambda表达式基本:
(参数列表)->{函数体}
——当参数列表类型可以由接收的函数式接口推断出的话,可以省略类型;在此基础上如果还只有一个参数,括号也可以省略;如果函数体只有一个语句,可以省略{} -
与函数式接口的兼容:lambda表达式可以赋值给一个函数式接口(什么叫函数式接口——只有一个抽象函数的接口),与函数式接口完全兼容大大拓展了lambda表达式的适用范围
-
方法引用,等价于对应形式的lambda表达式,也可以用函数式接口对象接收,三种形式:
- object::instanceMethod==>(参数列表)->object.instanceMethod(参数列表);唯一不同的是方法引用会马上检测object是否为null,而对应的lambda表达式会等到调用时才检测object是否为null
- Class::instanceMethod==>(Class类参数 self,参数列表)->self.instanceMethod(参数列表);
- Class::staticMethod==>(参数列表)->Class.staticMethod(参数列表);
-
构造器引用——与方法引用一样,只不过方法名为new,如object::new,以及数组形式的构造器object[]::new;调用的构造器重载版本根据具体场景推断
-
@FunctionalInterface注解可以表明这个接口是函数式接口,在向该接口增加抽象方法时会报错,且javadoc中会标明这个接口是函数式接口
-
lambda表达式的捕获——无需像c++一样写捕获列表,直接捕获lambda表达式所在作用于变量即可(值传递),称为自由变量,同时无法捕捉会变的变量
4.内部类
- 内部类——与c++的内部类一样,不过不同的是,
- java内部类初始化的时候会默认传入外部类的this指针,使其可以访问创建它的外部类对象
- java内部类在外部类外面创建的话得加外部类的对象,比如
outClassObj.new InnerClass()
,而不能直接new OutClass.InnerClass
- 局部内部类——在函数内定义的类;除了像一般内部类一样访问外部类的数据,还可以访问函数的局部变量(像lambda表达式一样捕获,只能捕获事实不变量)
- 匿名内部类——如匿名接口,实际也可以定义继承自普通(非接口)类的匿名子类;匿名内部类没有构造函数,可以通过初始化块来初始化数据–>引申一个双括号初始化技巧
- 静态内部类——加static标识
class OuterClass{
public static class InnerClass{
...
}
}
- 静态内部类才与c++中的内部类相当;静态内部类不像一般内部类,创建的时候不会传入外部类的对象指针;静态内部类也成为嵌套类
- 构造时可以直接
new OuterClass.InnerClass()
构造 - 与常规内部类不同,静态内部类可以有静态字段和方法
- 接口内部声明的内部类自动是static和public
5.服务加载器与代理
略。看不懂,以后有机会再拜读