手记

Java基础内部类4-内部类进阶

前言

除了前面介绍,内部类还有一些更高级的用法,下面就简单的介绍一下

接口内部类

内部类除了可以定义在类的内部,也可以定义在接口里面,用法与类类似

// Move.java

public interface Move {

    void run();
    void walk();

    class Run {

        public void move() {
            System.out.println("run");
        }
    }

    class Walk {
        public void move() {
            System.out.println("walk");
        }
    }
}

// AnimalMoveImpl.java
public class AnimalMoveImpl implements Move {
    @Override
    public void run() {
        new Run().move();
    }

    @Override
    public void walk() {
        new Walk().move();
    }
}

多层嵌套内部类访问外围类成员

内部类无论嵌套了多少层,内部类都是可以无条件的访问外部的成员,包括private

public class MultiInner {
    private int val = 0;
    class Inner1 {
        {
            System.out.println(val);
        }
        class Inner2 {
            {
                System.out.println(val);
            }
            class Inner3 {
                {
                    System.out.println(val);
                }
            }
        }
    }
}

内部类继承

这是一个比较有意思的事情

NOTE: 这里说的内部类继承不是内部类继承其他类,而是其他类继承内部类

class WithInner {
    class Inner {}
}

public class InheritInner extends WithInner.Inner {

}

在想象中应该是这样写,没问题,但是如果在ide中敲代码,编译器会报错

No enclosing instance of type 'xxx.xxx.xxx.WithInner' is in scope

意思为没有封闭类型的WithInner类型,在ide会提示一种方案是将Inner改为静态内部类,这样确实可以解决问题,但是如果不能用静态内部类呢?

试想一下为什么静态内部类可以,而成员内部类会报错,这两者有什么区别?

回头看一下发现,成员内部类在创建的时候是要依赖外部类的实例对象,但是在第三方类继承内部类的时候,没有外部类对象,这样就无法构成闭环,所以报错。解决办法也很简单,在构造第三方类的时候,手动提供一个外部类对象,并对其初始化即可

public class InheritInner extends WithInner.Inner {
    InheritInner(WithInner wi) {
        wi.super();
    }

    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
}

内部类能被覆盖吗?

你觉得呢?

分析一下,内部类(以成员内部类来说)依赖于外部类,被编译器编译成WithInner$Inner.class,假如说有个WithInner的子类SubWithInner包含了一个同名的Inner类,这个会覆盖父类中的Inner吗?子类中的Inner被编译成SubWithInner$Inner.class这明显与父类中的类名不一样。所以理论上是不会覆盖的。实践一下!

// Egg.java
public class Egg {

    private Yolk y;

    protected class Yolk {
        public Yolk() {
            System.out.println("Egg.Yolk");
        }
    }

    public Egg() {
        System.out.println("new egg()");
        y = new Yolk();
    }
}

// BigEgg.java
public class BigEgg extends Egg {

    public class Yolk {
        public Yolk() {
            System.out.println("BigEgg.Yolk");
        }
    }

    public static void main(String[] args) {
        new BigEgg();
    }
}
new egg()
Egg.Yolk

从输出结果来看,确实没有覆盖,所以,内部类是不会像方法一样被覆盖,但是,如果手动继承那就另说

关于内部类的详细文章可以参考目录 [smxknife's Java内部类]

1人推荐
随时随地看视频
慕课网APP