1. Introduction

将类写在其他类的内部,可以写在其他类的成员位置或者局部位置,这时写在其他类内部的类就称为内部类。在描述事物时,若一个事物内部还包含其他可能包含的事物,比如在描述汽车时,汽车中还包含这发动机,这时发动机就可以使用内部类来描述。
内部类分为成员内部类(member inner class)与局部内部类(Local Inner Class)。

内部类的特点

  • javac编译内部类后,会创建一个Outter$Innerr.class 的文件
  • 在内部类中可以直接访问外部类的所有成员。,所以Inner Class必须在Outter Class**实例化**以后才能被加载和实例化。
  • 外部类不可以直接使用内部类的成员,必须通过创建内部类实例进行调用。
  • 当第一次使用外部类的静态变量,静态方法时,外部类会被加载但是内部类不会被加载。**

    2. Member Inner Class

    成员内部类,定义在外部类中的成员位置。与类中的成员变量相似,可通过外部类对象进行访问

    A. 定义格式:

    1. class 外部类 {
    2. 修饰符 class 内部类 {
    3. //其他代码
    4. }
    5. }

    B. 内部类的访问方式

  • 非静态成员内部类的访问方式: 外部类名.内部类名 变量名 = new 外部类名().new 内部类名();

  • 非静态成员内部类调用外部类属性:外部类名.this.属性名
  • 非静态内部类调用外部类的方法:外部类名.this.方法名

    1. class Car {//外部类
    2. String name;
    3. public void ready(){
    4. System.out.println(发动机已启动);
    5. }
    6. public class Engine { //内部类
    7. public void start() {
    8. //调用外部类的属性
    9. System.out.println(Car.this.name + "启动发动机");
    10. //调用外部类的方法
    11. Car.this.ready();
    12. }
    13. }
    14. public static void main(String[] args) {
    15. Car car = new Car();
    16. //创建内部类对象
    17. //Inner Class必须在Outter Class实例化以后才能被加载和实例化。
    18. Car.Engine egine = car.new Engine();
    19. //调用内部类中的方法
    20. egine.start();
    21. }
    22. }

    C. 静态内部类

    如果一个内部类不需要对它的外部类(outer class)进行引用,那个你可以把它声明为static。

  • 静态内部类的加载不需要依附外部类的实例对象。可以直接调用静态内部类创建内部类对象。

  • 静态内部类不能调用外部类的非静态成员和方法
  • 加载静态内部类前,外部类会先被加载。 ```java public class Outter { public static String name = “张三”; public String age = “23”;

    static class Inner{

    1. public void say(){
    2. System.out.println("外部静态成员变量,name = " + name);
    3. System.out.println("测试静态成员内部类实例化");
    4. }

    } }

public class MainTest { public static void main(String[] args) { //静态成员内部类实例化,这里只加载 Outter.Inner inner = new Outter.Inner(); inner.say(); } }

  1. <a name="RZKk8"></a>
  2. # 3. Local Inner Class
  3. 局部内部类,定义在外部类方法中的局部位置。与访问方法中的局部变量相似,可通过调用方法进行访问.
  4. <a name="uc62k"></a>
  5. ### A. 定义格式:

class 外部类 { 修饰符 返回值类型 方法名(参数) { class 局部内部类 { //其他代码 } } }

<a name="Kl1nU"></a>
### B. 访问方式: 在外部类方法中,创建内部类对象,进行访问
```java
//定义类
class Outter {//外部类
    public static void main(String[] args) {
        class Inner {// 内部类
            public void print(){
                System.out.println("局部内部类方法");
            }
        }
        //创建内部类对象,调用puff方法
        new Inner().print();
    }
}

C. 什么时候使用局部内部类?

比如当一个方法中需要使用一个坐标去存储x, y时,我们就可以在方法中定义这个局部内部类(相当于C中的struct)去方便使用。

4. Anonymous Inner Class

A. 引入

最常用到的内部类就是匿名内部类,它是局部内部类的一种。
当我们需要实现一个接口时,我们需要写如下代码:

public interface Smoking {
    public abstract void smoking();
}
class XXX implements Smoking{
    public void smoking(){
        //to do
    }
}
public class Test {
    public static void main(String[] args) {
        XXX x = new XXX();
        x.smoking();
        Smoking s = new XXX();
        s.smoking();
    }
}

匿名内部类简化如上代码: 将定义实现类,重写方法,建立实现类对象,合为一步完成:

public class Test {
    public static void main(String[] args) {
        new Smoking(){
            public void smoking(){
                System.out.println("人在吸烟");
            }
        }.smoking();
    }
}

匿名内部类的本质是一个实现了接口或继承了某个类的子类匿名对象。javac 编译后会生成一个Test$1.class的对象。

//启动一个线程:
new Tread() {
    @Override
    public void run(){
        //to do….
    }
}.start();

//定义一个实现接口的对象:
Animal a= new Animal(){
    public void eat(){
        System.out.println("在吃饭");
    } 
    public void sleep(){
        System.out.println("在睡觉");
    }
};
a.eat();
a.sleep();

B. Annonymous Inner Class as parameter

接口作为方法参数与返回值:

  • 接口作为方法参数的情况是很常见的,经常会碰到。当遇到方法参数为接口类型时,那么该方法要传入一个接口实现类对象。

    //给button添加一个监听器:
    JButton jbtNew = new JButton("New" );
    jbtNew.addActionListener{
      new ActionListener(){
          public void actionPerformed(ActionEvent e){
              System. out.println("Process new" );
          }
      }
      );
    
  • 接口作为方法返回值的情况,在后面的学习中会碰到。当遇到方法返回值是接口类型时,那么该方法需要返回一个接口实现类对象。比如返回值类型是 List