Java中的内部类、匿名类、匿名内部类

内部类

Java中在一个类的内部定义的类叫做内部类(inner class)。建立一个内部类时,其对象就拥有了与外部类对象之间的关系。这种通过this来引用形成的,是内部类对象可以随意访问外部类中的所有成员变量!(因为被private修饰的成员变量和成员方法仅能被该类所使用,内部类中可以使用外部类的所有成员变量、成员方法)
Java程序中只能有一个public修饰的类且该类名是Java文件名的类,同时该Java程序中可以有多个类,但不能写public(只能写class)。
内部类的定义格式:

public class <文件名> {
	class <内部类名称> {
		<内部类的成员变量和成员方法>;
	}
}

创建内部类对象时,必须通过外部类的实例来实现。(以Outer和Inner为例)

public class Outer {
	class Inner {
		<内部类成员变量和成员方法>;
	}
}

先创建外部类Outer类的实例,才能创建内部类Inner类的实例

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

等价于

Outer.Inner inner = new Outer().new Inner();

使用<引用形式是外部类对象名>.this来引用内部类对象的外部类的对象的所有成员变量和成员方法。(这里仅仅只能在内部类中引用外部类通过这种方式引用外部类的成员和方法)
外部类对象和内部类对象之间是一对多关系,一个内部类对象只会引用一个外部类实例,而一个外部类对象可以对应多个内部类对象。在外部类中不能直接访问内部类成员,必须通过内部类的实例访问。
内部类中不能有被static修饰的任何成员变量和成员方法(被static修饰的成员变量和成员方法随着类的加载而加载,此时内部类还不能在堆空间产生实例)。
实力内部类与外部类变量名相同时,通过<类名>.<成员变量名>的方式来区分。Outer.a和Inner.a表示外部类、内部类的成员变量。

public class Outer {
    int num = 0;

    public void method() {
        System.out.println("num = " + num);
        System.out.println("this.num = " + this.num);
        System.out.println("Outer.this.num = " + Outer.this.num);
    }

    class Inner {
        int num = 1;

        public void method() {
            System.out.println("num = " + num);
            System.out.println("this.num = " + this.num);
            System.out.println("Outer.this.num = " + Outer.this.num);
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
        System.out.println("------");
        Outer.Inner inner = outer.new Inner();
        inner.method();
    }
}

num = 0
this.num = 0
Outer.this.num = 0
------
num = 1
this.num = 1
Outer.this.num = 0

匿名类

在堆内存中定义,但未在栈内存开辟空间的对象。

new <类的构造方法>() {
};

可以直接在()后面.来调用相关成员变量或成员方法,不能被引用,一般只用一次,较多用于传参或者返回值。当该类是抽象类时,必须实现该类所有的抽象方法。

new <抽象类的构造方法>() {
	@Override
	public <方法返回值> <抽象方法名> {
		<实现抽象方法>;
	}
};

匿名内部类

匿名内部类必须继承一个父类或者实现一个接口,但是最多只能实现一个接口
匿名内部类由于没有名字,因而无法定义构造方法,,编译程序会自动生成该类的构造方法,并在其中自动调用其父类的构造方法。
在匿名内部类中可以定义实例变量、若干实例初始化代码块和新的实例方法。Java虚拟机首先会调用其父类的构造方法,然后按照实例变量和实例初始化代码块定义的先后顺序依次进行初始化。
被匿名内部类访问的局部变量必须是final变量,Java8以后自动使用final修饰匿名内部类的局部变量。
匿名内部类可以直接访问外部类所有成员变量和成员方法,包括外部类中用private的成员变量和成员方法。()

public class AnonymousInner {
    public AnonymousInner(int i) {
        System.out.println("another constructor");
    }

    public AnonymousInner() {
        System.out.println("default constructor");
    }

    public void method() {
        System.out.println("from AnonymousInner");
    }
    public static void main(String[] args) {
        new AnonymousInner().method();
        int i = 1;
        AnonymousInner anonymousInner = new AnonymousInner(i) {// 定义了一个继承于AnonymousInner类的匿名内部类,大括号内是这个匿名内部类的类体,定义时直接生成了该类的对象并返回的一个实例引用。
            {
                System.out.println("initialize constructor");
            }
            public void method() {
                System.out.println("from anonymous" + i);
            }
        };
        anonymousInner.method();
    }
}

匿名内部类的{}中定义了实例变量、初始化代码块和实例的方法(仅该实例对象可用,其他类根据自己的定义而使用)本例中增加了对其内部类类体的引用。便于未来使用该匿名内部类。
输出结果如下

default constructor
from AnonymousInner
another constructor
initialize constructor
from anonymous1

猜你喜欢

转载自blog.csdn.net/qq_38637725/article/details/84060725