教材
《Java核心技术·卷I 开发基础(原书第12版)》P233-289
《Java语言程序设计(第3版)》P168-174, P188-208
思维导图
目录
一、接口
1.1 介绍
- 定义:
- 一种可以被类层次中任何类实现行为的协议 是常量 抽象方法 默认方法 静态方法的集合
- 可以用来实现多重继承
- 声明
[public] interface InterfaceName [extends SuperInterfaces] {
// 1. 常量的定义
// 2. 抽象方法的定义
// 3. 静态方法的定义
// 4. 默认方法的定义
}
- 关键字 interface
- 接口名后缀通常是 able
- 不能用 new 操作符创建接口的实例
- 可以声明接口变量(必须引用实现了这个接口的一个类对象)
- 可以使用 instanceof 检查一个对象是否实现了某个特定的接口
- 继承
- 关键字 extends
- 子接口继承父接口中的 常量 抽象方法 默认方法
1.2 实现
[public] class ClassName implements InterfaceList {
// 类体定义
}
- 两个步骤:
- 将类声明为实现给定的接口
- 对接口中的所有抽象方法提供定义(必须使用与接口完全相同的方法签名 必须显式地把方法声明为 public)
- 关键字 implements
- 实现多个接口(用逗号分隔)
1.3 常量
int STATUS = 0;
public int STATUS = 0;
public static final int STATUS = 0;
public final static 修饰(可以省略)
使用接口名引用
不推荐在接口中定义常量
1.4 静态方法
public static 修饰
public interface InterfaceName {
...
public static returnType methodName([paramList]) {
...
}
}
接口名.静态方法名() 访问
不能被子接口继承 不被实现类继承
1.5 默认方法
public interface InterfaceName {
...
public default returnType methodName([paramList]) {
...
}
}
- 关键字 default
- 可以被子接口和实现类继承(子接口若定义相同的默认方法 父接口的默认方法会被隐藏)
- 可以调用其他方法
- 接口演化:为接口增加一个非默认方法不能保证源代码兼容
1.7 解决默认方法冲突
- 冲突
对于一个继承自超类且实现了多个接口的类 其中一个接口存在默认方法 超类或另一个接口中存在一个名称和参数类型相同的(默认或非默认)方法 此时将产生冲突
- 规则
- 超类优先:如果超类提供了一个具体方法 同名且有相同参数类型的默认方法会被忽略
- 接口冲突:覆盖默认方法(提供默认方法的一个新实现 选择两个冲突方法中的一个)
1.8 回调
可以指定某个特定事件发生时应该采取的动作的程序设计模式
1.9 Comparable 接口
- 定义
public interface Comparable<T> {
int compareTo (T other);
}
泛型接口
- 实现
当前对象与参数对象比较 返回一个整数值
小于 --> 负整数 等于 --> 0 大于 --> 正整数
1.10 Comparator 接口
- 定义
public interface Comparator<T> {
int compare (T first, T second);
}
泛型接口
- 实现
比较两个参数对象 返回一个整数值
当第一个参数小于 等于 大于第二个参数时 --> 负整数 0 正整数
1.11 Cloneable 接口
二、lambda 表达式
2.1 介绍
- 定义:可以传递给方法的一段代码(一个语句 或 一个代码块)
(param1, param2, ...) -> expression;
(param1, param2, ...) -> { ... };
// 比较两个字符串的长度
class LengthComparator implements Comparator<String> {
public int compare (String first, String second) {
return first.length() - second.length();
}
}
String[] strings = ...;
Arrays.sort(strings, new LengthComparator());
// 使用 lambda 表达式简化代码
Arrays.sotr(strings, (String first, String second) -> first.length() - second.length());
// 进一步简化 省略参数类型
Arrays.sotr(strings, (first, second) -> first.length() - second.length());
语法
- 没有参数也有括号
- 参数类型可自动推导 能忽略类型
- 只有一个参数且类型可自动推导 能省略小括号
- 不需要指定返回类型(可自定推导)
- 只在某些分支返回一个值 另外一些分支不返回值 是不合法的
2.2 函数式接口
- 定义:只有一个抽象方法的接口
lambda 表达式可以传递到函数式接口 创建该接口的对象
public interface BiFunction<T, U, R> {
R apply (T t, U u);
}
BiFunction<String, String, Integer> comp =
(first, second) -> first.length() - second.length();
Integer result = comp.apply("123", "1234");
常用的预定义函数式接口
public interface Function<T, R> { R apply (T t); }
public interface BiFunction<T, U, R> { R apply (T t, U u); }
public interface Predicate<T> { boolean test (T t); }
public interface Supplier<T> { T get(); }
public interface Consumer<T> { void accept (T t); }
2.3 方法引用
- 定义:指示编译器生成一个函数式接口的实例 覆盖这个接口的抽象方法来调用特定的方法
- 语法(:: 操作符)
- 对象 :: 实例方法名
- 类名 :: 实例方法名
- 类名 :: 静态方法名
list.forEach(x -> System.out.println(X));
list.forEach(System.out::println);
Arrays.sort(strings, (x, y) -> x.comparaToIgnoreCase(y));
Arrays.sort(strings, String::compareToIgnoreCase);
当 lambda 表达式的体只调用一个方法而不做其他操作时 能把 lambda 表达式重写为方法引用
可以在方法引用中使用 this 和 super 参数
2.4 构造器引用
方法名为 new 的方法引用
2.5 变量作用域
lambda 表达式的体与嵌套块有相同的作用域
lambda 表达式能引用外围作用域中值不变的变量
不能在 lambda 表达式中声明一个与局部变量同名的参数或变量
可以使用 this 关键字 指示创建该 lambda 表达式的方法的 this 参数
三、内部类
3.1 介绍
- 定义:在一个类内部定义的另一个类
类型
- 静态
- 静态内部类
- 非静态
- 成员内部类
- 局部内部类
- 匿名内部类
- 使用原因
- 内部类可以对同一个包中的其他类隐藏
- 内部类方法可以访问定义这些方法的作用域中的数据
3.2 成员内部类
- 定义:在外部类的类体中的类
public class OuterClass {
... // 类体
class InnerClass {
... // 类体
}
}
可以访问外部类对象的所有成员
可以创建内部类的实例
不能定义 static 变量和 static 方法
可以使用 abstract 和 final 关键字
可以使用 private public proteccted (默认) 关键字
3.3 局部内部类
- 定义:在方法体或语句块(方法 构造方法 局部块 初始化块 静态初始化块)内部的类
public class OuterClass {
...
public returnType methodName([paramLIst]) {
class InnerClass {
... // 类体
}
}
}
类似局部变量 在方法体或语句块的外部不能访问局部内部类
不能使用 private protected public static关键字
可以使用 final abstract 关键字
可以访问外层类的成员
static 方法中定义的局部内部类 可以访问外层类中的 static 成员 不能访问外层类的实例成员
3.4 匿名内部类
- 定义:没有名字的类
TypeName obj = new TypeName() {
... // 类体
};
somemethod(
new TypeName() {
... // 类体
}
);
不能定义构造方法
匿名内部类的定义 创建对象同时发生
3.5 静态内部类
- 定义:关键字 static
public class OuterClass {
... // 类体
public static InnerClass {
... // 类体
}
}
可以定义静态成员
只能访问外部类的静态成员
创建静态内部类的实例不需要先创建一个外部类的实例
四、服务加载器
五、代理
编程练习
public interface Swimmable {
void swim();
}
public interface Flyable {
void fly();
}
public class Duck implements Swimmable, Flyable {
public void swim() {
System.out.println("The duck is swimming.");
}
public void fly() {
System.out.println("The duck is flying");
}
public static void main(String[] args) {
Duck duck = new Duck();
duck.swim();
duck.fly();
}
}
public interface IntSequence {
boolean hasNext();
int next();
}
public class RandomIntSequence implements IntSequence {
private int n;
public RandomIntSequence() {
this(0);
}
public RandomIntSequence(int n) {
this.n = n;
}
@Override
public boolean hasNext() {
n = (int) (Math.random() * (99 - 10) + 10);
return true;
}
@Override
public int next() {
return n;
}
public static void main(String[] args) {
RandomIntSequence randomIntSequence = new RandomIntSequence();
System.out.println(randomIntSequence.hasNext());
System.out.println(randomIntSequence.next());
}
}
public class SequenceTest {
public static double average(IntSequence seq, int n) {
double sum = 0.0;
for (int i = 0; i < n; i++) {
if (seq.hasNext()) {
sum += seq.next();
}
}
return sum / n;
}
public static void main(String[] args) {
RandomIntSequence randomIntSequence = new RandomIntSequence();
System.out.print(average(randomIntSequence, 10));
}
}
public class Position implements Comparable<Position> {
private final double x;
private final double y;
public Position() {
this(0.0, 0.0);
}
public Position(double x, double y) {
this.x = x;
this.y = y;
}
public double getDistance() {
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
}
public int compareTo(Position otherPosition) {
return -Double.compare(getDistance(), otherPosition.getDistance());
}
public static void main(String[] args) {
Position o = new Position();
Position a = new Position(1.5, 2.5);
Position b = new Position(2.8, 0.6);
System.out.println(o.compareTo(a));
System.out.println(o.compareTo(b));
System.out.println(a.compareTo(b));
}
}
public class Student {
private final String name;
public Student() {
this("Unknown");
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
import java.util.Arrays;
import java.util.Comparator;
public class StudentRank implements Comparator<Student> {
public int compare(Student s1, Student s2) {
return s1.getName().compareTo(s2.getName());
}
public static void main(String[] args) {
Student[] roster = {
new Student(),
new Student("John"),
new Student("Oliver"),
new Student("Amy"),
new Student("Cameron")
};
for (Student student : roster) {
System.out.print(student.getName());
System.out.print(' ');
}
System.out.print('\n');
Arrays.sort(roster, new StudentRank());
for (Student student : roster) {
System.out.print(student.getName());
System.out.print(' ');
}
}
}
import java.util.Arrays;
import java.util.Comparator;
public class StringReverseSort implements Comparator<String> {
public int compare(String first, String second) {
return -first.compareTo(second);
}
public static void main(String[] args) {
String[] strings = {
"apple",
"Apple",
"hello",
"cat",
"dog",
"Oliver",
"person"
};
for (String string : strings) {
System.out.print(string);
System.out.print(' ');
}
System.out.print('\n');
Arrays.sort(strings, new StringReverseSort());
for (String string : strings) {
System.out.print(string);
System.out.print(' ');
}
}
}
public interface Calculator {
double calculate(int a, int b);
default int subtract(int a, int b) {
return a - b;
}
default int add(int a, int b) {
return a + b;
}
static void main(String[] args) {
Calculator calculator = (a, b) -> a * a + b * b;
System.out.print(calculator.calculate(3, 4));
}
}