Java[4] 接口与“λ”

教材

《Java核心技术·卷I 开发基础(原书第12版)》P233-289

《Java语言程序设计(第3版)》P168-174, P188-208


思维导图


目录

思维导图

一、接口

1.1 介绍

1.2 实现

1.3 常量

1.4 静态方法

1.5 默认方法

1.7 解决默认方法冲突

1.8 回调

1.9 Comparable 接口

1.10 Comparator 接口

1.11 Cloneable 接口

二、lambda 表达式

2.1 介绍

2.2 函数式接口

2.3 方法引用

2.4 构造器引用

2.5 变量作用域

三、内部类

3.1 介绍

3.2 成员内部类

3.3 局部内部类

3.4 匿名内部类

3.5 静态内部类

四、服务加载器

五、代理

编程练习


一、接口

1.1 介绍

  • 定义:
  1. 一种可以被类层次中任何类实现行为的协议  是常量 抽象方法 默认方法 静态方法的集合
  2. 可以用来实现多重继承
  • 声明

[public] interface InterfaceName [extends SuperInterfaces] {

        // 1. 常量的定义

        // 2. 抽象方法的定义

        // 3. 静态方法的定义

        // 4. 默认方法的定义

}

  1. 关键字 interface
  2. 接口名后缀通常是 able
  3. 不能用 new 操作符创建接口的实例
  4. 可以声明接口变量(必须引用实现了这个接口的一个类对象)
  5. 可以使用 instanceof 检查一个对象是否实现了某个特定的接口
  • 继承
  1. 关键字 extends
  2. 子接口继承父接口中的 常量 抽象方法 默认方法

1.2 实现

[public] class ClassName implements InterfaceList {

        // 类体定义

}

  • 两个步骤:
  1. 将类声明为实现给定的接口
  2. 对接口中的所有抽象方法提供定义(必须使用与接口完全相同的方法签名  必须显式地把方法声明为 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. 超类优先:如果超类提供了一个具体方法 同名且有相同参数类型的默认方法会被忽略
  2. 接口冲突:覆盖默认方法(提供默认方法的一个新实现  选择两个冲突方法中的一个

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());

 语法

  1. 没有参数也有括号
  2. 参数类型可自动推导 能忽略类型
  3. 只有一个参数且类型可自动推导 能省略小括号
  4. 不需要指定返回类型(可自定推导)
  5. 只在某些分支返回一个值 另外一些分支不返回值 是不合法的

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 方法引用

  • 定义:指示编译器生成一个函数式接口的实例 覆盖这个接口的抽象方法来调用特定的方法
  • 语法(:: 操作符)
  1. 对象 :: 实例方法名
  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 介绍

  • 定义:在一个类内部定义的另一个类

类型

  • 静态
  1. 静态内部类
  • 非静态
  1. 成员内部类
  2. 局部内部类
  3. 匿名内部类
  • 使用原因
  1. 内部类可以对同一个包中的其他类隐藏
  2. 内部类方法可以访问定义这些方法的作用域中的数据

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));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值