匿名内部类、Lambda表达式、方法引用对比分析


一、匿名内部类

匿名内部类可以看作是特殊的局部内部类,其本质就是一个继承类(或实现接口)的匿名子类。

匿名内部类是在使用的时候动态的指定方法体的逻辑,无需每次都去创建一个继承类(或实现接口)的子类。编译器会在编译阶段自动生成一个匿名子类。

1. 语法格式

匿名内部类的语法格式:new 接口名|类名(){重写方法}

其中,如果重写方法为非必要的,原则上是可以没有重写方法部分的。

2. 使用方法

① 传统方式

父子类:

public class ParentClass {
    
    

    public void aa(String str) {
    
    

    }

    public void bb(String str) {
    
    

    }
}
public class ChildClass extends ParentClass {
    
    

    @Override
    public void aa(String str) {
    
    
		System.out.println("自定义方法体");
    }

    @Override
    public void bb(String str) {
    
    
		System.out.println("自定义方法体");
    }
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        ParentClass ohj = new ChildClass();
    }
}

接口实现类:

public interface ParentInterface {
    
    

    void aa(String str);

    void bb(String str);
}
public class ChildClass implements ParentInterface {
    
    

    @Override
    public void aa(String str) {
    
    
		System.out.println("自定义方法体");
    }

    @Override
    public void bb(String str) {
    
    
		System.out.println("自定义方法体");
    }
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        ParentInterface ohj = new ChildClass();
    }
}

② 匿名内部类方式

父子类:

public class ParentClass {
    
    

    public void aa(String str) {
    
    

    }

    public void bb(String str) {
    
    

    }
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        ParentClass obj = new ParentClass() {
    
    
            @Override
            public void aa() {
    
    
                System.out.println("自定义方法体");
            }

            @Override
            public void bb() {
    
    
                System.out.println("自定义方法体");
            }
        };
    }
}

接口实现类:

public interface ParentInterface {
    
    

    void aa(String str);

    void bb(String str);
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        ParentInterface obj = new ParentInterface() {
    
    
            @Override
            public void aa() {
    
    
                System.out.println("自定义方法体");
            }

            @Override
            public void bb() {
    
    
                System.out.println("自定义方法体");
            }
        };
    }
}

二、Lambda表达式

从Java8开始,引入了Lambda表达式。

对于只有一个抽象方法的接口(函数式接口),可以直接使用Lambda表达式创建它的匿名实现类实例。

  • 使用匿名内部类方式定义的内部类:编译之后,会生成一个单独的class字节码文件(外部类名$编号.class);
  • 使用Lambda表达式定义的内部类:编译之后,不会生成一个单独的class字节码文件,对应的字节码会在运行的时候动态生成。

1. 语法格式

Lambda表达式的语法格式:(参数列表) -> {方法体}

省略写法:

  • 小括号内参数的参数类型可以省略
  • 小括号内无参数时,小括号不可省略
  • 小括号内只有一个参数时,小括号可以省略
  • 小括号内有多个参数时,小括号不可省略
  • 大括号内有且只有一行语句时,可以省略

2. 使用方法

public interface ParentInterface {
    
    

    void aa(String str);
}

① 匿名内部类方式

public class Test {
    
    

    public static void main(String[] args) {
    
    
        ParentInterface obj = new ParentInterface() {
    
    
            @Override
            public void aa(String str) {
    
    
                System.out.println("自定义方法体");
            }
        };
    }
}

② Lambda表达式方式

public class Test {
    
    

    public static void main(String[] args) {
    
    
        ParentInterface obj = str -> System.out.println("自定义方法体");
    }
}

三、方法引用

方法引用是对Lambda表达式进一步简化,借用其他类的方法体,省去了写方法体的过程。

对于方法体只有一行代码的Lambda表达式(该行代码为调用某个类或某个实例的方法时),可以简洁为更简单的方法引用的方式。

1. 语法格式

方法引用的语法格式:

语法种类 语法格式 示例 参数对应关系
类型的静态方法引用 类::静态方法 String::valueOf 抽象方法的参数与静态方法的参数顺序对应
类型的构造方法引用 类::new String::new 抽象方法的参数与构造方法的参数顺序对应
类型的实例方法引用 类::实例方法 String::replaceAll 抽象方法的第一个参数为调用引用方法的实例对象

抽象方法的剩余参数与实例方法的参数顺序对应
对象的实例方法引用 对象::实例方法 s::replaceAll 实例对象s为外部参数

抽象方法的参数与实例方法的参数顺序对应

需要注意:

  • 当接口的抽象方法无返回值时,方法引用的方法有无返回值都可以;
  • 当接口的抽象方法有返回值时,方法引用的方法也必须有返回值,且返回值类型 instanceof 接口的抽象方法返回值类型

2. 使用方法

① 类型的静态方法引用

类型的静态方法引用:类名::静态方法

对应Lambda表达式:(参数1,参数2,…) -> 类名.静态方法(参数1,参数2,…)

@FunctionalInterface
public interface ParentInterface {
    
    

    String aa(String s);
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        // 类型的静态方法引用
        ParentInterface parentInterface1 = String::valueOf;
        // 对应Lambda表达式方式
        ParentInterface parentInterface2 = s -> String.valueOf(s);
    }
}

② 类型的构造方法引用

类型的构造方法引用:类::new

对应Lambda表达式:(参数1,参数2,…) -> new 类名(参数1,参数2,…)

@FunctionalInterface
public interface ParentInterface {
    
    

    String aa(String s);
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        // 类型的构造方法引用
        ParentInterface parentInterface1 = String::new;
        // 对应Lambda表达式方式
        ParentInterface parentInterface2 = s -> new String(s);
    }
}

③ 类型的实例方法引用

类型的实例方法引用:类::实例方法

对应Lambda表达式:(参数1,参数2,…) -> 参数1.静态方法(参数2,…)

@FunctionalInterface
public interface ParentInterface {
    
    

    String aa(String s1, String s2, String s3);
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        // 类型的实例方法引用
        ParentInterface parentInterface1 = String::replaceAll;
        // 对应Lambda表达式方式
        ParentInterface parentInterface2 = (s1,s2,s3) -> s1.replaceAll(s2,s3);
    }
}

④ 对象的实例方法引用

对象的实例方法引用:对象::实例方法

对应Lambda表达式:(参数1,参数2,…) -> 对象.静态方法(参数1,参数2,…)

@FunctionalInterface
public interface ParentInterface {
    
    

    String aa(String s1, String s2);
}
public class Test {
    
    

    public static void main(String[] args) {
    
    
        String s = "";
        // 对象的实例方法引用
        ParentInterface parentInterface1 = s::replaceAll;
        // 对应Lambda表达式方式
        ParentInterface parentInterface2 = (s1,s2) -> s.replaceAll(s1,s2);
    }
}

四、匿名内部类、Lambda表达式、方法引用对比分析总结

  • Lambda表达式是匿名内部类的简写(匿名内部类为函数式接口的实现的这种)
  • 方法引用是Lambda表达式的简写(Lambda表达式的方法体只有一行代码且该行代码方法调用)

猜你喜欢

转载自blog.csdn.net/JokerLJG/article/details/129051108