主要内容
包括实例内部类、匿名内部类、静态内部类和局部内部类的特点和使用方法
1. 实例内部类
成员内部类的一种,没有static
修饰,实例内部类具有以下特点
- 在创建实例内部类的实例时,外部类的实例必须已经存在,想创建内部类Inner类的实例,必须先创建外部类Outer类的实例
- 实例内部类的实例自动持有外部类的实例的引用,其引用形式是:
外部类名字.this
,在内部类中,可以直接访问外部类的所有成员,包括成员变量和成员方法 - 外部类实例与内部类实例之间是一对多的关系,一个内部类实例只会引用一个外部类实例,而一个外部类实例可对应零个或多个内部类实例,在外部类中不能直接访问内部类的成员,必须通过内部类的实例去访问。
- 在实例内部类中不能定义静态成员,只能定义实例成员,否则编译将无法通过
- 若实例内部类与外部类包含同名的成员,例如内部类变量
Inner.x
和外部类Outer.x
,在内部类中使用this.x
表示内部类变量x
,使用Outer.this.x
表示外部类的变量x - 实例内部类的class文件名为:
外部类名$内部类名.class
package inter;
/**
* @author wonzeng
* 2020年7月10日
*/
//外部类
public class Outer {
int x;
// 内部类
class Inner{
// 内部类中不能出现静态变量或静态方法
// static int cnt;
int x;
public Inner() {
this.x = 100;
System.out.println("Outer.Inner.Inner():"+this.x);
// Outer.Inner.Inner():100
// 访问外部同名的变量x
System.out.println("Outer.Inner.Inner():"+Outer.this.x);
// Outer.Inner.Inner():10
}
// 内部类方法
public void innerPrint() {
System.out.println("Outer.Inner.print():"+this.x);
// Outer.Inner.print():100
}
}
public Outer() {
this.x = 10;
System.out.println("Outer.Outer():"+this.x);
// Outer.Outer():10
}
public static void main(String[] args) {
Outer p = new Outer();
Inner inner = p.new Inner();
// 或使用以下:
// Inner inner = new Outer().new Inner();
inner.innerPrint();
}
}
运行结果
Outer.Outer():10
Outer.Inner.Inner():100
Outer.Inner.Inner():10
Outer.Inner.print():100
2. 匿名内部类(匿名类)
匿名内部类是一种特殊的类,没有名字,具有以下特点
-
匿名内部类必须继承一个父类,或实现一个接口,但最多只能实现一个接口。
-
匿名内部类由于没有名字,因而无法定义构造方法,编译程序会自动生成它的构造方法,并在其中自动调用其父类的构造方法
-
匿名内部类中可以定义实例变量、若干个实例初始化代码块和新的实例方法,Java虚拟机首先调用其父类的构造方法,然后按照实例变量和实例初始化代码块定义的先后次序依次进行初始化
-
匿名内部类访问局部变量只能读取不能修改
-
匿名内部类可以访问外部类的所有成员
-
匿名内部类的class文件名为:
外部类名$编号.class
继承父类实现匿名内部类
package inter;
/**
* @author wonzeng
* 2020年7月10日
*/
public class AnonymityTest {
private int x;
public AnonymityTest(int x) {
this.x = x;
System.out.println("父类构造方法");
// TODO Auto-generated constructor stub
}
public void display() {
System.out.println("AnonymityTest.display():"+this.x);
}
public static void main(String[] args) {
int cnt = -1;
// 创建匿名内部类,继承父类
AnonymityTest p = new AnonymityTest(10) {
// 构造代码块
{
System.out.println("调用父类构造方法后x的值:"+super.x);
// 修改父类属性
super.x = 9999;
// 不能修改外部变量
// cnt = 9;
System.out.println("局部内部类访问外部变量:"+cnt);
}
// 重写父类方法
public void display() {
System.out.println("AnonymityTest.main(...).new AnonymityTest() {...}.display():"+super.x);
}
};
// 调用的是匿名类的方法display
p.display();
}
}
运行结果
父类构造方法
调用父类构造方法后x的值:10
局部内部类访问外部变量:-1
AnonymityTest.main(...).new AnonymityTest() {...}.display():9999
lambda
表达式或匿名对象实现接口
package inter;
//接口
interface Inner{
public void abstractMethod(String msg);
}
public class AchieveInterface {
public AchieveInterface() {
// TODO Auto-generated constructor stub
}
public static void test1() {
}
public static void test2() {
}
public static void test3() {
}
public static void main(String[] args) {
// 实现接口方式1:
// 匿名内部类实现接口
Inner p1 = new Inner() {
@Override
public void abstractMethod(String msg) {
// TODO Auto-generated method stub
System.out.println("匿名内部类实现接口:"+msg);
}
};
// 调用方法
p1.abstractMethod("参数1");
// 实现接口方式2:
// 匿名内部类
new Inner() {
@Override
public void abstractMethod(String msg) {
// TODO Auto-generated method stub
System.out.println("匿名内部类实现接口:"+msg);
}
}.abstractMethod("参数2");
// 实现接口方式3:
Inner p3 = (msg)->{
System.out.println("lambda实现接口:"+msg);
};
p3.abstractMethod("参数3");
}
}
运行结果
匿名内部类实现接口:参数1
匿名内部类实现接口:参数2
lambda实现接口:参数3
3. 静态内部类
定义内部类时用static
修饰,就变成了一个静态内部类,具有以下特点
- 静态内部类在类加载后就可以创建对象,无需创建外部类对象
- 具有类成员拥有的
public、protected、private
和默认这4种权限 - 静态内部类定义的位置处于类内部,在其他方面与顶层类一样,既可以定义final或abstract,也可以继承类或实现接口,还可以被其他类继承
- 静态内部可直接访问类外部类中的static型成员,非static型间接访问,即先创建外部类的对象,然后通过该对象来访问
- 静态内部类生成的class文件:
外部类$静态内部类.class
package inter;
/**
* @author wonzeng
* 2020年7月10日
*/
//外部类:TestEmp
public class StaticClass {
static int N = 10;
private String msg = "外部类成员";
public StaticClass() {}
public static void display() {
System.out.println("外部类静态方法");
}
// 静态内部类:StaticInnerClass
public static class StaticInnerClass{
// 与外部类同名的静态变量
static int N = 20;
// 内部类的构造方法
public StaticInnerClass() {
// 创建外部类
StaticClass p = new StaticClass();
// 用外部类对象访问外部类中的成员
System.out.println("访问外部类中成员:"+p.msg);
System.out.println("访问外部类中的静态成员:"+StaticClass.N);
System.out.println("访问内部类静态成员:"+StaticInnerClass.N);
System.out.println("不指定范围,默认访问内部的静态成员:"+N);
// 直接使用外部类的静态方法
display();
}
// 实例方法
public void test() {
System.out.println("内部类中的实例方法");
}
// 静态方法
public static void printMessage() {
System.out.println("内部类中的静态方法");
}
}
public static void main(String[] args) {
// 使用内部类StaticInnerClass的静态方法
StaticInnerClass.printMessage();
// 创建内部类对象
StaticInnerClass p = new StaticInnerClass();
// 使用内部类对象的实例方法
p.test();
}
}
运行结果
内部类中的静态方法
访问外部类中成员:外部类成员
访问外部类中的静态成员:10
访问内部类静态成员:20
不指定范围,默认访问内部的静态成员:20
外部类静态方法
内部类中的实例方法
4. 局部内部类
也称为方法中的内部类,定义在方法中,只有在运行到类定义之后才能使用
- 由于外部完全不能访问局部内部类,因而它们不需要(不能定义)访问权限控制符,也不能定义为static
- 定义局部内部类的好处是可以访问外部类中的成员,还可以访问所在代码块(方法)中的局部变量,如方法的形式参数、方法体中的局部变量,但是不能修改这些局部变量
- 在方法中定义的局部变量在方法运行结束之后生命周期结束,不能再被访问,
- 局部内部类如果用来来实现外部接口,可以将创建的内部类对象返回作为接口的实现对象
- 一个类如果只在某个方法中使用,那么就可以在方法中定义
- 方法中的内部类class文件名为:
外部类名$.编号内部类名.class
package inter;
//接口
interface InterfaceImp{
public abstract void methodTest1();
public abstract void methodTest2();
}
public class AchieveImp{
public static void main(String[] args) {
AchieveImp p = new AchieveImp();
// 在成员方法中通过局部内部类实现接口中的方法,并返回接口对象
InterfaceImp inter = p.achieveInterface();
System.out.println("访问接口中的方法");
inter.methodTest1();
}
private int x = 10;
// 局部内部类的作用域仅限于当前方法中使用,实际很少使用
public InterfaceImp achieveInterface(){
int cnt = -1;
// 局部内部类实现接口
class Imp implements InterfaceImp{
// 局部内部类成员
public int x = 1000;
@Override
public void methodTest1(){
// 不能修改外部变量,只能读取
// cnt = 10;
System.out.println("局部内部类访问局部变量:"+cnt);
// 修改外部类成员
x += 20;
System.out.println("局部内部类直接访问外部类成员:"+x);
}
@Override
public void methodTest2(){
System.out.println("局部内部类实现接口中的方法"+x);
}
// 添加成员方法
public int getX() {
return x;
}
// 局部内部类不能定义静态方法
// public static void display() {}
};
// 实例化一个局部的内部类
Imp p = new Imp();
p.methodTest1();
p.methodTest2();
System.out.println("方法中访问局部内部类中的方法:"+p.getX());
return p;
}
}
运行结果
局部内部类访问局部变量:-1
局部内部类直接访问外部类成员:1020
局部内部类实现接口中的方法1020
方法中访问局部内部类中的方法:1020
访问接口中的方法
局部内部类访问局部变量:-1
局部内部类直接访问外部类成员:1040