内部类详解:Java中的嵌套艺术
一、什么是内部类?
顾名思义,它是一个类的内部定义的另一个类。
这是 java 语言中一个独特而强大的特性
就像现实生活中,房子包含房间一样
主要包含四大类:
成员内部类、静态内部类、局部内部类、匿名内部类
二、内部类的历史背景及意义
现在我们大致了解了什么是内部类
但是为什么要有内部类这个东西存在呢?
追根溯源往往可以帮助我们理解事情本质
在 java 诞生初期
开发者们发现
当需要实现事件监听、线程回调时
经常需要被迫给一个简单的任务创建一个单独的类文件
导致项目目录变成一个“垃圾场”
神说要有光
于是 内部类 诞生了
它有什么意义?
1.更好地体现了“包含”关系,符合现实逻辑,帮助开发者更好开发
2.不破坏封装性的前提下,访问外部类的成员属性和方法变得更方便了
3.内部类同样可以继承类或实现接口,间接实现了多重继承的效果
4.代码瘦身:避免了类名比逻辑还长的情况出现
三、内部类
接下来我们详细介绍一下四种内部类
1、成员内部类
成员内部类是最常用的内部类,它就像是外部类的一个成员变量
特点:
1.可以直接访问外部类的所有成员属性和成员方法(包括private、静态)
2.在外部类中,可以直接访问内部类中所有的成员属性和方法(也包括private),但是要借助内部类的对象调用
3.成员内部类不能定义 static 成员属性或者 static 成员方法
深度探索:非静态内部类不能定义 static 成员属性和方法-CSDN博客https://blog.csdn.net/qq_73698057/article/details/149978575?sharetype=blogdetail&sharerId=149978575&sharerefer=PC&sharesource=qq_73698057&spm=1011.2480.3001.8118 4.内部类方法中、内部类中、外部类中有同名属性,访问时遵循就近原则
public class Car {private String brand = "Toyota";private int speed = 0;// 成员内部类 - 引擎public class Engine {private int horsepower = 150;public void start() {System.out.println(brand + " 引擎启动,马力: " + horsepower);speed = 10; // 可以修改外部类的成员}public void showInfo() {System.out.println("品牌: " + brand + ", 当前速度: " + speed);}}public void drive() {// 外部类访问内部类需要创建对象Engine engine = new Engine();engine.start();engine.showInfo();}
}// 使用示例
public class Test {public static void main(String[] args) {Car car = new Car();car.drive();// 创建内部类对象的另一种方式Car.Engine engine = car.new Engine();engine.showInfo();}
}
2、静态内部类
是成员内部类的一种特殊形式
使用 static关键字 修饰,更像一个独立的类
注意:
static 内部类中可以定义 static属性和方法
static 内部类中只能访问外部类类中的 static 属性和方法(静态访问静态)
外部类中可以访问 static 内部类中的所有属性和方法
public class MathUtils {private static final double PI = 3.14159;private String instanceField = "实例字段"; // 静态内部类无法访问// 静态内部类public static class Calculator {private static int count = 0;public static double circleArea(double radius) {count++; // 可以有静态成员return PI * radius * radius; // 只能访问外部类的静态成员}public static int getCount() {return count;}}
}// 使用示例
public class StaticInnerTest {public static void main(String[] args) {double area = MathUtils.Calculator.circleArea(5.0);System.out.println("圆面积: " + area);System.out.println("计算次数: " + MathUtils.Calculator.getCount());}
}
3、局部内部类(不常用)
局部内部类定义在方法中
特点:
作用范围只能是在当前方法中
从内部类引用的本地变量必须是最终变量或实际上的最终变量
解释一下这句话:
“本地变量”:指的是在方法内部定义的局部变量,包括方法参数,例如:
public class Example {public void method() {int localVariable = 10; // 这就是本地变量class LocalInnerClass {// 在这里引用本地变量}} }
“最终变量”:用 final 修饰的变量
“实际上的最终变量”:jdk8 引入的概念,即使没有显示使用 final 关键字,但是如果变量在初始化之后从未被修改,那么它就被认为是实际上的最终变量
也就是说,局部内部类里想修改变量值是不可以的,只能修改常量
public class LocalInnerExample {public void processData() {final int multiplier = 10; // 必须是final或实际上final// 局部内部类class LocalProcessor {public void process(int value) {System.out.println("处理结果: " + (value * multiplier));}}LocalProcessor processor = new LocalProcessor();processor.process(5);}
}
4、匿名内部类——某种意义上可以替代接口和抽象类
没有名字的内部类
本身是一个特殊的局部内部类(定义在方法中)
注意:
匿名内部类必须依托于一个接口或者一个父类(这个父类可以是抽象类或者普通类)
匿名内部类在声明的时候就要创建对象,否则后面无法创建
匿名内部类中无法定义构造器
功能:
1.匿名内部类实现接口
2.匿名内部类实现抽象类
3.匿名内部类对象使用父类构造方法
// 定义一个接口
interface ClickListener {void onClick();
}// 定义一个抽象类
abstract class Animal {abstract void makeSound();public void sleep() {System.out.println("动物在睡觉");}
}public class AnonymousInnerExample {public static void main(String[] args) {// 1. 实现接口的匿名内部类ClickListener button = new ClickListener() {@Overridepublic void onClick() {System.out.println("按钮被点击了!");}};button.onClick();// 2. 继承抽象类的匿名内部类Animal dog = new Animal() {@Overridevoid makeSound() {System.out.println("汪汪汪!");}};dog.makeSound();dog.sleep();// 3. 直接使用匿名内部类处理事件(常见用法)processClick(new ClickListener() {@Overridepublic void onClick() {System.out.println("这是匿名处理的点击事件");}});}public static void processClick(ClickListener listener) {listener.onClick();}
}
四、易踩坑的点
创建内部类对象的语法易出错:
public class CreationError {class Inner {void display() {System.out.println("内部类方法");}}public static void main(String[] args) {CreationError outer = new CreationError();// 错误的创建方式// Inner inner = new Inner(); // 编译错误// 正确的创建方式Inner inner1 = outer.new Inner(); // 方式1Inner inner2 = new CreationError().new Inner(); // 方式2}
}