写在前面:内部类在编译后,会产生类似Outer$Inner.class这样的字节码文件(Outer为外部类类名,Inner为内部类内名),
假如是局部内部类,字节码文件会是Outer$1Inner.class,Outer$2Inner.class这种格式
假如内部类是匿名形式,那么会产生Outer$1.class这样的字节码文件,第二个匿名类则是Outer$2.class。
这里我定义了两个成员内部类,类名都是Inner,并不冲突
然后如果你想看一下内部类内容,可以使用 javap -private 命令~~我就不贴出来了
所以的内部类都可以直接访问到外部类的成员变量,因为内部类中持有一个外部类的引用(静态成员内部类除外)
1. 成员内部类
package InnerClass;
/**
* @author LiFeng
* @create 2019-09-10 上午 11:19
* @describe
*/
public class Outer {
private String name = "out";
private int sex = 1;
/**
* 外部类Outer中定义了内部类Outer,但是并不持有Inner的实例对象
* 修饰符通常为private,私有化内部类,以阻止其他程序对其直接访问,想要访问必须通过外部类提供的接口
* 这里设为public为演示如何在其他类中访问内部类
*/
public class Inner {
private String name = "Inner";
private int age = 20;
/**
* 成员内部类访问外部类的属性或方法时,若两者不存在同名情况,可直接访问
* 若存在同名,则采用以下方式 Outer.this.xxx() 或者 Outer.this.xx
*/
public void innerMethod() {
name = "hello";
sex = 2;
age = 18; // 直接访问外部类不同名属性
Outer.this.name = "outHello"; // 访问外部类同名属性
}
/**
* 如果想定义静态成员,则内部类必须是静态的
*/
// public static void test() {
// System.out.println("hello world");
// }
}
/**
* 外部类想要访问内部类成员属性,则必须先持有其实例对象
* 若内部类被static修饰(极少见,若内部类中定义了静态成员,则该内部类必须是静态)那么内部类只能访问外部类中的静态成员。
* 此时,外部类可以直接这样访问内部类的静态成员Inner.test()(仅限静态成员,极少这样做,就不写演示代码了)
*/
public void outerMethod() {
new Inner().innerMethod();
}
}
class Run {
public static void main(String[] args) {
Outer outer = new Outer();
// 外部获取Inner实例对象的方式
Outer.Inner inner = outer.new Inner();
inner.innerMethod();
//如果内部类是静态的,可以这样访问静态内部类的静态成员
// Outer.Inner.test();
}
}
2. 局部内部类
定义在外部类中的局部位置上。当内部类被定义在局部位置上,只能访问被final修饰的变量。(不常用,不过多介绍)
这里需要了解一下 为什么局部内部类和匿名内部类只能访问final修饰的变量?可以参考这篇文章,但是要注意的是,局部内部类不仅限于访问局部变量,成员变量也是可以访问的。
https://blog.csdn.net/sf_climber/article/details/78326984
3. 匿名内部类
匿名内部类(对象):没有名字的内部类,匿名内部类其实就是一个匿名子类对象。匿名内部类的格式:new 父类名 或者 接口名(){ 定义子类成员或者覆盖父类方法 } 其实它是一种特殊的局部内部类,所以它也有着局部内部类同样的访问限制问题。
package InnerClass;
/**
* @author LiFeng
* @create 2019-09-10 下午 2:10
* @describe
*/
public class Outer3 {
public void syso() {
// 方式一:编译通过,可以执行
new Thread() {
void show() {
System.out.println("show run");
}
}.show();
// 方式二:编译不通过
Object obj = new Object() {
void show() {
System.out.println("show run");
}
};
// 此处编译不通过,提示找不到该方法,很显然匿名内部类对象被向上转型为了Object类,而Object中确实是不存在sho()方法的
// obj.show();
}
}
匿名内部类 new A(){ } 实际上产生的是一个A的子类的实例对象,我们可以通过看编译后的字节码文件证明。上例中第一个匿名内部类通过反编译后的代码。
package InnerClass;
import java.io.PrintStream;
final class Outer3$1
extends Thread
{
void show()
{
System.out.println("show run");
}
}