前言
简单来说,内部类就是在类的内部定义的类,根据内部类定义的位置,我们可以将其分为成员内部类和局部内部类:
一、成员内部类
🍑1、实例内部类
实例内部类即未被static修饰的成员内部类。使用时需要注意如下一些语法上的规定:
- 外部类中的任何成员都可以在实例内部类方法中直接访问。
- 实例内部类所处的位置与外部类成员位置相同,因此也受
public
、private等
访问限定符的约束。 - 实例内部类中不可以定义static修饰的成员,但允许定义
final
修饰的static成员。 - 在实例内部类方法中访问同名的成员时,优先访问自己的(
就近原则
),如果要访问外部类同名的成员,必须:外部类名称.this.同名成员
来访问。 - 实例内部类对象
必须在先有外部类对象
前提下才能创建。 - 实例内部类的非静态方法中包含了一个指向
外部类对象的引用
。 - 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。
📝实例展示:
class OuterClass { private int data1=1; int data2=2; public static int data3=3; public void func1() { System.out.println("外部类func1"); } //内部类可以被public、private等限定符修饰 public class InnerClass { int data2=888; //内部类可以定义被final修饰的静态成员变量 static final int SIZE = 999; public void func2() { System.out.println("内部类func2"); //默认就近访问同名成员 System.out.println(data2); //使用类名访问外部类同名成员 System.out.println(OuterClass.this.data2); //可直接访问外部类的成员 data1=111; data3=333; func1(); } } } public class Test { public static void main(String[] args) { //两种创建内部类对象的方式: //方式1: //OuterClass.InnerClass innerClass = new OuterClass().new InnerClass(); //方式2: OuterClass outerClass = new OuterClass(); OuterClass.InnerClass innerClass = outerClass.new InnerClass(); innerClass.func2(); } }
运行结果:
🍑2、静态内部类
被static
修饰的内部成员类称为静态内部类。使用静态内部类时同样要遵循一些语法规则:
- 在静态内部类中只能访问外部类中的静态成员,因为非静态成员需要使用引用来访问,如果非要访问则需要创建外部对象的引用。
- 同样外部类中不能直接访问静态内部类中的成员,如果要访问必须先要创建内部类的对象。
- 静态内部类所处的位置与外部类成员位置相同,也受
public
、private等
访问限定符的约束。 - 在静态内部类方法中访问同名的静态成员时,优先访问自己的(
就近原则
),如果要访问外部类同名的成员,必须:外部类名称.同名成员
来访问。 - 创建静态内部类对象时,不需要先创建外部类对象。
📝实例展示:
class OuterClass { public int data1=1; int data2=2; public static int data3=3; public void func1() { System.out.println("外部类func1"); } static class InnerClass { public int data4=4; public static int data5=5; public void func2() { System.out.println("内部类func2"); //只能直接访问外部类的静态成员。非静态成员需要对象的引用才能访问。 System.out.println(data3); System.out.println(data4); System.out.println(data5); } } } public class Test { public static void main(String[] args) { //静态内部类不依赖于外部类的对象,可直接如下创建: OuterClass.InnerClass innerClass = new OuterClass.InnerClass(); innerClass.func2(); } }
运行结果:
二、局部内部类
定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用。根据是否具名将其分为方法内部类和匿名内部类,同时局部内部类还遵循如下语法规则:
- 局部内部类只能在所定义的方法体或
{}
内部使用。 - 不能被
public
、static
等修饰符修饰。
下面分别讲解:👇
🍑1、方法内部类
在方法中定义方法内部类相对来说是非常鸡肋的,这种方式开发中很少用到,大家目前了解语法即可。
📝实例展示:
class OuterClass { public void func() { class InnerClass { private int a = 10; public void test() { System.out.println("方法内部类中的方法!"); } } //只能在方法体中使用方法内部类 InnerClass innerClass = new InnerClass(); innerClass.test(); } } public class Test { public static void main(String[] args) { OuterClass outerClass = new OuterClass(); outerClass.func(); } }
🍑2、匿名内部类
匿名内部类是与new
关联的,在创建对象的时候定义类,new后面是父类或者父接口,然后是圆括号()
,里面可以是传递给父类构造方法的参数,最后是大括号{};
,里面是类的定义。
如果对象只会创建一次
,且不需要构造方法来接受参数,则可以使用匿名内部类,代码书写上更为简洁。匿名内部类在之后会频繁的使用,这里我们先来了解一下匿名内部类的语法:
new 父类(参数列表) { //匿名内部类实现部分 };
或者
new 父接口() { //匿名内部类实现部分 };
下面我们就以接口
为例,简单展示一下匿名内部类,我们先看两段代码:
📝代码1:
interface IA { void test(); } class AA implements IA { @Override public void test() { System.out.println("类AA重写IA接口test方法"); } }
📝代码2:
interface IA { void test(); } public class Test { public static void main(String[] args) { new IA() { @Override public void test() { System.out.println("匿名内部类重写IA接口方法"); } }.test();//这里调用了test()方法 } }
分析: 上面的两段代码是对IA
接口的两种实现。代码1定义了一个类AA实现了IA接口并重写了IA接口的方法。代码2是采用了匿名内部类的实现方式,定义了一个没有名字的类实现了IA接口并重写了IA接口的方法,在只创建一次对象的情况下,这种代码2匿名的实现方式可以实现代码1相同的效果。
三、拓展:内部类与字节码文件
内部类和外部类共用同一个java
源文件,但是经过编译之后,内部类会形成单独的字节码文件。