💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 匿名类和内部类 * ## 内部类的范围 内部类有以下几种范围: ### 1. 成员内部类(Member Inner Class) 成员内部类是定义在外部类的成员位置上的类,它可以访问外部类的所有成员,包括私有成员,也可以被外部类以及其他类访问。 - 语法格式 ~~~ public class Outer { // 定义外部类 public class Inner { // 定义内部类 } } ~~~ ### 2. 静态内部类(Static Inner Class) 静态内部类是定义在外部类的静态成员位置上的类,它不能访问外部类的非静态成员,但可以访问外部类的静态成员。 - 语法格式 ``` public class OuterClass { private static int outerStaticField; public static class InnerClass { //定义静态内部类 } } ``` ### 3. 局部内部类(Local Inner Class) 局部内部类是定义在方法或语句块内部的类,它只能在该方法或语句块内部访问,不能被外部类和其他类访问。 - 语法格式 ``` ~~~ public classOuterClass { public void method() { //定义成员方法 class InnerClass { //定义局部内部类 } } } ~~~ ``` ### 4. 匿名内部类(Anonymous Inner Class) 匿名内部类是一种没有名字的内部类,它可以用来创建一个只需要使用一次的类。匿名内部类通常用于实现某个接口或继承某个类,并重写其中的方法。 - 语法格式 ``` new 接口名/类名() { // 匿名类的成员变量和方法的定义 }; ``` ## 1. 主要解决了以下几个问题: ### 1.1. 简化代码。 匿名类可以避免编写完整的类来实现简单的接口或继承抽象类,简化代码量。内部类可以隐藏实现细节,保持外部类的简洁性。 ``` // 简化以下代码 public interface Runnable { // 定义Runnable接口 void run(); } // 语法格式是实例化接口或类 new 接口名/类名() {} Runnable runnable = new Runnable() { // 使用匿名内部类实现Runnable接口 @Override public void run() { System.out.println("Running..."); } }; ``` 需要注意的是,匿名类只能实现一个接口或继承一个类,而且它没有构造函数,因此不能在其中初始化成员变量。如果需要实现多个接口或者需要初始化成员变量,可以考虑使用具名的内部类。 ***** ### 1.2. 增加封装性。 内部类可以访问外部类的私有成员,增加了封装性。局部内部类的作用域只在方法内,更加封装。 ``` public class Outer { // 定义外部类 private int num = 10; // 私有成员 public class Inner { // 定义内部类 public void show() { System.out.println(num); // 访问外部类的私有成员 } } } ``` ***** ### 1.3. 解决多继承问题。 Java只支持单继承,通过内部类可以部分模拟多继承的效果,一个内部类可以继承一个类,而外部类可以继承另一个类。 ``` public class Outer { // 定义外部类 public void show() { } } public class Outer2 { // 定义另一个外部类 public void display() { } } public class Test extends Outer { // 外部类继承Outer public class Inner extends Outer2 { // 内部类继承Outer2 public void print() { show(); // 调用外部类方法 display(); // 调用内部类方法 } } } ``` ***** ### 1.4. 隐藏实现细节。 内部类的作用域仅在外部类内,可以隐藏实现细节,保持外部类的简洁。 ``` public class Outer { // 定义外部类 private int num = 10; // 外部类私有成员 public class Inner { // 定义内部类 private int innerNum = 20; // 内部类私有成员 public void show() { System.out.println(num); // 访问外部类的私有成员 System.out.println(innerNum); // 访问内部类的私有成员 } } public void display() { // 外部类的方法 Inner inner = new Inner(); // 实例化内部类 inner.show(); // 通过外部类方法间接调用内部类方法 } } ``` 外部类的外部无法直接访问Inner类的私有成员innerNum,实现细节被隐藏。只有通过Outer类的方法才能间接使用Inner类,这增加了封装性。 ***** ### 1.5. 避免命名空间污染。 使用内部类可以避免在同一个命名空间下定义太多的类,防止命名空间污染。 ``` public class Outer { // 定义外部类 public class Inner1 { // 定义内部类1 } public class Inner2 { // 定义内部类2 } public class Inner3 { // 定义内部类3 } } ``` 如果不使用内部类,需要在同一个命名空间下定义三个类,这会导致命名空间过于繁杂,内部类可以避免这种情况,防止命名空间污染。 ***** ## 2. 匿名类示例——创建线程对象: 使用了匿名类来创建一个`Runnable`对象,重写了`run`方法,并在其中输出了一条消息。然后,我们将这个`Runnable`对象传递给`Thread`构造函数,创建了一个新的线程对象,并调用`start`方法来启动该线程。 ``` public class AnonymousClassExample { public static void main(String[] args) { // 使用匿名类创建一个Runnable对象 Runnable runnable = new Runnable() { @Override public void run() { System.out.println("Hello, World!"); } }; // 使用Runnable对象创建一个线程 Thread thread = new Thread(runnable); thread.start(); } } ``` ***** ## 3. 内部类示例——迭代器: 定义了一个成员内部类`InnerIterator`,它实现了`Iterator`接口,并重写了其中的方法。在`InnerClassExample`类中,我们定义了一个`iterator`方法,用于返回一个`InnerIterator`对象。在`main`方法中,我们使用`iterator`方法获取一个迭代器对象,并使用`while`循环输出迭代器中的元素。由于`InnerIterator`是`InnerClassExample`的成员内部类,所以它可以访问`elements`和`size`成员变量。 ``` import java.util.Iterator; public class InnerClassExample { // 成员变量 private Object[] elements; private int size; // 构造方法 public InnerClassExample(Object[] elements) { this.elements = elements; this.size = elements.length; } // 获取迭代器对象的方法 public Iterator<Object> iterator() { return new InnerIterator(); } // 成员内部类 private class InnerIterator implements Iterator<Object> { // 成员变量 private int index; // 构造方法 public InnerIterator() { this.index = 0; } // 判断是否还有下一个元素 @Override public boolean hasNext() { return index < size; } // 获取下一个元素 @Override public Object next() { if (hasNext()) { return elements[index++]; } else { throw new IndexOutOfBoundsException(); } } // 移除当前元素(不支持) @Override public void remove() { throw new UnsupportedOperationException(); } } // 测试代码 public static void main(String[] args) { Object[] elements = {1, 2, 3, 4, 5}; InnerClassExample example = new InnerClassExample(elements); Iterator<Object> iterator = example.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } } ``` 输出结果: ``` 1 2 3 4 5 ``` *****