Java 内部类

159 阅读4分钟

内部类

  • 类的五大成员

属性、方法、构造方法、代码块、内部类

什么是内部类?

在一个类的里面,再定义一个类

举例:在A类的内部定义B类,B类就被称为内部类

public class Outer {       /内部类
    public class Inner {   /外部类
        
    }
}

public class Test {        /外部其他类
    public static void main(String[] args) {
        
    }
}
  • 内部类表示的事物是外部类的一部分
  • 内部类单独出现没有任何意义
  • 比如:汽车的发动机,ArrayList的迭代器,人的心脏等

内部类的访问特点

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建内部类对象

内部类的分类

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

成员内部类

  • 写在成员位置的,属于外部类的成员
  • 成员内部类可以被一些修饰符所修饰,比如:private、默认、protected、public、static等
  • 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量
public class Car {     //外部类
    String carName;
    int carAge;
    int carColor;
    class engineName { //成员内部类
        String engineName;
        int enginAge;
    }
}

获取成员内部类对象

  • 方式一:在外部类中编写方法,对外提供内部类的对象
  • 方式二:直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
    • 范例:Outer.Inner oi = new Outer().new Inner();
  • 当内部类被private所修饰,无法在外部之间获取内部类对象,这时可以通过方式一获取
//在外部类中
public Inner gerInstance() {
    return new Inner();
}

//在类外,可以通过多态来获取对象
Outer o = new Outer();
//Outer.Inner inner = o.getInstance(); //错误的,外部无法访问到Inner
Object inner = o.getInstance();

//或者直接使用
sout(o.getInstance());
  • 在底层内部类的地址 @ 的左边显示的是 OuterInner这样的形式,所以在被变量取名时尽量不要使用Inner 这样的形式,所以在被变量取名时尽量不要使用 和 _

成员内部类如何获取外部类成员变量

public class Outer {
    private int a = 10;
    class Inner {
        private int a = 20;
        
        public void show() {
            int a = 30;
            sout(Outer.this.a);  //10
            sout(this.a);        //20
            sout(a);             //30
        }
    }
}
public class Test {
   public static void main(String[] args) {
       Outer.Inner oi = new Outer().new Inner();
       
       oi.show();
   }
}
  • 在内部类对象生成时,虚拟机会自动生成一个Outer.this变量,里面存储的是外部类Outer的地址值

静态内部类

静态内部类也是成员内部类中的一种

public class Car {     //外部类
    String carName;
    int carAge;
    int carColor;
    static class engineName { //静态内部类
        String engineName;
        int enginAge;
    }
}
  • 静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建外部类对象

  • 创建静态内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();

Outer.Inner oi = new Outer.inner();
  • 调用非静态方法的格式:先创建对象,用对象调用

  • 调用静态方法的格式:外部类名.内部类名.方法名();

局部内部类

  • 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
  • 外界无法直接使用局部内部类,需要在方法内部创建对象并使用
  • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量

匿名内部类

匿名内部类本质上就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置

真的没有名字吗?其实并不是,其实是不用我们自己写名字,虚拟机会自动分配名字,格式为 父类或接口名字$序号 ,例如Inter$1

格式

new 类名或者接口名() {
    重写方法;
};

举例

new Inter() {
    public void show() {
        
    }
};

格式的细节

  • 包含继承/实现关系

  • 包含方法的重写

    包含创建对象

  • 整体就是一个类的子类对象或者接口的实现类对象

使用场景

  • 当方法的参数是接口或者类时
  • 以接口为例,可以传递这个接口的实现类对象,如果这个类只要使用一次,就可以用匿名内部类来简化代码