• Java 内部类 面试“变态题”


    一、面试“变态题”

    题目要求:

     


    二、代码分析

    1、主程序分析:

    1)主程序中第一条语句“Outer.Inner in = new Sub( )” ,使用了多态引用说明Sub 类是继承自“Outer.Inner”类的。可推断出第一个空为:“extends Outer.Inner”。

    (2)主程序中的第二个语句“in.method( )”,创建内部类对象调用method方法,结果输出“hello inner”,可推断出子类Sub中的method 方法中包含  System.out.println("hello inner"); 语句。

    2、Outer类分析:

    (1)Outer 类中有一个 “抽象内部类”,所以子类继承时,必须重写抽象类方法。

    3、Sub类分析:

    (1)在Sub类中单单重写父类的method方法,仍然会报错,那么缺什么呢?缺一个无参的构造器。Sub(){} 

    (2)加上 Sub(){} 后,方法体的首行应该需要调用父类的构造器的方法。它的父类是 “Outer.Inner”,是一个非静态内部类。如果直接写“super()”,仍然会报错。那怎么解决呢?

    注意:此处 非静态内部类 构造器的调用需要创建父类的对象,再进行调用。

    (3)当在Sub类中创建了Outer类的对象后,写上这样的语句Outer outer = new Outer();  在Sub()方法体内写上outer.super();后。发现,仍然会报错。那为什么呢?此时看一下执行时初始化调用的语句顺序,发现调用Sub类的构造器时,会先执行outer.super()语句,但此时“outer”变量 编译器还不知道,所以为了让编译器先识别outer对象,需要在创建Outer类对象前加上关键字“static”。即“static Outer outer = new Outer();”。

    (4)说明:

    创建子类一个对象后(new),子类构造器,父类构造器,静态代码块(即static{ }),非静态代码块(即 { }),的调用顺序

    ①在子类的构造器首行中,会有默认的“super()”语句(一般情况下省略了),会先进入父类的构造器中,之后调用父类的静态代码块(没有的可跳过),然后是子类的中的静态代码块。

    ②调用父类的非静态代码块,父类的构造器。

    ③调用子类的非静态代码块,子类的构造器。


    三、本题的解题代码

    1. //2022.7.28
    2. public class TestInner {
    3. public static void main(String[] args) {
    4. Outer.Inner in = new Sub();
    5. in.method();
    6. }
    7. }
    8. class Outer{
    9. abstract class Inner{
    10. abstract void method();
    11. }
    12. }
    13. class Sub extends Outer.Inner{
    14. static Outer outer = new Outer();
    15. Sub(){
    16. outer.super();
    17. }
    18. @Override
    19. void method() {
    20. System.out.println("hello inner");
    21. }
    22. }

    四、运行结果

    打印出了题目要求,“hello inner”。 代码可行


    五、附 创建子类对象后,子类构造器与父类构造器以及静态代码块与非静态代码块的调用顺序

    1. //2022.7.28
    2. public class TestBlock {
    3. public static void main(String[] args) {
    4. //创建一个子类的对象
    5. Son son = new Son();
    6. }
    7. }
    8. class Father{
    9. //静态代码块
    10. static {
    11. System.out.println("我是父类的静态代码块");
    12. }
    13. //非静态代码块
    14. {
    15. System.out.println("我是父类的非静态代码块");
    16. }
    17. //无参构造器
    18. public Father() {
    19. System.out.println("我是父类的构造器");
    20. }
    21. }
    22. class Son extends Father{
    23. //静态代码块
    24. static {
    25. System.out.println("我是子类的静态代码块");
    26. }
    27. //非静态代码块
    28. {
    29. System.out.println("我是子类的非静态代码块");
    30. }
    31. //无参构造器
    32. public Son() {
    33. System.out.println("我是子类的构造器");
    34. }
    35. }

    六、执行结果

     

  • 相关阅读:
    区块链的使用场景和优势
    APS系统的实施步骤,外行人都能看懂
    sandman_nc_2016
    【算法挨揍日记】day12——153. 寻找旋转排序数组中的最小值、LCR 173. 点名
    vue3如何打开页面即向后端发送请求
    探讨大型公共建筑能耗监测与信息管理系统研究及应用
    Lesson 02 类与对象 (终)
    Linux C++ 051-设计模式之中介者模式
    遭遇[myers@airmail.cc].Devos勒索病毒:数据恢复和保护方法
    Qt/C++原创推流工具/支持多种流媒体服务/ZLMediaKit/srs/mediamtx等
  • 原文地址:https://blog.csdn.net/weixin_51733609/article/details/126033128