接口、lambda表达式和内部类
接口
概念
接口中的所有方法默认属于public,在声明方法时,不需要提供关键字public
特性
- 接口不是类,不能使用new运算符实例化
- 可以声明接口的变量,同时变量必须引用一个实现了接口的类对象
- 可以使用instanceof检测一个对象是否实现了某个接口
- 接口中定义变量,默认为public static final
静态方法
java8后,可以在接口中增加静态方法
默认方法
1 2 3 4 5
| public interface Comparable<T> { default int compareTo(T other) { return 0; } }
|
主要用于“接口演化”,如果给接口添加了一个非默认方法,则必须修改接口实现类;如果是默认方法,则不需要修改实现类,同时在实现类调用新增加的方法,将自动调用接口中的默认实现
默认方法冲突
- 超类优先:一个类扩展了一个超类,同时实现了一个接口,并从超类和接口继承了相同的方法
- 接口冲突:一个类实现了两个接口,接口中存在同名的默认方法,则必须在实现类中实现该方法,来解决冲突
lambda表达式
1 2 3 4 5
| (String first, String second) -> first.length() - second.length();
Comparator<String> cmp = (first, second) -> first.length() - second.length();
() -> { for (int i = 100; i >= 0; i--) System.out.println(i);};
|
如果lambda表达式只在某些分支返回一个值,而其它分支不返回值,是不合法的
方法引用
object::instanceMethod - System.out::println等价于x -> System.out.println(x)
Class::staticMethod - Math::pow等价于(x, y) -> Math.pow(x, y)
Class::instanceMethod - String::compareToIgnoreCase等价于(x, y) -> x.compareToIgnoreCase(y)
内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class TalkingClock { private boolean beep; public void start(int interval, final boolean beep) { ActionListener listener = new TimePrinter(this); Timer t = new Timer(interval, listener); t.start(); } class TimePrinter implements ActionListener { private TalkingClock outer; public TimePrinter(TalkingClock outer) { this.outer = outer; } public void actionPerformed(ActionEvent e) { if (outer.beep) { System.out.println("beep"); } } } }
|
这种情况下编译后,会在TalkingClock添加静态方法access$000,对于if(outer.beep)的访问会变为if(TalkingClock.access$000)
1 2 3 4 5 6 7 8 9
| public void start() { class TimePrinter implements ActionListener { public void actionPerformed(ActionEvent e) { if (beep) { System.out.println("beep"); } } } }
|
这种情况下编译后,在生成的TalkingClock$1TimePrinter中会存在val$beep变量,在调用构造函数时,会传入beep,并存储在val$beep中,之后则访问局部变量
1 2 3 4 5 6 7 8 9
| final int[] counter = new int[1]; for (int i = 0; i < dates.length; i++) { dates[i] = new Date() { public int compareTo(Date other) { counter[0]++; return super.compareTo(other); } } }
|
如果想更新一个在封闭作用域中的值,可以采用数组的方式,因为普通的变量必须是final,无法进行更改
匿名内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public void start(int interval, int beep) { ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { if (beep) { System.out.println("beep"); } } }; Timer t = new Timer(interval, listener); t.start(); Timer t = new Timer(interval, event -> { if (beep) { System.out.println("beep"); } }); t.start(); }
|
对于静态方法,如果需要包含当前类的类名,则应该使用如下表达式
1
| new Object(){}.getClass().getEnclosingClass()
|
静态内部类
静态内部类的对象没有对外围类对象的引用特权,其它和普通的内部类一致
代理
使用方式
1 2 3 4 5 6 7 8 9 10 11 12 13
| class TraceHandler implements InvocationHandler { private Object target; public TraceHandler(Object t) { target = t; } public Object invoke(Object proxy, Method m, Object[] args) { return m.invoke(target, args); } } Object value = "test"; InvocationHandler handler = new TraceHandler(value); Class[] interfaces = new Class[] { Comparable.class }; Object proxy = Proxy.nenProxyInstance(null, interfaces, handler);
|
代理类特性
- 所有的代理类都覆盖了Object类中的toString,equals和hashCode方法
- 对于特定的类加载器和接口数组调用两次newProxyInstance方法,只能得到同一个类的两个对象 Class proxyClass = Proxy.getProxyClass(null, interfaces)
- 代理类一定是public和final的