Java内部类介绍

103 阅读3分钟

一个类A内部定义了一个类B,那么B就是A的内部类。A可以成为外部类。

成员内部类

成员内部类创建对象:

外部类名.内部类名 变量 = 外部类对象.new 内部类构造方法(参数)

代码实例:

public class Test {
    public static void main(String[] args) {
        // 创建成员内部类的对象 : 外部类名.内部类名 对象名= new  外部类构造方法(...).new 内部类的构造方法(...);
        Person.Heart heart = new Person().new Heart();
        heart.beats();
    }
}
// 外部类
class Person {
    class Heart {
        private int rate;
        public void beats() {
            System.out.println("咚咚咚!");
        }
    }
}

内部类访问外部类成员

成员内部类的方法中默认存在一个外部类对象:外部类名.this。

可以用此格式来调用外部类成员,访问时如果(内部类变量和外部类变量)没有冲突,格式可省略。

对于外部类来讲,没有默认的内部类对象,如果要访问内部类成员,需要创建内部类对象。

代码实例:

package com.itheima.innerclass_demo.member_innerclass;

public class Test {
    public static void main(String[] args) {
        // 创建成员内部类的对象 : 外部类名.内部类名 对象名= new  外部类构造方法(...).new 内部类的构造方法(...);
        Person.Heart heart = new Person().new Heart();
        heart.beats();

        // 静态成员内部类创建对象的方式
        // Person.Heart heart = new Person.Heart();
    }
}
// 外部类
class Person {
    int num = 30;

    // 想拿到 num = 20
    public void show() {
        // 外部类访问内部类成员
        Heart heart = new Heart();
        System.out.println(heart.num);// 20
    }

    // 心脏类
    class Heart {
        private int rate;
        int num = 20;

        public void beats() {
            int num = 10;
            System.out.println("咚咚咚!");
            System.out.println(num);// 10
            System.out.println(this.num);// 20
            System.out.println(Person.this.num);// 30
            // 若变量只存在于外部类,内部类没有定义,那么完全可以省略外部类.this
        }
    }
}

匿名内部类

匿名内部类是一个非常特殊的内部类,顾名思义,匿名内部类没有类名,因此这个内部类只能使用一次。

使用场景

匿名内部类一般用于简化代码,若要快速实现一个抽象类或者接口的抽象方法时,我们就可以使用匿名内部类来简化,可以不用专门定义一个有名类来操作。

使用条件

必须要有一个父类(一般就是抽象类或者接口)

案例代码

先看一段不使用匿名内部类实现的代码:

public class Test2 {
    public static void main(String[] args) {
        useSwimming(new SwimmingImpl());
    }
    public static void useSwimming(Swimming swimming) {
        swimming.swim();
    }
}
// 接口
interface Swimming {
    public abstract void swim();
}
class SwimmingImpl implements  Swimming {
    @Override
    public void swim() {
        System.out.println("我们去🏊‍吧");
    }
}
// 输出:我们去🏊‍吧

上面这个程序在主类中定义了一个useSwimming方法,该方法接收一个接口对象,因此在主方法调用该方法时需要传入一个接口的实现类,我们就需要额外定义一个实现类SwimmingImpl。接下来我们将上述代码用匿名内部类实现:会发现使用匿名内部类就无需额外创建一个实现类,而是直接对接口进行重写,然后作为参数传递给主调函数即可。

package com.itheima.innerclass_demo.anonymous_innerclass;

public class Test1 {
    public static void main(String[] args) {
	// 匿名内部类作为参数传递
        useSwimming(new Swimming() {
            @Override
            public void swim() {
                System.out.println("游泳");
            }
        });
    }
    // 方法的参数是一个接口 , 那么调用此方法需要传入此接口的实现类对象
    /*
        Swimming swimming = new SwimmingImpl()
     */
    public static void useSwimming(Swimming swimming) {
        swimming.swim();
    }
}

// 接口
interface Swimming {
    public abstract void swim();
}

匿名内部类格式 :

new 抽象类名/接口名(){

重写抽象方法

};

注意 : 匿名内部类创建的是一个 子类/实现类 对象

匿名对象的使用方式

  1. 使用父类型变量多态接收该匿名子类对象。

  2. 以匿名对象的方式使用

    1. 直接调用方法使用

    2. 当做方法的参数传递

    3. 当做方法的返回值使用

package com.itheima.innerclass_demo.anonymous_innerclass;

public class Test2 {
    public static void main(String[] args) {
        // 1) 直接调用方法使用
        new Flyable() {
            @Override
            public void fly() {
                System.out.println("飞~");
            }
        }.fly();

        //  2) 当做方法的参数传递  !!!
        useFly(new Flyable() {
            @Override
            public void fly() {
                System.out.println("飞~");
            }
        });

    }
    public static void useFly(Flyable flyable) {
        flyable.fly();
    }

	// 作为方法的返回值
    public static Flyable getFlyable(){
        return new Flyable() {
            @Override
            public void fly() {
                System.out.println("飞~");
            }
        };
    }

}

// 接口
interface Flyable {
    public abstract void fly();
}