第6章 接口、lambda 表达式与内部类

1. 接口的概念

  接口不是类,是对类的一组需求描述,是抽象规范。所以接口中不能含有实例域(可以包含常量),在Java SE 8 之前,也不能在接口中实现方法。提供实例域和方法实现的任务应该由实现接口的类来完成。

  类实现接口需要如下步骤:

  1. implements interface
  2. 对接口中所有方法进行定义。

  接口中所有方法自动属于public,在实现接口时,必须把方法声明为 public 。

  类似于抽象类,尽管不能构造接口的对象,但是可以声明接口的引用,指向实现了该接口的类的实例。因为java不支持多继承,所以利用接口可以提供多继承的大多数优势,同时避免多继承的复杂性和低效率。

Java抽象类与接口的区别:http://www.importnew.com/12399.html

2. 默认方法

  可以为接口方法的提供一个默认实现,必须用 default 修饰符标记这样一个方法。  

public interface Comparable<T>{

    default int compareTo(T other) {return 0;}
}

 

3. 默认方法冲突

  如果在一个接口中将一个方法定义为默认方法,同时在父类或另一个接口中定义了同样的方法,解决冲突的规则如下:

  1. 父类优先
  2. 接口冲突

4. 对象克隆

  默认的克隆操作是"浅拷贝",并没有克隆对象中引用的其他对象。如果原对象和克隆共享的子对象是不可变对象,则克隆是安全的,反之,需要对每个可变的子对象也进行克隆。

  

int[][] a = {{1},{2},{3}};
int[][] b = a.clone();    // 浅拷贝

a[1][1] = 0;
System.out.println(b[1][1]);  // 输出 0


int[][] c = new int[a.length][a[0].length];

for(int i=0; i< a.length; i++){
    c[i] = a[i].clone();    // 克隆所有子对象,深拷贝
}
a[0][0] = 0;
System.out.println(c[0][0]);    // 输出 1

 

5. lambda表达式

  lambda表达式是一个代码块,以及必须传入代码块的变量规范。

(int a, int b) -> 
    { 
        if(a == b) return 0;
        else if(a < b) return b-a;
        else return a-b;
    }

 

  即使lambda表达式没有参数,仍然要提供括号,就像无参方法一样;如果可以推导出参数类型,则可以忽略其类型;如果方法只有一个参数,而且这个参数的类型可以推导出来,那么可以省略小括号。

  如果一个lambda表达式只在某些分支返回一个值,在另一些分支不返回值,则不合法。

6. 函数式接口

  对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式。这种接口称为函数式接口

7. 内部类

  • 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。
  • 内部类可以对同一包中的其他类隐藏起来。
  • 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。

  内部类的对象总有一个隐式引用,指向创建它的外部类对象。只有内部类可以是私有类,而常规类可以具有包可见行,或公有可见行。

8. 局部内部类

  在一个方法中定义局部类,局部类不能用 private 或 public 访问说明符修饰。它的作用域被限制在声明这个局部类的块中,对外部世界完全隐藏起来,即使声明该局部类的其他代码也不能访问它。但局部类可以访问包含它们的外部类,同时,还可以访问局部变量,不过,那些局部变量必须事实上为 final 。

9. 匿名内部类

new SuperType(construction parameters){
    inner class methods and data
}

 

  其中,SuperType 可以是一个接口,于是内部类就需要实现这个接口。也可以是一个类,于是内部类就需要扩展它。由于构造器的名字必须与类名相同,但匿名内部类没有类名,所以没有构造器方法。取而代之的是,将构造器参数传递给父类构造器。

10. 静态内部类

  将内部类声明为static,取消对外部类的引用。

 

posted @ 2018-03-29 20:45  walker993  阅读(420)  评论(0编辑  收藏  举报