内部类分为四种
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中一种非常灵活和强大的特性,能够简化代码并提高开发效率。