Java 基础进阶篇(七):匿名内部类与 Lambda 表达式

  • Post author:
  • Post category:java





一、内部类概述

内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。如 People 类和 Heart 类:

在这里插入图片描述


场景:

当一个事物的内部,还有一个部分需要一个完整的结构进行描述时。


作用:

内部类通常可以方便访问外部类的成员,包括私有的成员;内部类提供了更好的封装性,内部类本身就可以用 private protected 等修饰,封装性可以做更多控制。


注:

外部类不能使用 protected 和 private 修饰。




二、需要了解的内部类



2.1 静态内部类

有static修饰,属于外部类本身。

它的特点和使用与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已。

在这里插入图片描述

静态内部类创建对象的格式:

在这里插入图片描述

拓展:


1.

静态内部类中是否可以直接访问外部类的静态成员?


可以,外部类的静态成员只有一份可以被共享访问。


2.

静态内部类中是否可以直接访问外部类的实例成员?


不可以,外部类的实例成员必须用外部类对象访问。


总结:

静态内部类可以直接访问外部类的静态成员,不能直接访问外部类的实例成员。




2.2 成员内部类

无 static 修饰,属于外部类的对象。

JDK 16之前,成员内部类中不能定义静态成员,JDK 16开始也可以定义静态成员了。

在这里插入图片描述

成员内部类创建对象的格式:

在这里插入图片描述

拓展:


1.

成员内部类中是否可以直接访问外部类的静态成员?


可以,外部类的静态成员只有一份可以被共享访问。


2.

成员内部类的实例方法中是否可以直接访问外部类的实例成员?


可以,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员。


总结:

可以直接访问外部类的静态成员,实例方法中可以直接访问外部类的实例成员。




2.3 局部内部类

局部内部类放在方法、代码块、构造器等执行体中。

局部内部类的类文件名为: 外部类$N内部类.class,N 代表索引,从 1 开始。




2.4 面试笔试题

请观察如下代码,写出合适的代码对应其注释要求输出的结果。

在这里插入图片描述

class People{
    private int heartbeat = 150;
    /**
       成员内部类
     */
    public class Heart{
        private int heartbeat = 110;
        public void show(){
            int heartbeat = 78;
            System.out.println(heartbeat); // 78
            System.out.println(this.heartbeat); // 110
            System.out.println(People.this.heartbeat); // 150
            System.out.println(new People().heartbeat); // 150
        }
    }
}


注意:

在成员内部类中访问所在外部类对象 ,格式:

外部类名.this




三、匿名内部类



本质上是一个没有名字的局部内部类,定义在方法中、代码块中等。


作用:

方便创建子类对象,最终目的为了简化代码编写。


格式:

在这里插入图片描述

如:

new Employee{… }



{…}

就是匿名内部类。

在这里插入图片描述


特点总结:


① 匿名内部类是一个没有名字的内部类。

② 匿名内部类写出来就会产生一个匿名内部类的对象。

③ 匿名内部类的对象类型相当于是当前 new 的那个的类型的子类类型。

举例:

interface Swimming{
    void swim();
}
public class Test {
    public static void main(String[] args) {
        Swimming ss = new Swimming() {
            @Override
            public void swim() {
                System.out.println("老师游泳!");
            }
        };
        go(ss); // 老师游泳!
        
        // 匿名内部类可以作为方法的实际参数进行传输
        go(new Swimming() {
            @Override
            public void swim() {
                System.out.println("学生游泳!");
            }
        });  // 学生游泳!
    }

    public static void go(Swimming s){
        s.swim();
    }
}


对比写一个学生类和老师类实现 Swimming 接口,匿名内部类使得代码更加的简化




四、Lambda表达式





4.1 Lambda 表达式的概述

Lambda 表达式是 JDK 8 开始后的一种新语法形式,

其用于简化匿名内部类的代码写法


格式:


在这里插入图片描述


注意:Lambda 表达式只能简化函数式接口的匿名内部类的写法形式


函数式接口:首先必须是接口(抽象类不可以)其次接口中有且仅有一个抽象方法的形式

通常函数式接口用

@FunctionalInterface

注解进行标注,起到只能定义一个抽象方法的限制作用。




4.2 Lambda 表达式的省略规则

  1. 参数类型可以省略不写。

  2. 如果只有一个参数,参数类型可以省略,同时 () 也可以省略。

  3. 如果 Lambda 表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号 “;”

  4. 如果 Lambda 表达式的方法体代码只有一行代码。可以省略大括号不写。

    此时,如果这行代码是 return 语句,必须省略 return,同时也必须省略 “;”。




4.3 Lambda 的使用

举例:自定义数组的排序规则,让其降序排序。

在这里插入图片描述


sort(T[] a, Comparator<? super T > c);


参数一:

被排序的数组 必须是引用类型的元素。

参数二:

代表了一个比较器对象。

该比较器对象是一个函数式接口,因此有两种方案:一种是匿名内部类的形式,另一种是比较类实现该接口的方法。


注:


? super T

:代表泛型下限,

?

必须是

T

或者其父类。

在这里插入图片描述


方式一:匿名内部类

public class Test2 {
    public static void main(String[] args) {
        // 定义数组
        Integer[] ages = {34, 12, 42, 23};

        // 匿名内部类
        Arrays.sort(ages, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1; //  降序
            }
        });
        // 简化形式 1
        Arrays.sort(ages, (Integer o1, Integer o2) ->{
            return o2 - o1;
        });
        // 简化形式 2
        Arrays.sort(ages, (o1, o2) ->{
            return o2 - o1;
        });

        // 简化形式 3
        Arrays.sort(ages, (o1, o2) -> o2 - o1 );
    }
}


方式二:子类实现

public class Test2 {
    public static void main(String[] args) {
        Integer[] ages = {34, 12, 42, 23};
        Arrays.sort(ages, new Comp());
        System.out.println(Arrays.toString(ages)); // [42, 34, 23, 12]
    }
}
class Comp implements Comparator<Integer>{
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2-o1;
    }
}

文章参考:

Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)



版权声明:本文为weixin_43819566原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。