内部类(四大类型)

内部类分为四种

一.实例内部类

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

代码解释

  1. 外部类Outclass

    • 包含实例变量date1、静态变量date2和私有变量date3

    • 包含一个非静态内部类InnerClass,内部类可以访问外部类的所有变量(包括私有变量)。

  2. 内部类InnerClass

    • 包含实例变量date4、静态常量date5和私有变量date6

    • test方法中,内部类可以访问外部类的变量(通过this隐式引用外部类实例)。

  3. 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内部类,这意味着它不需要依赖外部类的实例即可创建。

  • 静态内部类不能访问外部类的实例变量(如date1date3),但可以访问外部类的静态变量(如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()

关键点

  1. 静态内部类的特点

    • 静态内部类不需要外部类的实例即可创建。

    • 静态内部类不能访问外部类的实例变量,但可以访问外部类的静态变量。

    • 静态内部类的实例与外部类的实例无关。

  2. 非静态内部类与静态内部类的区别

    • 非静态内部类

      • 需要依赖外部类的实例才能创建。

      • 可以访问外部类的所有变量(包括私有变量)。

    • 静态内部类

      • 不需要外部类的实例即可创建。

      • 只能访问外部类的静态变量。

示例补充

为了进一步展示静态内部类的特点,可以尝试在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)是一种特殊的内部类,它定义在方法的作用域内,通常用于实现特定方法的逻辑。局部内部类的特点和使用场景与其他内部类有所不同,以下是详细的介绍和示例。

局部内部类的特点

  1. 作用域限制

    • 局部内部类只能在定义它的方法的作用域内使用。

    • 它不能被其他方法访问,也不能被外部类的其他部分访问。

  2. 访问权限

    • 局部内部类可以访问外部类的所有成员(包括私有成员)。

    • 局部内部类可以访问其所在方法的局部变量,但这些局部变量必须是final的(或者在Java 8及以上版本中,局部变量可以是“实际上不可变”的)。

  3. 用途

    • 局部内部类通常用于实现特定方法的逻辑,例如回调接口的实现、匿名类的替代等。

    • 它可以隐藏实现细节,使代码更加模块化和清晰。

示例代码

以下是一个包含局部内部类的示例代码:

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

代码解释

  1. 外部类Outclass

    • 包含一个私有变量outValue

    • 包含一个方法test,在该方法中定义了一个局部内部类LocalInnerClass

  2. 局部内部类LocalInnerClass

    • 定义在test方法的作用域内。

    • 可以访问外部类的私有变量outValue

    • 可以访问方法的局部变量localVar,但localVar必须是final的(或实际上不可变的)。

  3. Main

    • 创建了一个Outclass的实例outclass

    • 调用了outclass.test()方法,该方法内部创建了局部内部类的实例并调用了其display方法。

关键点

  1. 局部变量的不可变性

    • 在Java 8及以上版本中,局部变量不需要显式声明为final,但它们必须是“实际上不可变的”,即在方法的作用域内不能被修改。

    • 如果局部变量的值在方法中被修改,则无法在局部内部类中使用该变量。

  2. 局部内部类的用途

    • 局部内部类通常用于实现特定方法的逻辑,例如实现回调接口或替代匿名类。

    • 它可以隐藏实现细节,使代码更加模块化和清晰。

示例:实现回调接口

假设有一个回调接口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中一种特殊的内部类,它没有类名,通常用于创建单次使用的对象。匿名内部类通常用于实现接口或继承类,并且可以直接在代码中实例化,而不需要单独定义一个类。

匿名内部类的特点

  1. 没有类名

    • 匿名内部类没有显式的类名,因此不能通过类名来创建多个实例。

    • 它只能被实例化一次。

  2. 实现接口或继承类

    • 匿名内部类可以实现一个接口或继承一个类(但不能同时实现接口和继承类)。

    • 如果继承了一个类,它必须是该类的一个子类。

    • 如果实现了一个接口,它必须实现接口中的所有抽象方法。

  3. 访问权限

    • 匿名内部类可以访问外部类的所有成员(包括私有成员)。

    • 匿名内部类可以访问其所在方法的局部变量,但这些局部变量必须是final的(或者在Java 8及以上版本中,局部变量可以是“实际上不可变”的)。

  4. 用途

    • 匿名内部类通常用于实现回调接口、事件监听器、线程启动等场景。

    • 它可以简化代码,避免定义单独的类。

匿名内部类的语法

匿名内部类的语法如下:

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()

匿名内部类的使用场景

  1. 事件监听器

    • 在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!");
                  }
              });
          }
      }
  2. 线程启动

    • 匿名内部类可以用于实现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();
          }
      }
  3. 回调接口

    • 匿名内部类常用于实现回调接口,例如在多线程编程或异步操作中:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值