目录
在类中定义的类称为内部类,内部类又可以分为成员内部类(实例内部类、静态内部类)、局部内部类、匿名内部类等。
成员内部类:在一个类中,与类成员变量、方法同级别的类,可以称为成员内部类。
实例内部类
- public class Main {
- public static void main(String[] args) {
- Outer outer = new Outer("Outer"); // 实例化一个Outer
- Outer.Inner inner = outer.new Inner(); // 实例化一个Inner
- inner.hello();
- }
- }
-
- class Outer { // 定义一个外部类
- private String name;
-
- Outer(String name) {
- this.name = name;
- }
-
- class Inner { // 定义一个内部类
- void hello() {
- System.out.println("Hello, " + Outer.this.name);
- }
- }
- }
Outer是一个外部类,而Inner是一个内部,它与外部类有个最大的不同,就是内部类的实例不能单独存在,必须依附于一个外部类的实例。
静态内部类
- public class Main {
- public static void main(String[] args) {
- Outer.StaticNested sn = new Outer.StaticNested();
- sn.hello();
- }
- }
-
- class Outer {
-
- private static String NAME = "OUTER";
-
- private String name;
-
- Outer(String name) {
- this.name = name;
- }
-
- static class StaticNested {
- void hello() {
- System.out.println("Hello, " + Outer.NAME);
- }
- }
- }
用static修饰的内部类不依附于外部的实例,而是一个完全独立的类,因此无法引用外部类.this,但它可以访问外部类的private静态字段和静态方法。
局部字面意思范围,例如在方法范围的类,就是一个局部内部类。
- public class Main {
- public static void main(String[] args) {
- Outer outer = new Outer("Outer");
- outer.outerMethod();
- }
- }
-
- class Outer {
-
- static String name; // 内部类可以访问,
-
- public Outer(String name){
- this.name = name;
- }
-
- void outerMethod() {
- class Inner {
- public void innerMethod() {
- System.out.println(name);
- }
-
- }
- Inner n = new Inner();
- n.innerMethod();
- }
-
-
- }
局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
局部内部类只在当前方法中有效。
匿名内部类:可以理解为隐藏了名字的内部类。
- public class Main {
- public static void main(String[] args) {
- Outer outer = new Outer("Outer"); // 实例化一个Outer
- outer.asyncHello();
- }
- }
-
- class Outer { // 定义一个外部类
- private String name;
-
- Outer(String name) {
- this.name = name;
- }
-
- void asyncHello() {
- Runnable r = new Runnable() {
- @Override
- public void run() {
- System.out.println("Hello, " + Outer.this.name);
- }
- };
- new Thread(r).start();
- }
-
- }
在asyncHello()方法中,方法内部实例化了一个Runnable。Runnable本身是接口,接口是不能实例化的,所以这里实际上是定义了一个实现了Runnable接口的匿名类,并且通过new实例化该匿名类,然后转型为Runnable。在定义匿名类的时候就必须实例化它,定义匿名类的写法如下:
- Runnable r = new Runnable() {
- // 实现必要的抽象方法...
- };
匿名类也完全可以继承自普通类
- public class Main {
- public static void main(String[] args) {
- HashMap
map1 = new HashMap (); - HashMap
map2 = new HashMap () {}; // 匿名类! - HashMap
map3 = new HashMap () { - {
- put("A", "1");
- put("B", "2");
- }
- };
- System.out.println(map3.get("A"));
- }
- }
map1是一个普通的HashMap实例,但map2是一个匿名类实例,只是该匿名类继承自HashMap。map3也是一个继承自HashMap的匿名类实例,并且添加了static代码块来初始化数据。观察编译输出可发现Main$1.class和Main$2.class两个匿名类文件。