什么是内部类?

类的五大成员

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

内部类即在一个类的里面,再定义一个类。

  • 内部类表示的事物是外部类的一部分
  • 内部类单独出现没有任何意义

内部类访问特点

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

内部类分类

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

成员内部类

卸载成员位置的,属于外部类的成员

成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static等

在成员内部类里面,JDK16之前不能定义静态变量,JDK16以后才可以

public class Car{    //外部类
    String carName;
    int carAge;
    int carColor;
    class Engine{    //成员内部类
        String engineName;
        int engineAge;
    }
}
获取成员内部类对象
  1. 在外部类中编写方法,对外提供内部类的对象。
  2. 直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
public class Outer{
    String name;
    class Inner{
        //JDK16之后才可以这样书写
        static int num = 10;
    }
    public Inner getInstance(){
        return new Inner();
    }
}
public class Test{
    public static void main(String[] args){
        //直接创建内部类对象
        //若成员内部类被private修饰,则无法直接创建内部类对象,只能通过在外部类中编写方法,对外提供内部类的对象。
        Outer.Inner oi = new Outer.new Inner();
        
        //另一种方法
        //若Inner私有,则不能使用 Outer.Inner inner = o.getInstance();
        //可以使用Inner的父类创建,形成多态,但这里Inner没有父类,默认继承Object
        Object inner = o.getInstance();
        
        //对象地址值
        System.out.println(o.getinstance());
    }
}
成员内部类如何获取外部类的成员变量
class Outer{
    private int a = 10;
    class Inner{
        private int a = 20;
        public void show(){
            int a = 30;
            //Outer.this 获取了外部类对象的地址值
            System.out.println(Outer.this.a); //10
            System.out.println(this.a); //20
            System.out.println(a); //30
        }
    }
}

Outer.this.a 的原理:

image-20220922203031111
image-20220922203031111

静态内部类

是成员内部类的一种特殊情况

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。

public class Car{    //外部类
    String carName;
    int carAge;
    int carColor;
    static class Engine{    //静态内部类
        String engineName;
        int engineAge;
    }
}
获取静态内部类对象

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

public class Test{
    public static void mian(String[] args){
        //创建静态内部类的对象
        //只要是静态的东西,都可以直接用类名点直接获取
        //非静态方法
        Outer.Inner oi = new Outer.Inner();
        oi.show1();
        
        //静态方法
         Outer.Inner.show2();
    }
}
public class outer{
    int a = 10;
    static int b = 20;
    static class Inner{
        public void show1(){
            
            System.out.println(a); //报错
            
            Outer o = new Outer();
            System.out.println(o.a); //正常
            System.out.println(b); //正常
            System.out.println("非静态的方法被调用");
        }
        public static void show2(){
            System.out.peintln("静态方法被调用");
        }
    }
}

局部内部类

  • 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
  • 外界是无法直接使用,需要在方法内部创建对象并使用。
  • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
public class Test{
    public static void main(String[] args){
        /*
        //无法直接使用show方法里面的局部变量a
        Outer o = new Outer();
        o.a;    //这里a指成员变量,无法访问到show方法中的a
        */
        Outer o = new Outer();
        o.show();
        //输出
        /*
        null
        0
        10
        20
        局部内部类中的f1方法
        局部内部类中的f2方法
        */
    }
}
public class Outer{
    int b = 20;
    public void show(){
        int a = 10;
        
        //局部内部类
        //和局部变量类似
        class Inner{
            String name;
            int age;
            public void f1(){
                System.out.println(a); //正常
                System.out.println(b); //正常
                System.out.println("局部内部类中的f1方法");
            }
             public static void f2(){
                System.out.println("局部内部类中的f2方法");
            }
        }
        //创建局部内部类对象
        Inner i = new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
        i.f1();
        Inner.f2();
    }
}

匿名内部类

匿名内部类本质就是隐藏了名字的内部类

格式:

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

代码演示

public class Test{
    public static void main(String[] args){
        //new 类名();
        new Swim(){
            @Override
            public void swim(){
                System.out.println("游泳");
            }
        };
    }
}
public interface Swim{
    public abstract void swim();
}
//上文中代码段
        {
            @Override
            public void swim(){
                System.out.println("游泳");
            };
//表示没有名字的类
//实现了Swim类,所以要重写Swim中的抽象方法
            
//若Swim为抽象类
//则是没有名字的类继承了Swim类,也要重写Swim中的抽象方法

所以可以得出匿名内部类包含了:

  1. 继承/实现关系;
  2. 方法的重写;
  3. 创建对象。
匿名内部类作用
public class Test{
    public static void method(Animal a){
        a.eat();
    }
    
    //若要调用method方法
    //需要先创建一个具体的动物类Dog
    Dog d = new Dog;
    method(d);
    //如果Dog只需要用一次,这种方法过于麻烦
    //匿名内部类方法
    method(new Animal(){
        @Override
        public void eat(){
            System.out.println("狗吃骨头");
        }
    });
}
public abstract class Animal{
    public abstract eat();
}
public class Dog extends Animal{
    @Override
    public void eat(){
        System.out.println("狗吃骨头");
    }
}