首先
,
介绍一下接口
(
interface
)
技术
,
这种技术主要用来描述类具有什么功能,而并不 给出每个功能的具体实现。
一个类可以实现
(
implement
)—个或多个接口,并在需要接口的地方,
随时使用实现了相应接口的对象
。
了解接口以后
,
再继续介绍而表达式,这是 一种表示可以在将来某个时间点执行的代码块的简洁方法。
使用
lambda
表达式
,
可以用一 种精巧而简洁的方式表示使用回调或变量行为的代码。 接下来,
讨论内部类
(
inner
class
)
机制
。
理论上讲
,
内部类有些复杂
,
内部类定义在另 外一个类的内部,
其中的方法可以访问包含它们的外部类的域
。
内部类技术主要用于设计具 有相互协作关系的类集合。
在本章的最后还将介绍代理
(
proxy
)
,
这是一种实现任意接口的对象
。
代理是一种非常
专业的构造工具
,
它可以用来构建系统级的工具
。
接口
接口概念
在
Java
程序设计语言中
,
接口不是类
,
而是对类的一组需求描述
,
这些类要遵从接口描
述的统一格式进行定义
。
接口中的所有方法自动地属于
public
。
因此
,
在接口中声明方法时
,
不必提供关键字
public
为了让类实现一个接口
,
通常需要下面两个步骤
:
1
)
将类声明为实现给定的接口
。
2
)
对接口中的所有方法进行定义
。
要将类声明为实现某个接口
,
需要使用关键字
implements
:
cl
ass Employee implements Comparable
接口的特性
接口不是类
,
尤其不能使用
new
运算符实例化一个接口
:
x
=
new
Comparable
(
.
.
.
)
;
/
/
ERROR
然而
,
尽管不能构造接口的对象
,
却能声明接口的变量
:
Comparable
x
;
//
OK
接口变量必须弓
I
用实现了接口的类对象
:
x
=
new
Employee
(
. .
.
)
;
/
/
OK
provided
Employee
implements
Comparable
接下来
,
如同使用
instanceof
检查一个对象是否属于某个特定类一样
,
也可以使用
instance
检查一个对象是否实现了某个特定的接口
:
if
(
anObject
instanceof
Comparable
)
{
.
.
.
}
与接口中的方法都自动地被设置为
public
—样,
接口中的域将被自动设为 public static final
。
尽管每个类只能够拥有一个超类
,
但却可以实现多个接口
。这就为定义类的行为提供了
极大的灵活性
。
例如
,
Java
程序设计语言有一个非常重要的内置接口
,
称为
Cloneable
(
将在
6.2
.
3
节中给予详细的讨论
。
)
如果某个类实现了这个
Cloneable
接口
,
Object
类中的
clone
方
法就可以创建类对象的一个拷贝
。
如果希望自己设计的类拥有克隆和比较的能力
,
只要实现
这两个接口就可以了
:
使用逗号将实现的各个接口分隔开
。
class
Employee
implements
Cloneable
,
Comparable
接口与抽象类
为什么
Java
程序设计语言还要不辞辛苦地引入接口概念?
为什么不将
Comparable
直接设计成如下所示的抽象类。
然后
,
Employee
类再直接扩展这个抽象类
,
并提供
compareTo
方法的实现
非常遗憾
,
使用抽象类表示通用属性存在这样一个问题
:
每个类只能扩展于一个类
。
假
设
Employee
类已经扩展于一个类
,
例如
Person
,
它就不能再像下面这样扩展第二个类了
:
class
Employee
extends
Person
,
Comparable
/
/
Error
但是可以实现多个接口
Java
的设计者选择了不支持多继承
,
其主要原因是多继承会让语言
本身变得非常复杂
(
如同
C
+
+
,
)
效率也会降低
(
如同
Eiffel
。
)
实际上,
接口可以提供多重继承的大多数好处
,
同时还能避免多重继承的复杂性和低效性
。
静态方法
在
Java
SE
8
中
,
允许在接口中增加静态方法
。
理论上讲
,
没有任何理由认为这是不合法
的
。
只是这有违于将接口作为抽象规范的初衷。目前为止
,
通常的做法都是将静态方法放在伴随类中
。
lambda 表达式
lambda
表达式
,
这是这些年来
Java
语言最让人激动的一个变化
。
你会了解如何使用 lambda
表达式采用一种简洁的语法定义代码块
,
以及如何编写处理
lambda
表达式的代码
为什么引入 lambda 表达式
lambda
表达式是一个可传递的代码块
,
可以在以后执行一次或多次
。
到目前为止
,
在
Java
中传递一个代码段并不容易
,
不能直接传递代码段
_
Java
是一种面
向对象语言
,
所以必须构造一个对象
,
这个对象的类需要有一个方法能包含所需的代码
在其他语言中
,
可以直接处理代码块
。
Java
设计者很长时间以来一直拒绝增加这个特性
。
毕竟
,
Java
的强大之处就在于其简单性和一致性
。
如果只要一个特性能够让代码稍简洁一些
,
就把这个特性增加到语言中
,
这个语言很快就会变得一团糟
,
无法管理
。 不过
,
在另外那些
语言中
,
并不只是创建线程或注册按钮点击事件处理器更容易
;
它们的大部分
API
都更简单
、
更一致而且更强大
。
在
Java
中
,
也可以编写类似的
AP
丨利用类对象实现特定的功能
,
不过这
种
API
使用可能很不方便
。
lambda 表达式的语法
- 一个 Lambda 表达式可以有零个或多个参数
- 参数的类型既可以明确声明,也可以根据上下文来推断。例如:
(int a)
与(a)
效果相同
- 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:
(a, b)
或 (int a, int b)
或 (String a, int b, float c)
- 空圆括号代表参数集为空。例如:
() -> 42
- 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:
a -> return a*a
- Lambda 表达式的主体可包含零条或多条语句
- 如果 Lambda 表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致
- 如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空
函 数 式 接 口
对于只有一个抽象方法的接口
,
需要这种接口的对象时
,
就可以提供一个
lambda
表达
式
。
这种接口称为函数式接口
(
functional
interface
)
。
为了展示如何转换为函数式接口
,
下面考虑
Arrays
.
sort
方法
。
它的第二个参数需要一个
Comparator
实例
,
Comparator
就是只有一个方法的接口
,
所以可以提供一个
lambda
表达式
:
Arrays
.
sort
(
words
, (first
,
second
)
-
>
first
.
lengthO
-
second
.
lengthO
)
;
最好把
lambda 表达式看作是一
个函数
,
而不是一个对象
,
另外要接受
lambda
表达式可以传递到函数式接口
。
内部类
内部类
(
inner
class
)
是定义在另一个类中的类
。
为什么需要使用内部类呢
?
•内部类方法可以访问该类定义所在的作用域中的数据,
包括私有的数据
。
•内部类可以对同一个包中的其他类隐藏起来。
•
当想要定义一个回调函数且不想编写大量代码时
,
使用匿名
(
anonymous
)
内部类比较
便捷
。
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
.匿名内部类
什么是匿名对象?如果一个对象只要使用一次,那么我们就是需要
new Object().method()
。 就可以了,而不需要给这个实例保存到该类型变量中去。这就是匿名对象。
public class Test {
public static void main(String[] args) {
//讲new出来的Apple实例赋给apple变量保存起来,但是我们只需要用一次,就可以这样写
Apple apple = new Apple();
apple.eat();
//这种就叫做匿名对象的使用,不把实例保存到变量中。
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("我要被吃了");
}
}
匿名内部类跟匿名对象是一个道理:
匿名对象:我只需要用一次,那么我就不用声明一个该类型变量来保存对象了,
匿名内部类:我也只需要用一次,那我就不需要在类中先定义一个内部类,而是等待需要用的时候,我
就在临时实现这个内部类,因为用次数少,可能就这一次,那么这样写内部类,更方便。不然先写出一
个内部类的全部实现来,然后就调用它一次,岂不是用完之后就一直将其放在那,那就没必要那样。
1.
匿名内部类需要依托于其他类或者接口来创建
如果依托的是类
,
那么创建出来的匿名内部类就默认是这个类的子类
如果依托的是接口
,
那么创建出来的匿名内部类就默认是这个接口的实现类。
2.
匿名内部类的声明必须是在使用
new
关键字的时候
匿名内部类的声明及创建对象必须一气呵成
,
并且之后能反复使用
,
因为没有名字。
public static void main(String[] args) {
//如果我们需要使用接口中的方法,我们只需要走一步,就是使用匿名内部类,直接将其
类的对象创建出来。
new Test1(){
public void method(){
System.out.println("实现了Test接口的方法");
}
}.method();
}
}
interface Test1{
public void method();
}