1. 接口的概念
接口不是类,是对类的一组需求描述,是抽象规范。所以接口中不能含有实例域(可以包含常量),在Java SE 8 之前,也不能在接口中实现方法。提供实例域和方法实现的任务应该由实现接口的类来完成。
类实现接口需要如下步骤:
- implements interface
- 对接口中所有方法进行定义。
接口中所有方法自动属于public,在实现接口时,必须把方法声明为 public 。
类似于抽象类,尽管不能构造接口的对象,但是可以声明接口的引用,指向实现了该接口的类的实例。因为java不支持多继承,所以利用接口可以提供多继承的大多数优势,同时避免多继承的复杂性和低效率。
Java抽象类与接口的区别:http://www.importnew.com/12399.html
2. 默认方法
可以为接口方法的提供一个默认实现,必须用 default 修饰符标记这样一个方法。
public interface Comparable<T>{ default int compareTo(T other) {return 0;} }
3. 默认方法冲突
如果在一个接口中将一个方法定义为默认方法,同时在父类或另一个接口中定义了同样的方法,解决冲突的规则如下:
- 父类优先
- 接口冲突
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,取消对外部类的引用。