内部类分为四种
一.实例内部类
class Outclass {
public int date1 = 1;
public static int date2 = 2;
private int date3 = 3;
class InnerClass {
public int date4 = 4;
public static final int date5 = 5;
private int date6 = 6;
public void test() {
System.out.println("InnerClass::test()");
System.out.println(date1); // 访问外部类的实例变量
System.out.println(date2); // 访问外部类的静态变量
System.out.println(date3); // 访问外部类的私有变量(通过外部类实例)
System.out.println(date4); // 访问内部类的实例变量
System.out.println(date5); // 访问内部类的静态常量
System.out.println(date6); // 访问内部类的私有变量
}
}
public void test() {
System.out.println("Outclass::test()");
}
}
public class Main {
public static void main(String[] args) {
Outclass outclass = new Outclass(); // 创建外部类的实例
Outclass.InnerClass innerclass = outclass.new InnerClass(); // 通过外部类实例创建内部类实例
innerclass.test(); // 调用内部类的test方法
}
}
输出结果
运行修正后的代码,输出结果如下:
InnerClass::test()
1
2
3
4
5
6
代码解释
-
外部类
Outclass
:-
包含实例变量
date1
、静态变量date2
和私有变量date3
。 -
包含一个非静态内部类
InnerClass
,内部类可以访问外部类的所有变量(包括私有变量)。
-
-
内部类
InnerClass
:-
包含实例变量
date4
、静态常量date5
和私有变量date6
。 -
在
test
方法中,内部类可以访问外部类的变量(通过this
隐式引用外部类实例)。
-
-
Main
类:-
创建了一个
Outclass
的实例outclass
。 -
通过
outclass
实例创建了InnerClass
的实例innerclass
。 -
调用了
innerclass.test()
方法,展示了内部类可以访问外部类的变量。
-
关键点
-
非静态内部类:
-
非静态内部类需要依赖外部类的实例才能创建。
-
内部类可以访问外部类的所有变量(包括私有变量)。
-
-
静态内部类:
-
如果内部类是静态的(
static
),则可以直接通过外部类的类名访问,而不需要外部类的实例
-
二。静态内部类
Outclass
类
class Outclass {
public int date1 = 1; // 实例变量
public static int date2 = 2; // 静态变量
private int date3 = 3; // 私有实例变量
static class InnerClass {
public int date4 = 4; // 实例变量
public static final int date5 = 5; // 静态常量
private int date6 = 6; // 私有实例变量
public void test() {
System.out.println("InnerClass::test()");
}
}
public void test() {
System.out.println("Outclass::test()");
}
}
-
InnerClass
被定义为static
内部类,这意味着它不需要依赖外部类的实例即可创建。 -
静态内部类不能访问外部类的实例变量(如
date1
和date3
),但可以访问外部类的静态变量(如date2
)。
Main
类
public class Main {
public static void main(String[] args) {
Outclass outclass = new Outclass(); // 创建外部类的实例
Outclass.InnerClass innerclass = new Outclass.InnerClass(); // 创建静态内部类的实例
innerclass.test(); // 调用内部类的test方法
}
}
-
创建了一个
Outclass
的实例outclass
。 -
创建了一个
Outclass.InnerClass
的实例innerclass
。由于InnerClass
是静态的,可以直接通过Outclass.InnerClass
来创建实例,而不需要外部类的实例。 -
调用了
innerclass.test()
方法。
输出结果
运行这段代码,输出结果如下:
InnerClass::test()
关键点
-
静态内部类的特点:
-
静态内部类不需要外部类的实例即可创建。
-
静态内部类不能访问外部类的实例变量,但可以访问外部类的静态变量。
-
静态内部类的实例与外部类的实例无关。
-
-
非静态内部类与静态内部类的区别:
-
非静态内部类:
-
需要依赖外部类的实例才能创建。
-
可以访问外部类的所有变量(包括私有变量)。
-
-
静态内部类:
-
不需要外部类的实例即可创建。
-
只能访问外部类的静态变量。
-
-
示例补充
为了进一步展示静态内部类的特点,可以尝试在InnerClass
中访问外部类的变量:
修改InnerClass
static class InnerClass {
public int date4 = 4;
public static final int date5 = 5;
private int date6 = 6;
public void test() {
System.out.println("InnerClass::test()");
// System.out.println(date1); // 错误:不能访问外部类的实例变量
System.out.println(date2); // 正确:可以访问外部类的静态变量
}
}
运行结果
运行这段代码,输出结果如下:
InnerClass::test()
2
总结
-
静态内部类:
-
不需要外部类的实例即可创建。
-
只能访问外部类的静态变量。
-
-
非静态内部类:
-
需要外部类的实例才能创建。
-
可以访问外部类的所有变量(包括私有变量)。
-
三.局部内部类
局部内部类(Local Inner Class)是一种特殊的内部类,它定义在方法的作用域内,通常用于实现特定方法的逻辑。局部内部类的特点和使用场景与其他内部类有所不同,以下是详细的介绍和示例。
局部内部类的特点
-
作用域限制:
-
局部内部类只能在定义它的方法的作用域内使用。
-
它不能被其他方法访问,也不能被外部类的其他部分访问。
-
-
访问权限:
-
局部内部类可以访问外部类的所有成员(包括私有成员)。
-
局部内部类可以访问其所在方法的局部变量,但这些局部变量必须是
final
的(或者在Java 8及以上版本中,局部变量可以是“实际上不可变”的)。
-
-
用途:
-
局部内部类通常用于实现特定方法的逻辑,例如回调接口的实现、匿名类的替代等。
-
它可以隐藏实现细节,使代码更加模块化和清晰。
-
示例代码
以下是一个包含局部内部类的示例代码:
class Outclass {
private int outValue = 10; // 外部类的私有变量
public void test() {
final int localVar = 20; // 方法的局部变量,必须是final或实际上不可变
// 定义局部内部类
class LocalInnerClass {
public void display() {
// 访问外部类的私有变量
System.out.println("Outclass.outValue: " + outValue);
// 访问方法的局部变量
System.out.println("Local variable: " + localVar);
}
}
// 创建局部内部类的实例并调用方法
LocalInnerClass localInner = new LocalInnerClass();
localInner.display();
}
}
public class Main {
public static void main(String[] args) {
Outclass outclass = new Outclass();
outclass.test(); // 调用外部类的方法,内部会创建局部内部类的实例并调用其方法
}
}
输出结果
运行这段代码,输出结果如下:
Outclass.outValue: 10
Local variable: 20
代码解释
-
外部类
Outclass
:-
包含一个私有变量
outValue
。 -
包含一个方法
test
,在该方法中定义了一个局部内部类LocalInnerClass
。
-
-
局部内部类
LocalInnerClass
:-
定义在
test
方法的作用域内。 -
可以访问外部类的私有变量
outValue
。 -
可以访问方法的局部变量
localVar
,但localVar
必须是final
的(或实际上不可变的)。
-
-
Main
类:-
创建了一个
Outclass
的实例outclass
。 -
调用了
outclass.test()
方法,该方法内部创建了局部内部类的实例并调用了其display
方法。
-
关键点
-
局部变量的不可变性:
-
在Java 8及以上版本中,局部变量不需要显式声明为
final
,但它们必须是“实际上不可变的”,即在方法的作用域内不能被修改。 -
如果局部变量的值在方法中被修改,则无法在局部内部类中使用该变量。
-
-
局部内部类的用途:
-
局部内部类通常用于实现特定方法的逻辑,例如实现回调接口或替代匿名类。
-
它可以隐藏实现细节,使代码更加模块化和清晰。
-
示例:实现回调接口
假设有一个回调接口Callback
,我们可以在方法中定义一个局部内部类来实现该接口:
interface Callback {
void execute();
}
class Outclass {
public void test() {
final String message = "Hello, World!";
// 定义局部内部类实现Callback接口
class LocalCallback implements Callback {
@Override
public void execute() {
System.out.println(message); // 访问方法的局部变量
}
}
// 创建局部内部类的实例并调用方法
Callback callback = new LocalCallback();
callback.execute();
}
}
public class Main {
public static void main(String[] args) {
Outclass outclass = new Outclass();
outclass.test(); // 调用外部类的方法,内部会创建局部内部类的实例并调用其方法
}
}
输出结果
运行这段代码,输出结果如下:
Hello, World!
总结
-
局部内部类:
-
定义在方法的作用域内,只能在该方法中使用。
-
可以访问外部类的所有成员和方法的局部变量(局部变量必须是
final
或实际上不可变的)。 -
通常用于实现特定方法的逻辑,例如回调接口的实现。
-
通过合理使用局部内部类,可以使代码更加清晰和模块化,同时隐藏实现细节。
四.匿名内部类
匿名内部类(Anonymous Inner Class)是Java中一种特殊的内部类,它没有类名,通常用于创建单次使用的对象。匿名内部类通常用于实现接口或继承类,并且可以直接在代码中实例化,而不需要单独定义一个类。
匿名内部类的特点
-
没有类名:
-
匿名内部类没有显式的类名,因此不能通过类名来创建多个实例。
-
它只能被实例化一次。
-
-
实现接口或继承类:
-
匿名内部类可以实现一个接口或继承一个类(但不能同时实现接口和继承类)。
-
如果继承了一个类,它必须是该类的一个子类。
-
如果实现了一个接口,它必须实现接口中的所有抽象方法。
-
-
访问权限:
-
匿名内部类可以访问外部类的所有成员(包括私有成员)。
-
匿名内部类可以访问其所在方法的局部变量,但这些局部变量必须是
final
的(或者在Java 8及以上版本中,局部变量可以是“实际上不可变”的)。
-
-
用途:
-
匿名内部类通常用于实现回调接口、事件监听器、线程启动等场景。
-
它可以简化代码,避免定义单独的类。
-
匿名内部类的语法
匿名内部类的语法如下:
new 父类构造器(参数) {
// 匿名内部类的成员(方法、字段等)
}
或者:
new 实现的接口() {
// 匿名内部类的成员(方法、字段等)
}
示例代码
实现接口的匿名内部类
假设有一个接口Callback
:
interface Callback {
void execute();
}
使用匿名内部类实现该接口:
public class Main {
public static void main(String[] args) {
// 创建匿名内部类的实例
Callback callback = new Callback() {
@Override
public void execute() {
System.out.println("Callback executed!");
}
};
// 调用匿名内部类的方法
callback.execute();
}
}
继承类的匿名内部类
假设有一个类Parent
:
class Parent {
public void show() {
System.out.println("Parent show()");
}
}
使用匿名内部类继承该类:
public class Main {
public static void main(String[] args) {
// 创建匿名内部类的实例
Parent parent = new Parent() {
@Override
public void show() {
System.out.println("Anonymous class show()");
}
};
// 调用匿名内部类的方法
parent.show();
}
}
输出结果
运行上述代码,输出结果如下:
Callback executed!
Anonymous class show()
匿名内部类的使用场景
-
事件监听器:
-
在GUI编程中,匿名内部类常用于实现事件监听器。
-
例如,在Swing中为按钮添加点击事件监听器:
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Main { public static void main(String[] args) { JButton button = new JButton("Click Me"); // 使用匿名内部类实现事件监听器 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button clicked!"); } }); } }
-
-
线程启动:
-
匿名内部类可以用于实现
Runnable
接口,启动线程:public class Main { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("Thread is running!"); } }); thread.start(); } }
-
-
回调接口:
-
匿名内部类常用于实现回调接口,例如在多线程编程或异步操作中:
interface Callback { void execute(); } public class Main { public static void main(String[] args) { Callback callback = new Callback() { @Override public void execute() { System.out.println("Callback executed!"); } }; callback.execute(); } }
-
匿名内部类与局部变量的访问
在匿名内部类中访问方法的局部变量时,局部变量必须是final
的(或者在Java 8及以上版本中,局部变量可以是“实际上不可变”的”)。例如:
public class Main {
public static void main(String[] args) {
final int localVar = 10; // 局部变量必须是final或实际上不可变
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Local variable: " + localVar);
}
};
runnable.run();
}
}
输出结果
运行上述代码,输出结果如下:
Local variable: 10
总结
-
匿名内部类:
-
没有类名,只能被实例化一次。
-
可以实现接口或继承类。
-
可以访问外部类的所有成员和方法的局部变量(局部变量必须是
final
或实际上不可变的)。 -
常用于实现回调接口、事件监听器、线程启动等场景。
-
匿名内部类是Java中一种非常灵活和强大的特性,能够简化代码并提高开发效率。