内部类,顾名思义就是一个 A 类的内部再定义一个 B 类。那么 A 类就是外部类, B 类就是内部类。
public class A {
public class B{
}
}
内部类除了定义的位置有特殊性外,本质上与普通类没有区别,包括:
- 也拥有属性、构造、行为、初始化块、自己的内部类
- 内部类虽然和外部类书写在同一篇 .java 文件,但编译后拥有自己独立的 .class 文件
- 内部类的类名不是书写的简单名,而是和外部类的类名共同组成的
根据内部类书写的位置,可以分为两大类:
- 成员内部类
-
成员内部类
如果一个内部类是直接定在外部类的
{}
里,它的位置与外部类的属性、方法、构造平行,称为“成员内部类”。它是最普通的内部类,作为外部类的成员,它也能拥有访问修饰符来控制这个内部类能否被外部使用。1. 普通成员内部类
// Outside.java
public class Outside{
// 内部类位置与外部类的属性、方法、构造器平行,所以就作为了外部类的成员内部类
class Inside{
}
// 外部类的构造
public Outside(){
}
// 外部类有自己的属性、方法
private String name;
public void print(){
}
}
若内部类
class Inside{}
添加了 private 修饰,则表示只能在其外部类class Outside{}
中使用;若添加的是 public 则表示外部类外其他类也都可以使用。
要使用普通成员内部类,要先产生外部类的对象,再用外部类对象.new 内部类()
产生内部类对象:外部类型 外部实例名称 = new 外部类();
外部类.内部类类型 实例名称 = 外部实例.new 内部类();
// Outside.java
public class Outside {
// 外部类属性
public String nameOutside = "外部类";
// 内部类
public class Inside {
public String nameInside = "内部类 inside";
// 内部类访问外部类属性值
public void print() {
System.out.println(nameInside + "," + nameOutside);
}
}
}
// TestMain.java
public class TestMain {
public static void main(String[] args) {
// 外部类的实例
Outside outsideObj = new Outside();
/*
内部类作为了外部类的成员,所以创建内部类实例的语法
*/
Outside.Inside insideObj = outsideObj.new Inside();
insideObj.print();
}
}
2. 静态内部类
由于添加了 static 修饰,所以该静态内部类与它所属的外部类实例对象无关,就无须产生外部对象了。直接使用外部类类名访问。
Outsize.Inside inner2 = new Outsize.Inside();
局部内部类
局部内部类也被称为方法内部类,“局部”这个词也是老熟人了,提到作用域就肯定会提到它。既然是局部 XX 也就是指它是被定义在外部类的某个函数中的,它的书写位置与该方法的局部变量平级。作为方法的内部定义,同局部变量一样,只能在函数内部使用、没有访问修饰符。
3. 局部内部类
局部内部类只能在定义它的函数里使用。 ```java // Outside.java public class Outside { // 外部类属性 public String nameOutside = “外部类”;
public void foo() {
class Inside {
String nameInside = "内部类 inside";
public void print() {
System.out.println(nameInside + "," + nameOutside);
}
}
new Inside().print();
} }
// TestMain.java public class TestMain { public static void main(String[] args) { // 外部类的实例 Outside outsideObj = new Outside(); outsideObj.foo(); } }
<br />对于参数的使用,也是需要小心操作的。内部类中,书写 this 代表的是当前内部类对象,若要表示它所关联的外部类,要写成 `外部类.this.属性`。局部内部类中的方法,可以操作外部类属性。
```java
// Outside.java
public class Outside {
// 外部类属性
public String nameOutside = "外部类";
public int number = 5;
public void foo() {
class Inside {
String nameInside = "内部类 inside";
public int number = 10;
public void print() {
System.out.println(nameInside + "," + nameOutside);
}
public void printNumber(int number) {
System.out.println(number);
System.out.println(this.number); // 访问自身属性
System.out.println(Outside.this.number); // 访问外部类属性
}
}
Inside inside = new Inside();
inside.printNumber(number);
}
}
// TestMain.java
public class TestMain {
public static void main(String[] args) {
// 外部类的实例
Outside outsideObj = new Outside();
outsideObj.foo();
}
}
4. 匿名内部类
匿名内部类是在 new 对象同时去定义这个对象中的属性和行为的,由于没有取名字只能使用一次。
new Object(){
private int a;
public void test(){
}
}.test();
编译后的文件
含有内部类的 .java 文件在编译后会一个类生成一篇 .class 文件,在 out 文件夹可以查看
- 成员内部类编译后的 .class 文件名:外部类名字+$+内部类的名字
- 局部内部类编译后 .class 文件名:外部类名+$序号+内部类名
- 一个函数中可能会存在多个局部内部类,编译后序号从1开始,是同名局部内部类编译的顺序序号
根据语法特殊性,成员内部类 和 局部内部类 可被分为:
- 成员内部类分为:普通成员内部类、静态内部类
- 区别就在于加不加 static 关键字
- 局部内部类分为:普通局部内部类、匿名内部类
- 匿名内部类就是没有给类取类名的。由于没有名字就无法再次使用了,所以在定义时马上产生对象,只能使用一次