[JavaSE](成员内部类、局部内部类、匿名内部类、Lambda表达式)

 ✨✨个人主页:沫洺的主页

📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                           📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

                           📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏     

💖💖如果文章对你有所帮助请留下三连✨✨

🍂内部类

类中有什么

  1. 静态程序段(static{})
  2. 属性
  3. 方法
  4. 成员内部类,可以使用private修饰
  5. 初始化程序段(很少用)

内部类的概念

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

也就是在类{}里面创建的类才叫内部类

内部类的种类

  • 成员内部类
  • 局部内部类
  • 匿名内部类(直接new 抽象类,直接new 接口)

🌳成员内部类

什么是成员内部类

首先我们知道成员变量和成员方法是类的成员,那么成员内部类就是和成员变量和成员方法同一级的一个类而已,成员内部类也就是作为这个类(外部类)的成员存在。

举个例子

package cn.moming7;

public class A {        //相较于B这个类而言,A是外部类
    public class B{     //类种类,内部类
        
    }
}

案例分析

package cn.moming7;

public class A {    //外部类

    public int num = 100;     //成员变量

    class B {           //内部类
        public int num = 200;    //内部类的成员变量

        public void mod() {     //内部类的成员方法
            int num = 300;       //内部类的局部变量

            System.out.println(num);   //就近输出
            System.out.println(this.num);   //指定当前类下的变量num
            System.out.println(A.this.num);  //指定外部类A下的变量num
        }
    }
    public static void main(String[] args){
        A.B b = new A().new B();    //内部类实例化
        b.mod();    //调用内部类的成员方法
    }

}
300
200
100

🍁局部内部类

什么是局部内部类

首先我们知道局部变量是在成员方法里的,那么局部内部类和局部变量同一级,那么局部内部类的位置就在成员方法里

举个例子

package cn.moming7;

public class C {    //外部类
    private int age;        //成员变量
    public void show(){     //成员方法
        String name="沫洺";   //局部变量
        class B{        //局部内部类

        }
    }
}

局部内部类注意事项

局部内部类中可以使用局部变量,但是一但使用了局部变量,该局部变量就不能被重新赋值了。
因为: 当局部内部类中去使用局部变量时,局部变量就会被java自动使用final修饰。

局部内部类不能被public private static修饰,但可以被abstract、final修饰。

因为局部内部类是放在代码块或方法中的,不能有访问控制修饰符,且不能用static修饰。

🌿匿名内部类

什么是匿名

匿名就是没有名字

比如下面的代码

package cn.moming7;

import java.util.Random;

public class Demo {
    public static void main(String[] args) {
        Random random = new Random();      //实例化对象时给new出来的对象起了一个变量名random
        System.out.println(random);
        System.out.println(random.nextInt(10));

        System.out.println(new Random());   //实例化对象没有给名字,相当于new了个匿名对象
        System.out.println(new Random().nextInt(10));
    }
}
java.util.Random@3b07d329
0
java.util.Random@41629346
9

匿名内部类的作用

匿名内部类最常用的方法就是当做一个参数来用的,简化开发

什么时候使用匿名内部类

必须存在继承和实现关系的时候才可以使用

举例

在继承关系中对父类的方法进行重写

父类(Animal)

package cn.moming8;

public class Animal {
    public void call(){
        System.out.println("动物叫");
    }
}

子类(Dog)

package cn.moming8;

public class Dog extends Animal{
    @Override
    public void call() {
        System.out.println("狗叫");
    }
}

测试类(Test)

package cn.moming8;

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.call();
    }
}
狗叫

通过匿名内部类去重写方法

类(Animal)

package cn.moming8;

public class Animal {
    public void call(){
        System.out.println("动物叫");
    }
}

测试类(Test)

package cn.moming8;

public class Test {
    public static void main(String[] args) {
        new Animal(){
            @Override
            public void call() {
                System.out.println("狗叫");
            }
        }.call();
    }
}
狗叫

通过对比很明显的可以看到匿名内部类对方法重写更为简化

 通过匿名内部类对数组进行排序

package moming;

import java.util.Arrays;

public class Comparator {
    public static void main(String[] args) {
        Integer[] ints = {3,5,8,9,1,6,5};
        Arrays.sort(ints);  //默认升序
        System.out.println(Arrays.toString(ints));

        Arrays.sort(ints, new java.util.Comparator<Integer>() {    //通过匿名内部类重写比较方法
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        System.out.println(Arrays.toString(ints));
    }
}
[1, 3, 5, 5, 6, 8, 9]
[9, 8, 6, 5, 5, 3, 1]

​内部类的注意事项

  • 内部类可以直接使用外部类的成员(外部类就是指该类里有内部类,那么相交内部类而言它就是外部类)。
  • 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以 外部类的类名和$符号。
  • 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部 类的成员变量,无论是否是private的。
  • 外部类不能直接访问其内部类,想要访问内部类,需实例化内部类。
  • 内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的 静态成员变量。
  • 其他类想要直接访问内部类,可直接实例化内部类,方法如下外部类名.内部类 对象名 = new 外部类().new 内部类();
  • 如果内部类是静态的,当其他类调用内部类可直接通过类名调用,格式: 外部类.内部类 对象名 = new 外部类.内部类()
  • 当内部类是静态的,且方法也是静态的,此时可不需实例化对象,格式:外部类.内部类.静态方法名();

🍂Lambda表达式

先来看看Lambda表达式长什么样

拿出上面的匿名内部类排序数组,自动生成Lambda表达式 

切换完之后看效果发现Lambda表达式非常的简洁 

 那么什么是Lambda表达式

Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得

名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函 数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。

  • Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
  • Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
  • 使用 Lambda 表达式可以使代码变的更加简洁紧凑,有效避免内部匿名类出现。

 Lambda表达式的格式

(形式参数)->{方法体}

():  代表形参-  就是接口中抽象方法的参数
->:  固定语法
{}:  代表方法体- 接口中抽象方法重写之后的方法体

Lambda表达式的本质 

创建了一个接口的实现类对象

 使用Lambda表达式的前提

必须是一个接口并且接口中有且仅有一个抽象方法

比如上面的排序案例(Comparator)

所以根据Lambda表达式的特点 ,我们自己实现一个Lambda表达式

接口(DbDao1)无参无返回值

package cn.moming9;

public interface DbDao1 {
    void show();    //无参无返回值
}

接口(DbDao2)有参无返回值

package cn.moming9;

public interface DbDao2 {
    void myName(String name);   //有参无返回值
}

接口(DbDao3)有参有返回值

package cn.moming9;

public interface DbDao3 {
    int myAge(int age);     //有参有返回值
}

测试类(Test)

说明:useDbDao方法就是一个工具人,Lambda表达式的作用是作为参数来用的,所以我们需要一个方法的参数类型是是接口的方法。

package cn.moming9;

public class Test {
    public static void main(String[] args) {
        useDbDao1(()->{                           //无参无返回值
            System.out.println("你好");
        });
        useDbDao2((String name)->{                //有参无返回值
            System.out.println(name);
        });
        useDbDao3((int age)->{                    //有参有返回值
            return age;
        });
    }
    public static void useDbDao1(DbDao1 d1){
        d1.show();
    }
    public static void useDbDao2(DbDao2 d2){
        d2.myName("沫洺");
    }
    public static void useDbDao3(DbDao3 d3){
        d3.myAge(18);
    }
}
你好
沫洺

🍃省略模式

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

例如上面的测试类省略后

package cn.moming9;

public class Test {
    public static void main(String[] args) {
        useDbDao1(()-> System.out.println("你好"));
        useDbDao2((name)-> System.out.println(name));
        useDbDao3((age)-> age);
    }
    public static void useDbDao1(DbDao1 d1){
        d1.show();
    }
    public static void useDbDao2(DbDao2 d2){
        d2.myName("沫洺");
    }
    public static void useDbDao3(DbDao3 d3){
        d3.myAge(18);
    }
}

 Lambda和匿名内部类的区别

  • 使用匿名内部类 语法上没有限制
  • 使用Lambda 必须是一个接口并且接口中有且仅有一个抽象方法

🌻lambda表达式双冒号

双冒号运算符就是java中的方法引用,方法引用的格式是类名 :: 方法名。

这里只是方法名,方法名的后面没有括号“()”。--------> 这样的式子并不代表一定会调用这个方 法。这种式子一般是用作Lambda表达式,Lambda有所谓的懒加载,不要括号就是说,看情况调用方法。

以上面的测试类为例(useDbDao2使用双冒号)

package cn.moming9;

public class Test {
    public static void main(String[] args) {
        useDbDao1(()-> System.out.println("你好"));
        //useDbDao2((name)-> System.out.println(name));
        useDbDao2(System.out::println);
        useDbDao3((age)-> age);
    }
    public static void useDbDao1(DbDao1 d1){
        d1.show();
    }
    public static void useDbDao2(DbDao2 d2){
        d2.myName("沫洺");
    }
    public static void useDbDao3(DbDao3 d3){
        d3.myAge(18);
    }
}

例:

  • 表达式:person ->person.getAge();可以替换为 Person::getAge
  • 表达式:()-> new HashMap<>();可以替换为 HashMap::new
  • 表达式:()->Math.random();可以替换为 Math::random

这种方法引用或者是双冒号运算对应的参数类型是Function<T,R>T表示传入的类型,R表示返回的 类型。比如表达式person -> person.getAge();传入的参数是person,返回值是peron.getAge(),那么方法引用Person::getAge就对应着Funciton<Person,Integer>类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沫洺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值