【Java】内部类

概述

内部类是声明在另一个类的内部的类。本质上,它是一个被"嵌套"在外部类中的类。

当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。总的来说,遵循高内聚、低耦合的面向对象开发原则。

内部类的分类

类型 所在位置 是否依赖外部类对象 特点
成员内部类 类中,方法外 依赖 最常见,可访问外部类成员
静态内部类 类中,方法外,带 static 不依赖 不持有外部类引用,类似外部类的静态成员
局部内部类 方法内 依赖 方法内定义,仅方法内可见
匿名内部类 局部类的一种特殊形式 依赖 用来临时创建某个类或接口的对象(一次性使用)

(静态)成员内部类

如果成员内部类中不使用外部类的非静态成员,那么通常将内部类声明为静态内部类,否则声明为非静态内部类。

java 复制代码
[修饰符] class 外部类 {
    [其他修饰符] [static] class 内部类 {
    }
}
  • 成员内部类作为类的成员的角色
    • 和外部类不同,内部类还可以声明为privateprotected
    • 可以调用外部类的结构。(⚠️在静态内部类中不能使用外部类的非静态成员)
  • 成员内部类作为类的角色
    • 可以在内部定义属性、方法、构造器等结构;
    • 可以继承父类和实现父接口,和外部类的父类和父接口无关;
    • 可以声明为抽象类 ,因此可以被其它的内部类继承;
    • 可以声明为final的,表示不能被继承;
    • 编译后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)

注意点

  • 外部类访问成员内部类的成员,需要内部类.成员内部类对象.成员的方式;
  • 成员内部类可以直接使用外部类的所有成员,包括私有的数据;

实例化

  • 非静态成员内部类

和外部类对象绑定:内部类对象必须依赖外部类对象。外部类可通过 new Inner() 创建内部类对象(必须有外部类对象前缀)。

java 复制代码
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.show();
  • 静态成员内部类

不依赖外部类对象(不持有外部类实例)。可以访问外部类的静态成员,但不能访问非静态成员。

java 复制代码
Outer.Inner inner = new Outer.Inner();
inner.show();

局部(匿名)内部类

局部内部类是定义在方法内部、代码块内部或构造器内部的类。作用域仅限于该局部范围内,外部无法直接访问。

java 复制代码
// 非匿名
[修饰符] class 外部类 {
    [修饰符] 返回值类型 方法名([形参列表]) {
            [final/abstract] class 内部类 {
    	}
    }    
}
  • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。
    • 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类。
  • 不能使用访问修饰符,因为它是局部变量级别的类型。
  • 作用域仅限于该局部范围内,外部无法直接访问。
  • 可以访问外部类成员,包含静态成员。
  • 可以访问方法中的局部变量,但要求变量为 final 或 effectively final。Java 8 之后局部变量无需显式声明 final,只要它不被重新赋值(effectively final)即可。原因:局部变量属于栈内存,方法结束后销毁,但局部内部类对象可能还活着,因此 JVM 会复制一份局部变量到内部类中,需要保证不变性。
  • 局部内部类可以定义 static 成员。
java 复制代码
public class Outer {
    private String name = "OuterName";
    private static String a = "oa";

    public void doWork() {
        int count = 5; // effectively final

        class Worker {
            static int x = 0;
            public void execute() {
                x = 1;
                System.out.println("访问外部类成员: " + name);
                System.out.println("访问外部类static成员: " + a);
                System.out.println("访问方法局部变量: " + count);
            }
        }

        Worker w = new Worker();
        w.execute();
    }

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

匿名内部类是一种没有名字的局部内部类,通常用来简化代码,尤其在需要临时创建某个类的实例(通常是接口或抽象类)时使用。

java 复制代码
父类/接口 类型 变量 = new 父类/接口() {
    // 重写方法
};

传统方式:需要写一个单独的类文件 / 内部类实现一个接口。

java 复制代码
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Running...");
    }
}

然后使用

java 复制代码
Runnable r = new MyRunnable();

使用匿名内部类,节省代码、逻辑更集中,不用专门创建一个新类。

java 复制代码
Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("Running...");
    }
};

匿名内部类最常见的用途就是实现接口。

java 复制代码
interface Greeting {
    void sayHello();
}

public class Main {
    public static void main(String[] args) {
        Greeting g = new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("Hello from anonymous class!");
            }
        };

        g.sayHello();
        
        ///// or
        new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("Hello from anonymous class!");
            }
        }.sayHello();
    }
}

匿名内部类的对象作为实参。

java 复制代码
interface A {
	void method();
}

public class Test {
    public static void test(A a) {
    	a.method();
    }
    
    public static void main(String[] args) {
    	test(new A() {
			@Override
			public void method() {
				System.out.println("aaaa");
			}
    	});
    }   
}
java 复制代码
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("线程运行");
    }
}).start();
相关推荐
小张快跑。3 分钟前
Maven指定版本下载以及相关配置
java·maven
zhishidi5 分钟前
Spring @Scheduled注解调度机制详解
java·python·spring
⑩-6 分钟前
Blocked与Wati的区别
java·开发语言
AAA简单玩转程序设计8 分钟前
救命!Java这3个小技巧,写起来爽到飞起✨
java
IManiy15 分钟前
Java表达式引擎技术选型分析(SpEL、QLExpress)
java·开发语言
历程里程碑22 分钟前
C++ 17异常处理:高效捕获与精准修复
java·c语言·开发语言·jvm·c++
雨雨雨雨雨别下啦24 分钟前
ssm复习总结
java·开发语言
速易达网络42 分钟前
基于Java Servlet的用户登录系统设计与实现
java·前端·mvc
散一世繁华,颠半世琉璃1 小时前
从 0 到 1 优化 Java 系统:方法论 + 工具 + 案例全解析
java·性能优化·操作系统
JasmineWr1 小时前
Java SPI和OSGi
java·开发语言