小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-09 / 0 阅读
0
0

Java 内部类学习笔记

Java 内部类学习笔记

概述

内部类是指定义在另一个类内部的类,Java提供了三种主要的内部类形式,每种都有不同的特性和使用场景。

1. Inner Class(成员内部类)

特点

  • 定义在外部类的内部,与成员变量和方法同级
  • 可以访问外部类的所有成员(包括private)
  • 不能包含静态成员(static final常量除外)
  • 必须先创建外部类实例才能创建内部类实例

语法

class OuterClass {
    private String outerField = "外部字段";
  
    class InnerClass {
        void display() {
            System.out.println("访问外部字段: " + outerField);
        }
    }
}

示例

// 外部类
class University {
    private String universityName = "清华大学";
  
    // 内部类
    class Department {
        private String deptName;
    
        public Department(String name) {
            this.deptName = name;
        }
    
        void showInfo() {
            // 直接访问外部类的私有字段
            System.out.println("大学: " + universityName);
            System.out.println("院系: " + deptName);
        }
    
        // 可以访问外部类的this引用
        void showOuterThis() {
            System.out.println("内部类this: " + this);
            System.out.println("外部类this: " + University.this);
        }
    }
}

// 使用示例
public class InnerClassExample {
    public static void main(String[] args) {
        University tsinghua = new University();
    
        // 创建内部类实例
        University.Department csDept = tsinghua.new Department("计算机科学");
        University.Department mathDept = tsinghua.new Department("数学系");
    
        csDept.showInfo();
        mathDept.showInfo();
    }
}

2. Static Nested Class(静态嵌套类)

特点

  • 使用static关键字修饰的内部类
  • 不能直接访问外部类的非静态成员
  • 可以包含静态成员
  • 不需要外部类实例即可创建
  • 行为上更像一个独立的类

语法

class OuterClass {
    private static String staticField = "静态字段";
    private String instanceField = "实例字段";
  
    static class StaticNestedClass {
        void display() {
            System.out.println("只能访问静态字段: " + staticField);
            // System.out.println(instanceField); // 编译错误!
        }
    }
}

示例

// 外部类
class Calculator {
    private static String brand = "科学计算器";
    private double batteryLevel = 100.0;
  
    // 静态嵌套类
    static class Operation {
        private String operationName;
        private static int operationCount = 0;
    
        public Operation(String name) {
            this.operationName = name;
            operationCount++;
        }
    
        public double calculate(double a, double b) {
            System.out.println("使用" + brand + "进行计算"); // 只能访问静态字段
            System.out.println("操作类型: " + operationName);
        
            switch(operationName) {
                case "加法": return a + b;
                case "减法": return a - b;
                case "乘法": return a * b;
                case "除法": return a / b;
                default: return 0;
            }
        }
    
        public static int getOperationCount() {
            return operationCount;
        }
    }
}

// 使用示例
public class StaticNestedClassExample {
    public static void main(String[] args) {
        // 不需要外部类实例,直接创建静态嵌套类
        Calculator.Operation add = new Calculator.Operation("加法");
        Calculator.Operation multiply = new Calculator.Operation("乘法");
    
        System.out.println("5 + 3 = " + add.calculate(5, 3));
        System.out.println("5 × 3 = " + multiply.calculate(5, 3));
        System.out.println("操作总数: " + Calculator.Operation.getOperationCount());
    }
}

3. Anonymous Class(匿名内部类)

特点

  • 没有类名的内部类
  • 通常用于实现接口或继承类的一次性使用
  • 简洁但功能有限
  • 常用于事件监听器、线程等场景

语法

// 创建一个继承自某个类的匿名类
父类 对象名 = new 父类() {
   // 重写父类中的方法
};
// 创建一个实现某个接口的匿名类
接口 对象名 = new 接口() {
   // 实现接口中的方法
};
interface MyInterface {
    void method();
}

class OuterClass {
    void createAnonymous() {
        MyInterface obj = new MyInterface() {
            @Override
            public void method() {
                System.out.println("匿名类实现");
            }
        };
    }
}

示例

// 接口定义
interface ButtonClickListener {
    void onClick();
    void onDoubleClick();
}

interface Runnable {
    void run();
}

// 外部类
class GUIApplication {
    private String appName;
  
    public GUIApplication(String name) {
        this.appName = name;
    }
  
    public void createButton() {
        // 匿名内部类实现接口
        ButtonClickListener listener = new ButtonClickListener() {
            private int clickCount = 0;
        
            @Override
            public void onClick() {
                clickCount++;
                System.out.println(appName + " - 按钮被点击! 次数: " + clickCount);
            }
        
            @Override
            public void onDoubleClick() {
                System.out.println(appName + " - 按钮被双击!");
            }
        };
    
        // 模拟按钮点击
        listener.onClick();
        listener.onDoubleClick();
    }
  
    public void startThread() {
        // 匿名内部类继承Thread类
        Thread workerThread = new Thread() {
            @Override
            public void run() {
                for(int i = 1; i <= 3; i++) {
                    System.out.println(appName + " - 线程执行中: " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
    
        workerThread.start();
    }
  
    public void createRunnable() {
        // 使用Runnable接口的匿名内部类
        Runnable task = new Runnable() {
            @Override
    public void run() {
                System.out.println(appName + " - Runnable任务执行");
            }
        };
    
        task.run();
    }
}

// 使用示例
public class AnonymousClassExample {
    public static void main(String[] args) {
        GUIApplication app = new GUIApplication("我的应用");
    
        app.createButton();
        app.startThread();
        app.createRunnable();
    
        try {
            Thread.sleep(4000); // 等待线程执行完成
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

三种内部类的比较

特性 Inner Class Static Nested Class Anonymous Class
访问外部类成员 可以访问所有成员 只能访问静态成员 可以访问final或等效final的局部变量
静态成员 不能有(除常量) 可以有 不能有
创建方式 需要外部类实例 直接创建 在声明时创建
命名 有明确类名 有明确类名 无类名
使用场景 紧密关联的组件 工具类、辅助类 一次性实现、回调

实际应用场景

1. 迭代器模式(Inner Class)

class BookShelf {
    private String[] books;
    private int count;
  
    public BookShelf(int capacity) {
        books = new String[capacity];
        count = 0;
    }
  
    public void addBook(String book) {
        if(count < books.length) {
            books[count++] = book;
        }
    }
  
    // 内部类实现迭代器
    public class BookIterator {
        private int index = 0;
    
        public boolean hasNext() {
            return index < count;
        }
    
        public String next() {
            return books[index++];
        }
    }
  
    public BookIterator iterator() {
        return new BookIterator();
    }
}

2. Builder模式(Static Nested Class)

class Computer {
    private String cpu;
    private String memory;
    private String storage;
  
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.memory = builder.memory;
        this.storage = builder.storage;
    }
  
    // 静态嵌套类实现Builder模式
    public static class Builder {
        private String cpu;
        private String memory;
        private String storage;
    
        public Builder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
    
        public Builder setMemory(String memory) {
            this.memory = memory;
            return this;
        }
    
        public Builder setStorage(String storage) {
            this.storage = storage;
            return this;
        }
    
        public Computer build() {
            return new Computer(this);
        }
    }
}

注意事项

  1. 内存泄漏:内部类持有外部类引用,可能造成内存泄漏
  2. 序列化:内部类的序列化可能有问题
  3. 测试难度:内部类可能增加单元测试的复杂度
  4. 可读性:过度使用内部类可能降低代码可读性

总结

  • Inner Class:适用于需要紧密访问外部类状态的场景
  • Static Nested Class:适用于与外部类相关但不依赖其实例的场景
  • Anonymous Class:适用于简单的一次性实现场景

选择合适的内部类类型可以使代码更加清晰、模块化,并提高封装性。


评论