JAVA 内部类与Lambda

JAVA 内部类与Lambda

1 内部类

1.1 内部类基础

  • Java 一个类中可以嵌套另外一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类。语法格式如下:

    class OuterClass {   // 外部类
        // ...
        class NestedClass { // 嵌套类,或称为内部类
            // ...
        }
    }
    
  • 内部类访问特点

    • 内部类可以直接访问外部类的成员,包括私有

    • 由于内部类嵌套在外部类中,因此必须首先实例化外部类,然后创建内部类的对象来实现。

  • 嵌套类有两种类型

    • 内部类

    • 静态内部类

  • 成员内部类的定义位置

    • 在类中方法,跟成员变量是一个位置
  • 外界创建成员内部类格式

    格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
    举例:InnerClass.Inner ic = new InnerClass().new Inner();
    
  • 示例

    package com.fcarey.innerclass;
    
    public class InnerClass {
        int i = 0;
        private int j = 1;
    
        public class Inner {
            int k = 2;
    
            public void print() {
                System.out.println("public class Inner: " + i);
                System.out.println("public class Inner: " + j);
                System.out.println("public class Inner: " + k);
            }
        }
    }
    
    package com.fcarey.innerclass;
    
    public class Demo {
        public static void main(String[] args) {
            InnerClass.Inner ic = new InnerClass().new Inner();
            ic.print();
        }
    }
    

1.2 私有成员内部类

  • 内部类可以使用 private 或 protected 来修饰,如果你不希望内部类被外部类访问可以使用 private 修饰符:

    package com.fcarey.innerclass;
    
    public class InnerClass {
        int i = 0;
        private int j = 1;
    
        private class PrivateInner {
            public void print() {
                System.out.println("private class PrivateInner: " + i);
                System.out.println("private class PrivateInner: " + j);
            }
        }
    
        public void show() {
            PrivateInner privateInner = new PrivateInner();
            privateInner.print();
        }
    }
    
    package com.fcarey.innerclass;
    
    public class Demo {
        public static void main(String[] args) {
            InnerClass pic = new InnerClass();
            System.out.println(pic.i);
            // System.out.println(ic2.j); 报错,私有成员变量,外界无法使用,需要在方法内部创建对象并引用
            // System.out.println(ic2.k); 报错,局部内部变量,外界无法使用,需要在方法内部创建对象并引用
            pic.show();
        }
    }
    
    

1.3 静态内部类

  • 静态内部类可以使用 static 关键字定义,静态内部类我们不需要创建外部类来访问,可以直接访问它:

  • 静态成员内部类格式

    静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
    
    静态成员内部类中的静态方法:外部类名.内部类名.方法名();
    
  • 示例

    package com.fcarey.innerclass;
    
    public class InnerClass {
        int i = 0;
        private int j = 1;
    
        static class PSInner {
            public void print() {
                System.out.println("private static class PrivateInner: print()");
            }
    
            public static void show() {
                System.out.println("private static class PrivateInner: show()");
            }
        }
    }
    
    package com.fcarey.innerclass;
    
    public class Demo {
        public static void main(String[] args) {
            InnerClass.PSInner psInner = new InnerClass.PSInner();
            psInner.print();
            InnerClass.PSInner.show();
        }
    }
    
    

1.4 局部内部类

  • 局部内部类定义位置

    • 局部内部类是在方法中定义的类
  • 局部内部类方式方式

    • 局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用
    • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
    • 注意:静态内部类无法访问外部类的成员。
  • 示例:

    package com.fcarey.innerclass;
    
    public class InnerClass {
        int i = 0;
        private int j = 1;
    
        public class Inner {
            int k = 2;
    
            public void print() {
                System.out.println("public class Inner: " + i);
                System.out.println("public class Inner: " + j);
                System.out.println("public class Inner: " + k);
            }
        }
        
        public void partShow() {
            int l = 3;
            class PartInner {
                int m = 4;
    
                public void print() {
                    System.out.println("class PartInner:" + i);
                    System.out.println("class PartInner:" + j);
    //                System.out.println("class PartInner:" + k);
                    System.out.println("class PartInner:" + l);
                    System.out.println("class PartInner:" + m);
                }
            }
            PartInner partInner = new PartInner();
            partInner.print();
        }
    }
    
    package com.fcarey.innerclass;
    
    public class Demo {
        public static void main(String[] args) {
            InnerClass partIC = new InnerClass();
            partIC.partShow();
        }
    }
    

1.5 匿名内部类

  • 匿名内部类的前提

    • 存在一个类或者接口,这里的类可以是具体类也可以是抽象类
  • 匿名内部类的格式

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

    • 本质:是一个继承了该类或者实现了该接口的子类匿名对象
  • 示例

    package com.fcarey.innerclass;
    
    /*
        接口
     */
    interface Inter {
        void show();
    }
    
    public class AnonymousClass {
        public static void main(String[] args) {
            new Inter() {
                @Override
                public void show() {
                    System.out.println("the function of Anonymous Class :匿名内部类");
                }
            }.show(); // 直接调用方法
    
            anonymousShow(new Inter() {
                @Override
                public void show() {
                    System.out.println("the function of Anonymous Class ");
                }
            });
    
            anonymousShow(() -> {
                System.out.println("the function of Anonymous Class ");
            });
        }
        /**
         * 使用接口的方法
         */
        public static void anonymousShow(Inter inter) {
            inter.show();
        }
    }
    

2 Lambda表达式

Lambda表达式体现了函数式编程思想:

  • 在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”

  • 面向对象思想强调“必须通过对象的形式来做事情”

  • 函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”

  • 组成Lambda表达式的三要素:形式参数,箭头,代码块

  • 格式:

    (形式参数) -> {代码块}
    
    // 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
    // ->:由英文中画线和大于符号组成,固定写法。代表指向动作
    // 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
    

2.1 初识Lambda

2.1.1 无参无返回值抽象方法

package com.fcarey.innerclass;

public class LambdaTest {
    public static void main(String[] args) {
        
        // 通过匿名内部类实现
        useStringHander(new StringHandler() {
            @Override
            public void printMessage(String msg) {
                System.out.println(msg);
            }
        });
		// 通过Lambda表达式实现,其对匿名内部类做了优化
        useStringHander((msg -> {
            System.out.println("Anonymous class: "+msg);
        }));
    }
	// 使用接口的方法
    public static void useStringHander(StringHandler stringHandler) {
        stringHandler.printMessage("Hello World");
    }

}

interface StringHandler {
    void printMessage(String msg);
}

2.1.2 Lambda 有参无返回值抽象方法

package com.fcarey.innerclass;

public class LambdaTest {
    public static void main(String[] args) {
        useStringHander(new StringHandler() {
            @Override
            public void printMessage(String msg) {
                System.out.println(msg);
            }
        });

        useStringHander((msg -> {
            System.out.println("Anonymous class: "+msg);
        }));
    }

    public static void useStringHander(StringHandler stringHandler) {
        stringHandler.printMessage("Hello World");
    }

}

interface StringHandler {
    void printMessage(String msg);
}

2.1.3 Lambda 无参有返回值抽象方法

package com.fcarey.innerclass;

import java.util.Random;

public class LambdaTest02 {
    public static void main(String[] args) {
        useRandomNumberHandler(new RandomNumberHandler() {
            @Override
            public int getNumber() {
                Random r = new Random();
                return r.nextInt(100);
            }
        });
        useRandomNumberHandler(()->{Random r = new Random();
            return r.nextInt(100);
        });
    }
    public static void useRandomNumberHandler(RandomNumberHandler randomNumberHandler){
        int result = randomNumberHandler.getNumber();
        System.out.println(result);
    }
}

interface RandomNumberHandler{
    int getNumber();
}

2.1.4 有参有返回值抽象方法

package com.fcarey.innerclass;

import java.util.Random;

public class LambdaTest03 {

    public static void main(String[] args) {
        useCalculator(new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a+b;
            }
        });
        useCalculator((a, b) -> a+b);
    }

    public static void useCalculator(Calculator calculator) {
        Random rand = new Random();
        int a = rand.nextInt(100);
        int b = rand.nextInt(100);
        System.out.println(calculator.calc(a,b));;
    }
}

interface Calculator {
    int calc(int a, int b);
}

2.2 Lambda表达式的省略模式

省略的规则

  • 参数类型可以省略。但是有多个参数的情况下,不能只省略一个
  • 如果参数有且仅有一个,那么小括号可以省略
  • 如果代码块的语句只有一条,可以省略大括号和分号,和return关键字

2.3 Lambda表达式的使用前提

  • 使用Lambda必须要有接口
  • 并且要求接口中有且仅有一个抽象方法

2.4 Lambda表达式和匿名内部类的区别

  • 所需类型不同
    • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
    • Lambda表达式:只能是接口
  • 使用限制不同
    • 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
    • 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
  • 实现原理不同
    • 匿名内部类:编译之后,产生一个单独的.class字节码文件
    • Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
posted @ 2024-09-02 21:03  f_carey  阅读(1)  评论(0编辑  收藏  举报