Skip to content

12.4 内部类(入门)

内部类的概念

内部类是定义在另一个类内部的类。内部类可以访问外部类的成员,包括私有成员。

内部类的类型

在 Java 中,内部类主要分为四种类型:

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类

成员内部类

成员内部类是定义在外部类的成员位置的内部类,没有 static 修饰。

语法:

java
class 外部类 {
    // 外部类成员
    
    class 内部类 {
        // 内部类成员
    }
}

示例:

java
public class OuterClass {
    private int outerVar = 100;
    private static int staticOuterVar = 200;
    
    // 成员内部类
    class InnerClass {
        private int innerVar = 300;
        
        public void display() {
            // 可以访问外部类的实例变量
            System.out.println("outerVar: " + outerVar);
            // 可以访问外部类的静态变量
            System.out.println("staticOuterVar: " + staticOuterVar);
            // 可以访问内部类的实例变量
            System.out.println("innerVar: " + innerVar);
        }
    }
    
    public void createInner() {
        // 在外部类中创建内部类的对象
        InnerClass inner = new InnerClass();
        inner.display();
    }
    
    public static void main(String[] args) {
        // 创建外部类的对象
        OuterClass outer = new OuterClass();
        // 通过外部类对象创建内部类的对象
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.display();
        
        // 调用外部类的方法创建内部类对象
        outer.createInner();
    }
}

静态内部类

静态内部类是定义在外部类的成员位置,使用 static 修饰的内部类。

语法:

java
class 外部类 {
    // 外部类成员
    
    static class 内部类 {
        // 内部类成员
    }
}

示例:

java
public class OuterClass {
    private int outerVar = 100;
    private static int staticOuterVar = 200;
    
    // 静态内部类
    static class StaticInnerClass {
        private int innerVar = 300;
        private static int staticInnerVar = 400;
        
        public void display() {
            // 不能访问外部类的实例变量
            // System.out.println("outerVar: " + outerVar);
            // 可以访问外部类的静态变量
            System.out.println("staticOuterVar: " + staticOuterVar);
            // 可以访问内部类的实例变量
            System.out.println("innerVar: " + innerVar);
            // 可以访问内部类的静态变量
            System.out.println("staticInnerVar: " + staticInnerVar);
        }
        
        public static void staticDisplay() {
            // 不能访问外部类的实例变量
            // System.out.println("outerVar: " + outerVar);
            // 可以访问外部类的静态变量
            System.out.println("staticOuterVar: " + staticOuterVar);
            // 不能访问内部类的实例变量
            // System.out.println("innerVar: " + innerVar);
            // 可以访问内部类的静态变量
            System.out.println("staticInnerVar: " + staticInnerVar);
        }
    }
    
    public static void main(String[] args) {
        // 直接创建静态内部类的对象,不需要外部类对象
        OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();
        inner.display();
        
        // 调用静态内部类的静态方法
        OuterClass.StaticInnerClass.staticDisplay();
    }
}

局部内部类

局部内部类是定义在方法或代码块中的内部类。

语法:

java
class 外部类 {
    // 外部类成员
    
    方法返回类型 方法名() {
        // 方法体
        
        class 内部类 {
            // 内部类成员
        }
        
        // 使用内部类
    }
}

示例:

java
public class OuterClass {
    private int outerVar = 100;
    private static int staticOuterVar = 200;
    
    public void method() {
        final int localVar = 300; // 局部变量,必须是 final 或 effectively final
        
        // 局部内部类
        class LocalInnerClass {
            private int innerVar = 400;
            
            public void display() {
                // 可以访问外部类的实例变量
                System.out.println("outerVar: " + outerVar);
                // 可以访问外部类的静态变量
                System.out.println("staticOuterVar: " + staticOuterVar);
                // 可以访问方法中的局部变量(必须是 final 或 effectively final)
                System.out.println("localVar: " + localVar);
                // 可以访问内部类的实例变量
                System.out.println("innerVar: " + innerVar);
            }
        }
        
        // 创建局部内部类的对象
        LocalInnerClass inner = new LocalInnerClass();
        inner.display();
    }
    
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.method();
    }
}

匿名内部类

匿名内部类是没有名称的内部类,通常用于创建接口或抽象类的实例。

语法:

java
new 接口或抽象类() {
    // 实现方法
};

示例:

java
// 接口
interface Greeting {
    void sayHello();
}

// 抽象类
abstract class Animal {
    abstract void makeSound();
}

public class AnonymousInnerClassExample {
    public static void main(String[] args) {
        // 使用匿名内部类实现接口
        Greeting greeting = new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("Hello from anonymous inner class!");
            }
        };
        greeting.sayHello();
        
        // 使用匿名内部类继承抽象类
        Animal animal = new Animal() {
            @Override
            void makeSound() {
                System.out.println("Woof! Woof!");
            }
        };
        animal.makeSound();
        
        // 使用匿名内部类作为方法参数
        printMessage(new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("Hello as method parameter!");
            }
        });
    }
    
    public static void printMessage(Greeting greeting) {
        greeting.sayHello();
    }
}

内部类的特点

  1. 访问权限

    • 成员内部类:可以访问外部类的所有成员(包括私有成员)
    • 静态内部类:只能访问外部类的静态成员
    • 局部内部类:可以访问外部类的所有成员,以及方法中的 final 或 effectively final 局部变量
    • 匿名内部类:可以访问外部类的所有成员,以及方法中的 final 或 effectively final 局部变量
  2. 创建方式

    • 成员内部类:需要通过外部类对象创建
    • 静态内部类:可以直接通过外部类名创建,不需要外部类对象
    • 局部内部类:只能在定义它的方法或代码块中创建
    • 匿名内部类:在创建时直接实现接口或继承抽象类
  3. 作用域

    • 成员内部类:与外部类的成员具有相同的作用域
    • 静态内部类:与外部类的静态成员具有相同的作用域
    • 局部内部类:只在定义它的方法或代码块中可见
    • 匿名内部类:只在创建它的地方可见

内部类的应用场景

1. 封装

内部类可以隐藏在外部类中,不被外部代码访问,提高封装性。

示例:

java
public class DataStructure {
    private int[] array;
    
    public DataStructure(int size) {
        array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = i;
        }
    }
    
    // 内部类实现迭代器
    private class Iterator {
        private int index = 0;
        
        public boolean hasNext() {
            return index < array.length;
        }
        
        public int next() {
            return array[index++];
        }
    }
    
    // 提供获取迭代器的方法
    public Iterator getIterator() {
        return new Iterator();
    }
    
    public static void main(String[] args) {
        DataStructure data = new DataStructure(5);
        DataStructure.Iterator iterator = data.getIterator();
        
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

2. 事件处理

匿名内部类常用于事件处理,特别是在 GUI 编程中。

示例:

java
import java.awt.*;
import java.awt.event.*;

public class ButtonClickExample {
    public static void main(String[] args) {
        Frame frame = new Frame("Button Click Example");
        Button button = new Button("Click Me");
        
        // 使用匿名内部类处理按钮点击事件
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button clicked!");
            }
        });
        
        frame.add(button);
        frame.setSize(300, 200);
        frame.setVisible(true);
    }
}

3. 适配器模式

匿名内部类常用于实现适配器模式,只重写需要的方法。

示例:

java
// 适配器接口
interface MouseAdapter {
    void mousePressed();
    void mouseReleased();
    void mouseMoved();
    void mouseClicked();
}

// 抽象适配器类
abstract class AbstractMouseAdapter implements MouseAdapter {
    @Override
    public void mousePressed() {}
    
    @Override
    public void mouseReleased() {}
    
    @Override
    public void mouseMoved() {}
    
    @Override
    public void mouseClicked() {}
}

public class AdapterExample {
    public static void main(String[] args) {
        // 使用匿名内部类实现适配器,只重写需要的方法
        MouseAdapter adapter = new AbstractMouseAdapter() {
            @Override
            public void mouseClicked() {
                System.out.println("Mouse clicked!");
            }
        };
        
        adapter.mouseClicked();
    }
}

4. 工厂方法模式

内部类可以用于实现工厂方法模式,创建不同类型的对象。

示例:

java
interface Shape {
    void draw();
}

class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle");
    }
}

public class ShapeFactory {
    // 静态内部类作为工厂
    public static class Factory {
        public static Shape createShape(String type) {
            if (type.equals("circle")) {
                return new Circle();
            } else if (type.equals("rectangle")) {
                return new Rectangle();
            } else {
                throw new IllegalArgumentException("Invalid shape type");
            }
        }
    }
    
    public static void main(String[] args) {
        Shape circle = ShapeFactory.Factory.createShape("circle");
        circle.draw();
        
        Shape rectangle = ShapeFactory.Factory.createShape("rectangle");
        rectangle.draw();
    }
}

常见问题

1. 内部类访问外部类成员

症状:内部类无法访问外部类的成员

解决方案

  • 成员内部类可以直接访问外部类的所有成员
  • 静态内部类只能访问外部类的静态成员
  • 局部内部类和匿名内部类可以访问外部类的所有成员,以及方法中的 final 或 effectively final 局部变量

示例:

java
public class OuterClass {
    private int outerVar = 100;
    private static int staticOuterVar = 200;
    
    // 成员内部类
    class InnerClass {
        public void accessOuter() {
            System.out.println("outerVar: " + outerVar); // 正确
            System.out.println("staticOuterVar: " + staticOuterVar); // 正确
        }
    }
    
    // 静态内部类
    static class StaticInnerClass {
        public void accessOuter() {
            // System.out.println("outerVar: " + outerVar); // 错误
            System.out.println("staticOuterVar: " + staticOuterVar); // 正确
        }
    }
    
    public void method() {
        final int localVar = 300;
        
        // 局部内部类
        class LocalInnerClass {
            public void accessVariables() {
                System.out.println("outerVar: " + outerVar); // 正确
                System.out.println("staticOuterVar: " + staticOuterVar); // 正确
                System.out.println("localVar: " + localVar); // 正确
            }
        }
    }
}

2. 创建内部类对象

症状:无法创建内部类的对象

解决方案

  • 成员内部类:需要通过外部类对象创建:outer.new InnerClass()
  • 静态内部类:可以直接通过外部类名创建:OuterClass.StaticInnerClass()
  • 局部内部类:只能在定义它的方法或代码块中创建
  • 匿名内部类:在创建时直接实现接口或继承抽象类

示例:

java
public class OuterClass {
    // 成员内部类
    class InnerClass {}
    
    // 静态内部类
    static class StaticInnerClass {}
    
    public void method() {
        // 局部内部类
        class LocalInnerClass {}
        
        // 创建局部内部类的对象
        LocalInnerClass localInner = new LocalInnerClass();
    }
    
    public static void main(String[] args) {
        // 创建外部类对象
        OuterClass outer = new OuterClass();
        
        // 创建成员内部类的对象
        OuterClass.InnerClass inner = outer.new InnerClass();
        
        // 创建静态内部类的对象
        OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
        
        // 创建匿名内部类的对象
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Anonymous inner class");
            }
        };
    }
}

3. 内部类的名称冲突

症状:内部类与外部类或其他类的名称冲突

解决方案:使用完全限定名来区分

示例:

java
class OuterClass {
    private int x = 10;
    
    class InnerClass {
        private int x = 20;
        
        public void display() {
            int x = 30;
            System.out.println("局部变量 x: " + x); // 30
            System.out.println("内部类成员变量 x: " + this.x); // 20
            System.out.println("外部类成员变量 x: " + OuterClass.this.x); // 10
        }
    }
    
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.display();
    }
}

最佳实践

  1. 成员内部类:当内部类需要访问外部类的实例成员时使用

  2. 静态内部类:当内部类不需要访问外部类的实例成员时使用,提高性能

  3. 局部内部类:当内部类只在一个方法中使用时使用

  4. 匿名内部类:当只需要创建一个接口或抽象类的实例,且只使用一次时使用

  5. 命名规范:内部类的命名应该清晰,表明其用途

  6. 避免过度使用:内部类会增加代码的复杂性,应该只在必要时使用

总结

内部类是 Java 中一种重要的语法结构,主要包括四种类型:

  1. 成员内部类:定义在外部类的成员位置,没有 static 修饰,可以访问外部类的所有成员

  2. 静态内部类:定义在外部类的成员位置,使用 static 修饰,只能访问外部类的静态成员

  3. 局部内部类:定义在方法或代码块中,只能在定义它的方法或代码块中使用

  4. 匿名内部类:没有名称的内部类,通常用于创建接口或抽象类的实例

内部类的特点:

  • 可以访问外部类的成员,包括私有成员
  • 可以实现更好的封装
  • 可以更方便地实现某些设计模式
  • 可以使代码更加简洁

通过合理使用内部类,可以提高代码的可读性、可维护性和灵活性。

© 2026 编程马·菜鸟教程 版权所有