接口

1 接口不是类,而是对类的一组需求描述,一个类可以实现多个接口
任何实现接口的类 都需要 实现该接口的所有方法,如 comparable 接口

  1. public interface Comparable<T> {
  2. int compareTo(T Other);
  3. }

2 接口中的所有方法自动地属于public,所以接口内不需要标了
3 接口中不能含有实例域,可以声明常量,接口中的域将被自动设为public static final,接口不能被实例化
4 有些接口只定义了常量,而没有定义方法,实现这些接口 可以直接在方法中引用 常量 而不需加前缀 ,但不建议这样用
5 可以用 instanceOf 判断对象是否实现了 某接口
6 接口也可以被扩展 interface A extends B{}
7 Jdk8 后接口内 可以定义 静态方法
8 可以为接口方法 定义默认实现 需要用 default 修饰,默认方法内 可以调用其他非默认的方法
9 如果超类方法 或者 接口的默认方法实现 冲突 则(1 超类方法优先,2 接口冲突必须 手动覆盖默认实现)

接口示例

1 Java 通过传递 类对象 ,并调用该类的方法 实现 回调 ,形参有接口就行,实现了接口的类对象就可以传入
2 Arrays.sort方法还有第二个版本,有一个数组和一个比较器(comparator)作为参数 ,比较器是实现了Comparator 接口的类实例

  1. public interface Comparator<T>{
  2. int compare(T First, T Second);
  3. }
  4. compare 方法要在比较器上调用 而非排序的对象本身调用
  5. compare 方法并非一个静态方法 所以得创建实例调用 尽管该实例没有数据

3 cloneable 提供了一个安全的clone方法
4 clone方法是Object的一个protected方法,这说明你的代码不能直接调用这个方法。只有Employee类可以克隆Employee对象
5 Object 实现 clone方法 是逐个对象拷贝 但如果对象包含 引用类型的域 clone后依旧会 共享一些信息,默认的clone都是浅拷贝
6 如果共享的引用对象 是不可变的 就没有危险 如 String localDate
7 如果确实要使用clone方法,就必须使用cloneable接口,该接口并不指定一个方法,而是标记
8 标记接口不包含任何方法;它唯一的作用就是允许在类型查询中使用instanceof
9 使用clone方法的时候 需要子类覆写clone方法,并声明为 public ,如果默认的满足要求,就在其中调用(返回类型)super.clone() 即可,默认的如果不满足要求,就要自定义clone方法了
10 如果你的客户需要建立深拷贝,可能就需要实现clone方法
11 所有的数组对象都有一个public 的clone方法,可以调用来进行拷贝

lambda表达式

1 java通过lambda表达式 完成 传递代码块的功能,即传递函数的功能
2 (String s1,String s2)-> s1.length - s2.length; 箭头后 可以用大括号包裹代码块 ,不用大括号可以省略return ,没有参数的时候小括号也不能省略
可以忽略小括号内的 参数类型,编译器会自动推断 (s1, s2)-> s1.length() - s2.length()
无需指定lambda的返回类型,也会自动推断
3 最好把lambda表达式看作是一个函数,而不是一个对象,更加高效
4 对于只有一个抽象方法的接口,如comparator,这种接口就是函数式接口,需要这种接口的对象时,就可以提供一个lambda表达式,lambda表达式与之是兼容的
5 通过函数式 接口 来传递 lambda表达式
6 java.util.function包中定义了很多非常通用的函数式接口,可以用于保存一些通用的Lambda表达式,如 BiFunction,和Predicate
ArrayList 的 removeIf 就需要 Predicate 接口 返回一个boolean值
7 方法引用 可以通过引用方法 来 实现函数式接口 ,如 Object::intanceMethod / Class::Static Method / Class::intanceMethod
前二者 相当于 调用了 x -> method (x) , 第三个 缺了 实例对象,第一个参数将会充当实例 对象
8 方法引用不能独立存在,总是会转换为函数式接口的实例
9 可以使用this 和 super , 如 this::method super::method 相当于object ::instanceMethod
10 可以使用构造器方法引用,Class::new 相当于调用Class::staticMethod 并返回类实例
11 显然 方法引用 都不需要 括号
12 数组类型的构造器引用 int[]::new 参数是 数组长度
13 lambda 表达式 包含三部分, 一个是 参数, 一个是代码块 , 还有 自由变量,lambda 表达式 会保存该自由变量的值,被称作 捕获
这个特性 被称作 闭包
14 被捕获的值 必须是 被明确定义的 ,并且 代码块内部 不能 改变 被捕获变量的 值,因为并发的时候会不安全
15 lambda 使用 this 的时候 指的是 创建该lambda 的 实例对象,而非 函数式接口的实例对象
16 使用lambda表达式的重点是延迟执行,如(多次运行,开新线程运行,算法的适当位置运行,某些情况执行,必要时运行)
17 常用的 通用函数式接口有
image.png
18 Comparator接口包含很多方便的静态方法来创建比较器
静态comparing方法取一个“键提取器”函数,它将类型T映射为一个可比较的类型(如String)
Arrays.sort(people, Comparator.comparing(Person::getName));
19 要让比较器逆序比较,可以使用reversed实例方法

内部类

1 使用内部类的场合有
内部类可以访问定义该类的所有数据 包括私有数据
内部类可以对同一个包中的其他类隐藏起来
2 对于定义内部类后,并不意味着一个外围类实例 就有 一个内部类实例 ,内部类由 外围类的方法 构造
所有的内部类实例 都可以访问 构造该内部类实例的 外围类 实例 的 私有数据
3 如果内部类声明为public 在外围内之外也可以访问,通过OuterClass.InnerClass 来访问内部类
如果为 private 只能外围类内可见, 如果为protect 子类可见 默认 是 包可见

4 如果只有一个方法 用到了 内部类 ,可以将内部类定义在该方法中, 作为局部内部类, 这样其他方法就看不到了 ,所以也不需要 public 和private修饰了
5 使用了 局部类之后, 局部类 还可以 访问到 该方法 的 局部变量
6 将局部内部类的使用再深入一步。假如只创建这个类的一个对象,就不必命名了,即为 匿名内部类
格式为 new SuperType(构造参数){ } 其中 superType可以是类, 这样匿名内部类就扩展他 , 也可以是接口, 匿名内部类 就实现该接口

  1. public void start(boolean beep){
  2. A a = new A(){
  3. public void action(){
  4. if(beep){...}
  5. }
  6. }
  7. a...
  8. }

7 利用内部类的语法 可以实现 匿名的ArrayList 当只需要一次该List的时候 就可以使用

  1. action( new ArrayList<String>(){{add("A");add("B")}})

外面的大括号构建ArrayList 的匿名子类,内部括号 则是一个 对象构造块
但使用匿名子类 ,equals中的getClass == other.getClass 会失败
8 有时候使用内部类 只需要隐藏在外围类的内部 而不需要 访问外围类的 数据,就可以定义一个静态的内部类,将其声明为 static 即可
如果在外围类的静态函数中 初始化了 内部类, 则该内部类就必须是 静态内部类了

代理Proxy

1 利用代理可以在运行时创建一个实现了一组给定接口的新类,用于在编译器期间无法确定 实现 哪个接口的时候使用
由于 不能用反射 实例化 一个接口,所以要在运行的时候定义一个新类 实现该接口 ,随后 实例化该 新类
。。。