参考:Java核心技术 卷I 基础知识
接口,主要用来描述类具有什么功能,而并不给出每个功能的具体实现。一个类可以实现一个或多个接口,并在需要接口的地方,随时使用实现了相应接口的对象。接口不是类,是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。
接口中的所有方法自动地属于public。
接口中可以定义常量。接口不能包含实例域。
提供实例域和方法实现的任务应该由实现接口的那个类来完成。因此,可以将接口看成是没有实例域的抽象类。
接口不是类,尤其不能使用new运算符实例化一个接口。
不能构造接口的对象,但可以声明接口的变量。
接口变量必须引用实现了接口的类对象。
接口中的域被自动设为public static final。
如果先在一个接口中将一个方法定义为默认方法,然后又在超类或另一个接口中定义了同样的方法。Java规则如下:
(1)超类有限。如果超类提供了一个具体方法,同名且有相同的参数类型的默认方法会被忽略。
(2)接口冲突。如果一个超接口提供了一个默认方法,另一个接口提供了同名且参数类型(不论是否默认参数)相同的方法,必须覆盖这个方法来解决冲突。
回调是一种常见的程序设计模式。在这种模式中,可以指出某个特定事件发生时应该采取的动作。
lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。
lambda表达式由3个部分:
规则:lambda表达式中捕获的变量必须是实际上的最终变量。实际上的最终变量是指这个变量初始化之后就不会再为它赋新值。lamdba表达式与嵌套块有相同的作用域。这里同样适用命名冲突和遮蔽的有关规则。在方法中,不能有两个同名的局部变量,因此,lambda表达式中同样也不能有同名的局部变量。在一个lambda表达式中使用this关键字时,是指创建这个lambda表达式的方法的this参数。
使用lambda表达式的重点是延迟执行。毕竟,如果想要立即执行代码,完全可以直接执行,而无需把它包装在一个lambda表达式中。之所以希望以后再执行代码,这有很多原因:
内部类是定义在另一个类中的类。使用内部类的原因是:
静态内部类,这种内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。为此,可以将内部类声明为static,以便取消产生的引用。
代理
利用代理可以在运行时创建一个实现了一组给定接口的新类。这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。
代理类可以在运行时创建全新的类。这样的代理类能够实现指定的接口。尤其是,它具有下列方法:
然而,不能再运行时定义这些方法的新代码,而是要提供一个调用处理器。调用处理器是实现了InvocationHandler接口的类对象。在这个接口中只有一个方法:invoke。
无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的调用参数。调用处理器必须给出处理带哦用的方法。
创建一个代理对象,需要使用Proxy类的newProxyInstance方法。这个方法有三个参数:
使用代理可能处于很多原因,例如:
代理类是在程序运行过程中创建的。一旦被创建,就变成了常规类,与虚拟机中的任何其他类没有什么区别。
所有的代理类都扩展于Proxy类。一个代理类只有一个实例域--调用处理器,它定义在Proxy的超类中。为了履行代理对象的职责,所需要的任何附加数据都必须存储在调用处理器中。
所有代理类都覆盖了Object类中的toString、equals和hashCode。如同所有的代理方法一样,这些方法仅仅调用了调用处理器的invoke。Object类中的其他方法没有被重新定义。
对于特定的类加载器和预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器和接口数组调用两次newProxyInstance方法的话,那么久只能够得到同一个类的两个对象,也可以利用getProxyClass方法获得这个类。
代理类一定是public和final。如果代理类实现的所有接口都是public,代理类就不属于某个特定的报。否则,所有非公有的接口都必须属于同一个包。
可以通过调用Proxy类中的isProxyClass方法检测一个特定的Class对象是否代表一个代理类。