Java内部类是定义在另一个类里面的类。使用内部类的主要原因是它能够访问其外部类的成员,包括私有成员。内部类是一种强大的封装工具,因为它能够将一部分类的实现隐藏在另一个类的内部。Java中的内部类主要可以分为四种类型:
1. 成员内部类(Non-static Nested Class)
- 定义在类的内部,和方法、变量同级。
- 可以无条件访问外部类的所有成员属性和方法(包括私有的)。
- 需要先创建外部类的实例,然后通过外部类的实例创建内部类的实例。
使用Java内部类是一种编程技巧,允许你将一个类定义在另一个类的内部,从而密切地连接两个类的关系,同时保持它们的代码逻辑上的整洁。内部类提供了几个重要的特性和优势,可以在特定的编程场景中非常有用。
为什么需要使用内部类呢?
内部类主要有以下几个用途和优点:
- 对同一个包中其他类隐藏:内部类可以被声明为私有(private)、保护(protected)或者公共(public),或者默认不指定(包级私有),这样可以控制其他类对内部类的访问级别,实现封装和隐藏。
- 访问外部类的成员:内部类方法可以访问定义这个类的外围(外部)类中的数据,包括私有的字段和方法。这种能力使内部类成为实现某些特定功能的理想选择,尤其是当这些功能需要访问外围类的私有数据时。
使用内部类访问对象状态
- 访问数据字段:内部类不仅可以访问自身的数据字段,还可以直接访问创建它的外围类对象的数据字段。
- 隐式引用:每个内部类的实例都自动持有一个指向其外围类实例的隐式引用。这个引用在内部类的代码中是不可见的,但它允许内部类访问外围类的成员。
- 外围类的引用设置:当内部类的对象被创建时,外围类的引用隐式地传递给内部类。编译器会自动修改内部类的构造器,添加一个外围类引用的参数。
- 私有内部类:将内部类声明为私有,限制了只有外围类可以构造和访问内部类的对象,这提供了一种强大的封装机制。
内部类的特殊语法规则
- 外围类引用语法:在内部类中,可以通过
OuterClass.this
表达式访问外围类的实例。这种语法在访问外围类的成员时特别有用,尤其是在内部类和外围类有同名成员的情况下。 - 创建内部类对象的语法:要从外围类的非静态上下文之外创建内部类的实例,需要使用特殊的语法
outerObject.new InnerClass(constructionParameters)
。这种语法明确指出了内部类实例的创建依赖于外围类的一个实例。
内部类是Java中一个强大的特性,允许更紧密地将两个类的行为和状态绑定在一起,同时还提供了优秀的封装性。通过内部类,可以实现更加模块化和维护性更好的代码设计。
2. 局部内部类(Local Classes)
- 定义在一个方法或任意作用域内。
- 只在定义它的方法或作用域内可见和可用。
- 可以访问外部类的成员和final或effectively final的局部变量。
局部内部类是定义在外围类的某个方法中的类,仅在该方法的作用域内可见和可用。
- 作用域限定:声明局部类时,不能有访问说明符(即
public
和private
)。局部类的作用域被限定在声明这个局部类的块中。 - 对外部世界的隐蔽性:局部类对外部世界完全不可见,甚至外围类中非定义该内部类的其他方法和代码都不能访问它。
由外部方法访问变量
- 局部类不仅能访问外部类的字段,还能访问局部变量,但这些局部变量必须是实际上的最终变量(即effectively final),这意味着一旦赋值就不能更改。
- 编译器会检测对局部变量的访问,在局部内部类中为每个变量建立相应的实例字段,并将局部变量复制到构造器中,从而能够初始化这些实例字段。
3. 匿名内部类(Anonymous Inner Classes)
- 没有名称的局部内部类。
- 用于实例化接口或抽象类,常用于事件监听器或小型委托任务。
- 可以立即定义和实例化。
4. 静态内部类(Static Nested Classes)
- 定义为外部类的静态成员,可以像其他静态成员一样访问。
- 可以访问外部类的所有静态成员和方法,包括私有的。
- 不需要外部类的实例即可创建。
- 如果某个内部类不需要外围类的引用,可以将内部类声明为static
- 只有内部类可以声明为static
- 与常规内部类不同, 静态内部类可以有静态字段和方法
- 在接口中声明的内部类自动是public和static
5. 创建和使用内部类的例子
- 成员内部类:
public class OuterClass {
class InnerClass {
// ...
}
}
// 使用
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
- 局部内部类:
public class OuterClass {
public void myMethod() {
class LocalInnerClass {
// ...
}
LocalInnerClass lic = new LocalInnerClass();
}
}
- 匿名内部类:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类示例");
}
}).start();
- 静态内部类:
public class OuterClass {
static class StaticNestedClass {
// ...
}
}
// 使用
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
内部类提供了一种强大的机制来组织和封装复杂的系统,它们使代码逻辑更加紧密且易于维护。
6. 总结
Java 内部类是定义在另一个类内部的类,它们使得可以将一些逻辑更紧密地封装于类的内部,而不是暴露在外部。Java内部类主要分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。
- 成员内部类:它是最常见的内部类形式,定义在类内部,类似于类的一个成员。成员内部类可以无条件访问外部类的所有成员属性和方法,即使是私有的。这种内部类对外部世界是隐藏的,但可以被外部类的方法或者与之相同的包中的其他类访问。
- 局部内部类:局部内部类是定义在一个块里面的类,比如一个方法或者一个作用域块。它们仅在定义它们的块内部可见和可用。局部内部类对实现细节的隐藏尤其有用。
- 匿名内部类:匿名内部类是没有名字的内部类。它通常用于实现接口或继承类的简短实例。由于没有类名,所以不能使用构造器创建实例,而是通过实例化表达式来构造。匿名内部类是一种轻量级的编码方式,特别适合创建简单的实现或继承类的实例。
- 静态内部类:静态内部类是用static修饰的内部类,它不需要外部类的实例就可以被创建。静态内部类不能访问外部类的实例成员,只能访问外部类的静态成员。这种内部类通常用于当内部类与外部类的实例无关时。
每种类型的内部类都有其特定的用途和优点,例如提高封装性、更好地组织代码、减少类的命名冲突等。