【JAVA基础之内部类】成员内部类、匿名内部类、静态内部类、局部内部类

🔥作者主页小林同学的学习笔录

🔥小林同学的专栏JAVA之基础专栏

目录

1.内部类

1.1 概述

1.1.1 什么是内部类

1.1.2 什么时候使用内部类

1.2 内部类的分类

1.3 成员内部类

1.3.1  获取成员内部类对象的两种方式

1.3.2  经典面试题

1.4  静态内部类

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

1.5  局部内部类

1.6  匿名内部类

1.6.1  引出匿名内部类 

1.6.2  匿名内部类用处

1.6.3  匿名内部类的使用场景


1.内部类

1.1 概述

1.1.1 什么是内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类,其他称为外部其他类可以把内部类理解成寄生,外部类理解成宿主。

1.1.2 什么时候使用内部类

一个事物内部还有一个独立的事物,内部的事物脱离外部的事物无法独立使用

  1. 人里面有一颗心脏。

  2. 汽车内部有一个发动机。

  3. 目的为了实现更好的封装性。

1.2 内部类的分类

按定义的位置来分

  1. 成员内部类,类定义在了成员位置 (类中方法外称为成员位置,无static修饰的内部类)

  2. 静态内部类,类定义在了成员位置 (类中方法外称为成员位置,有static修饰的内部类)

  3. 局部内部类,类定义在方法内

  4. 匿名内部类,没有名字的内部类,可以在方法中,也可以在类中方法外。

1.3 成员内部类

类定义在成员位置上

1.3.1  获取成员内部类对象的两种方式

  • 方式一:外部直接创建成员内部类的对象
    • 外部类.内部类 变量 = new 外部类().new 内部类();
  • 方式二:在外部类中定义一个方法提供内部类的对象(一般用在内部类用private修饰才用到)

代码演示:

方式一:
public class Test {
    public static void main(String[] args) {
        //  宿主:外部类对象。
       // Outer out = new Outer();
        // 创建内部类对象。
        Outer.Inner oi = new Outer().new Inner();
        oi.method();
    }
}

class Outer {
    // 成员内部类,属于外部类对象的。
    // 拓展:成员内部类不能定义静态成员。
    public class Inner{
        // 这里面的东西与类是完全一样的。
        public void method(){
            System.out.println("内部类中的方法被调用了");
        }
    }
}


方式二:
public class Outer {
    String name;
    private class Inner{
        static int a = 10;
    }
    public Inner getInstance(){
        return new Inner();
    }
}

public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        System.out.println(o.getInstance());


    }
}

1.3.2  经典面试题

public class Test {
    public static void main(String[] args) {
        Outer.inner oi = new Outer().new inner();
        oi.method();
    }
}

class Outer {	// 外部类
    private int a = 30;

    // 在成员位置定义一个类
    class inner {
        private int a = 20;

        public void method() {
            int a = 10;
            System.out.println(???);	// 10   答案:a
            System.out.println(???);	// 20	答案:this.a
            System.out.println(???);	// 30	答案:Outer.this.a
        }
    }
}

执行原理:

1.4  静态内部类

静态内部类可以直接访问外部类的静态成员。

静态内部类不可以直接访问外部类的非静态成员,如果要访问需要创建外部类的对象。

静态内部类中没有虚拟机所创建的Outer.this

如何调用静态内部类的方法?

  • 非静态方法:创建对象,并调用方法
  • 静态方法:外部类名.内部类名.方法名()

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

外部类.内部类  变量 = new  外部类.内部类构造器;

代码演示:

// 外部类:Outer01
class Outer01{
    private static  String sc_name = "小白";
    private String sc_age = 24;
    // 内部类: Inner01
    public static class Inner01{
        // 这里面的东西与类是完全一样的。
        private String name;
        public Inner01(String name) {
            this.name = name;
        }
        public void showName(){
            System.out.println(this.name);
            // 拓展:静态内部类可以直接访问外部类的静态成员。
            System.out.println(sc_name);
            //访问外部类的非静态的变量需要创建外部类的对象
            Outer01 outer01 = new Outer01();
            System.out.println(outer.sc_age);
        }
    }
}

public class InnerClassDemo01 {
    public static void main(String[] args) {
        // 创建静态内部类对象。
        // 外部类.内部类  变量 = new  外部类.内部类构造器;
        Outer01.Inner01 in  = new Outer01.Inner01("张三");
        in.showName();
    }

1.5  局部内部类

将内部类定义在方法里面就叫做局部内部类,类似于方法中的局部变量

外部类是无法直接获取局部内部类的,需要创建该类的对象,然后再进行使用

该类可以直接访问外部类的成员,也可以访问方法内的局部变量

代码示例:

public class Outer {
    private int outerField = 10;

    public void outerMethod() {
        final int localVar = 20;
        //局部内部类
        class LocalInner {
            void display() {
                System.out.println("Outer Field: " + outerField);
                System.out.println("Local Variable: " + localVar);
            }
        }
        //外部类获取内部类信息,需要创建对象
        LocalInner inner = new LocalInner();
        inner.display();
    }


    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.outerMethod();
    }
}

1.6  匿名内部类

1.6.1  引出匿名内部类 

正常类:

匿名内部类(Student被匿名):

代码演示:

interface Swim {
    public abstract void swimming();
}

public class Demo07 {
    public static void main(String[] args) {
        // 使用匿名内部类对象,并且调用匿名内部类里面的方法
		new Swim() {
			@Override
			public void swimming() {
				System.out.println("自由泳...");
			}
		}.swimming();

        // 接口 变量 = new 实现类(); // 多态,走子类的重写方法
        Swim s2 = new Swim() {
            @Override
            public void swimming() {
                System.out.println("蛙泳...");
            }
        };

        s2.swimming();
        s2.swimming();
    }
}

注意:

new Swim(){
    @Override
    public void swim() {
        System.out.println("Demo01匿名内部类");
    }
};

这样的话是不会有打印数据的,因为整体只是一个匿名内部类对象,需要再去调用相应的成员

匿名内部类字节码文件反编译看到的效果

实际案例:

public class Test01 {
    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();
        list.add("11");
        list.add("12");
        list.add("13");
        //下面就是一个匿名内部类
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
    }
}

反编译之后

1.6.2  匿名内部类用处

匿名内部类在Java中有着一些重要的用途,其中包括:

  1. 简化代码:使用匿名内部类可以减少代码量,避免编写大量的类定义。

  2. 事件处理器:在GUI编程中常常使用匿名内部类来实现事件处理器,如按钮点击事件、菜单项选择等。

  3. 回调函数:匿名内部类也可以用作回调函数的实现,例如对异步任务的处理。

  4. 接口实现:如果只需要使用接口的一次实例,可以直接使用匿名内部类来实现接口的抽象方法。

  5. 方法重写:可以在匿名内部类中重写父类或接口的方法,以实现特定的逻辑。

总之,匿名内部类提供了一种简洁、灵活的方式来实现某些具体功能,通常用于临时、一次性的场景中。

1.6.3  匿名内部类的使用场景

interface Swim {
    public abstract void swimming();
}

public class Demo07 {
    public static void main(String[] args) {
        // 普通方式传入对象
        // 创建实现类对象
        Student s = new Student();
        
        goSwimming(s);
        // 匿名内部类使用场景:作为方法参数传递
        Swim s3 = new Swim() {
            @Override
            public void swimming() {
                System.out.println("蝶泳...");
            }
        };
        // 传入匿名内部类
        goSwimming(s3);

        // 完美方案: 一步到位
        goSwimming(new Swim() {
            public void swimming() {
                System.out.println("大学生, 蛙泳...");
            }
        });

        goSwimming(new Swim() {
            public void swimming() {
                System.out.println("小学生, 自由泳...");
            }
        });
    }

    // 定义一个方法,模拟请一些人去游泳
    public static void goSwimming(Swim s) {
        s.swimming();
    }
}

总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值