什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类 Car 中包含发动机类 Engine。内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名 和$符号 。 比如,Person$Heart.class
内部类分类
- 成员内部类
- 局部内部类
成员内部类
- 成员内部类 :定义在类中方法外的类
定义格式:
修饰符 class 外部类名称 {
修饰符 class 内部类名称 {
// ...
}
// ...
}
注意:
- 如果是内部类,想要访问外部类的属性和方法,可以随意访问
如何使用成员内部类?
- 间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
- 直接方式,公式:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
例如:
定义内部类
public class Body {//外部类
//外部类成员变量
private String name;
public class Heart {//内部类
public void innerMethod() {
System.out.println("我是内部类的方法");
//访问外部类的成员变量
System.out.println("我的name是" + name);
}
}
//外部类方法
public void outsideMethod() {
System.out.println("我是外部类方法");
//在外部类的方法当中,使用内部类
new Heart().innerMethod();
}
//外部类get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
定义测试类
public class BodyTest {
public static void main(String[] args) {
// 通过外部类的对象,调用外部类的方法,里面间接在使用内部类Heart
new Body().outsideMethod();
System.out.println("=====================");
Body.Heart heart = new Body().new Heart();
//调用内部类方法
heart.innerMethod();
}
}
代码执行后的结果
内部类的同名变量的访问问题
如果出现了外部类和内部类重名现象,那么在内部类中访问外部类的成员变量格式:外部类名称.this.外部类成员变量名
例如
public class Outer {
int num = 10; // 外部类的成员变量
public class Inner /*extends Object*/ {
int num = 20; // 内部类的成员变量
public void methodInner() {
int num = 30; // 内部类方法的局部变量
System.out.println(num); // 局部变量,就近原则
System.out.println(this.num); // 内部类的成员变量
System.out.println(Outer.this.num); // 外部类的成员变量
}
}
}
局部内部类
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
定义格式:
修饰符 class 外部类名称 {
修饰符 返回值类型 外部类方法名称(参数列表) {
class 局部内部类名称 {
// ...
}
}
}
注意事项:
定义一个类的时候,权限修饰符规则:
- 外部类:public / (default)
- 成员内部类:public / protected / (default) / private
- 局部内部类:什么都不能写
例如
class MyOuter {
public void methodOuter() {
class Inner { // 局部内部类
int num = 10;
public void methodInner() {
System.out.println(num);
}
}
//创建局部内部类对象
Inner inner = new Inner();
//使用内部类方法
inner.methodInner();
}
}
局部内部类的final问题
局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。备注:从Java 8+开始,只要局部变量事实不变,那么final关键字可以省略。
原因:
- new出来的对象在堆内存当中。
- 局部变量是跟着方法走的,在栈内存当中。
- 方法运行结束之后,立刻出栈,局部变量就会立刻消失。
- 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。