Java基础(五)
一、内容概述
1、接口:主要用来描述类具有什么功能,而并不给出每个功能的具体实现,一个类可以实现一个或多个接口。
2、lambda表达式:是一种表示可以在将来某个时间点执行的代码块的简洁方法。使用lambda表达式,可以用一种精巧而简洁的方式表示回调或变量行为的代码。
3、内部类:内部类定义在另外一个类的内部,其中的方法可以访问包含它们的外部类的域。内部类技术主要用于设计具有相互协作关系的类集合。
4、代理:是一种实现任意接口的对象。代理是一种非常专业的构造工具,它可以用来构建系统级的工具。
二、接口
接口中的所有方法自动的属于public,不过在实现接口时,必须把方法声明为public。
接口中还可以定义常量,接口中的域将被自动设为public static final。
接口中决不能含有实例域。在Java SE 8之前,也不能在接口中实现方法。
提供实例域和方法实现的任务应该由实现接口的那个类来完成。因此,接口也可以被视为没有实例域的抽象类。
类实现接口的步骤:
1、将类声明为实现给定的接口。
2、对接口中的所有方法进行定义。
要将类声明为实现某个接口,需要使用关键字implements。
接口不是类,不能使用new1运算符实例化一个接口,但却能声明接口的变量,接口变量必须引用实现了接口的类对象。
可以使用instance检查一个对象是否实现了某个特定的接口。
接口可以提供多重继承的大多数好处,同时还能避免多重继承的复杂性和低效性。
在Java SE 8中,允许在接口中增加静态方法。
可以为借口方法提供一个默认实现,必须用default修饰符标记这样一个方法。
默认方法的一个重要用法是“接口演化”。
在接口中定义了一个默认方法,在超类或者另一个接口中定义了同样的方法,产生冲突的解决规则:
1、超类优先:如果超类提供了一个具体方法,同名且有相同的参数类型的默认方法会被忽略。
2、接口冲突。如果一个超接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型(不论是否是默认参数)相同的方法,必须覆盖这个方法来解决冲突。
三、Lambda表达式
Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。
Lambda表达式的形式:参数,箭头(→)以及一个表达式。(参数)→{表达式}
对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个Lambda表达式,这种接口称为函数式接口。
要用::操作符分隔方法名和对象或类名,主要有3种情况:
1、object::instanceMethod
2、Class::staticMethod
3、Class::instanceMethod
在前两种情况中,方法引用等价于提供方法参数的lambda表达式。对于第三种情况,第一个参数会成为方法的目标。
在Java中,lambda表达式就是闭包。
Lambda表达式中捕获的变量必须实际上是最终变量(这个变量初始化之后就不会再为它赋新值)。
Lambda表达式的体与嵌套块有相同的作用域。
使用Lambda表达式的重点是延迟执行。延迟执行的原因有:
1、在一个单独的线程中运行代码。
2、多次运行代码。
3、在算法的适当位置运行代码(例如:排序中的比较操作)。
4、发生某种情况时执行代码(例如:点击了一个按钮,数据到达)。
5、只有必要时才运行代码。
四、内部类
内部类:是定义在另一个类中的类。
主要原因:
1、内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。
2、内部类可以对同一个包中的其他类隐藏起来。
3、当想要定一个一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。
内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。
表达式OuterClass.this表示外围类引用。
内部类中声明所有静态域都必须是final。内部类不能有static方法。
局部类不能用public或private访问说明符进行声明,它的作用域被限定在声明这局部类的块中。局部类有一个优势,即对外部世界可以完全隐藏起来。
局部类同时可以访问局部变量,不过局部变量必须事实为final。
匿名内部类:创建类的一个对象而没有命名。
在内部类不需要访问外围类对象的时候,应该使用静态内部类,与常规内部类不同,静态内部类可以有静态域和方法。
五、代理
利用代理可以在运行时创建一个实现了一组给定接口的新类。
要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法,这个方法有三个:
1、一个类加载器。作为Java安全模型的一部分,对于系统类和从因特网上下载下来的类,可以使用不同的类加载器。
2、一个Class对象数组,每个元素都是需要实现的接口。
3、一个调用处理器。
代理类的特性:
1、所有的代理类都扩展了Proxy类。一个代理类只有一个实例域——调用处理器,它定义在Proxy的超类中。
2、所有的代理类都覆盖了Object类中的toString,equals和hashCode。
3、没有定义代理类的名字,Sun虚拟机中的Proxy类将生成一个以字符串$Proxy开头的类名。
4、对于特定的类加载器和预设的一组接口来说,只能有一个代理类。
5、代理类一定是public和final。
6、可以通过调用Proxy类中的isProxyClass方法检测一个特定的Class对象是否代表一个代理类。