当前位置: 主页 > JAVA语言

java 匿名内部类 final-java 匿名内部类 final

发布时间:2023-03-24 10:07   浏览次数:次   作者:佚名

目录Kotlin 中的内部类总结

Java 中的内部类

这是一个 Java 内部类的简单实现:

public class OutterJava {
  private void printOut() {
    System.out.println("AAA");
   }
​
  class InnJava {
    public void printInn() {
      printOut();
     }
   }
}

外部类是一个私有方法,内部类为什么可以访问到外部类的私有方法呢?思考这个问题,首先要从它的字节码入手,看看 JVM 到底对 java 文件做了什么。

字节码分析流程是:

通过 javac 命令生成 class 文件,此时会发现生成了两个 class 文件,一个外部类 OtterJava 的,一个内部类 InnJava 的。

OutterJava.class

OutterJava.class 反汇编后的代码如下所示,这里面除了一个构造方法,多生成了一个

Compiled from "OutterJava.jawww.cppcns.comva"
public class java.OutterJava {
 public java.OutterJava();
  Code:
    0: aload_0
    1: invokespecial #2         // Method java/lang/Object."":()V
    4: return
​
 private void printOut();
  Code:
    0: gmdGVeWetstatic   #3         // Field java/lang/System.out:Ljava/io/PrintStream;
    3: ldc      #4         // String AAA
    5: invokevirtual #5         // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    8: return
​
 static void Access$000(java.OutterJava);
  Code:
 js   0: aload_0
    1: invokespecial #1         // Method printOut:()V
    4: return
}

从反编译出来的内容来看,多了一个静态的access$000(OutterJava)方法,它的内部调用了printOut()。

InnJava.class

Compiled from "OutterJava.java"
class java.OutterJava$InnJava {
 final java.OutterJava this$0;
​
 java.OutterJava$InnJava(java.OutterJava);
  Code:
    0: aload_0
    1: aload_1
    2: putfield   #1         // Field this$0:Ljava/OutterJava;
    5: aload_0
    6: invokespecial #2         // Method java/lang/Object."":()V
    9: return
​
 public void printInn2();
  Code:
    0: aload_0
    1: getfield   #1         // Field this$0:Ljava/OutterJava;
    4: invokestatic #3         // Method java/OutterJava.access$000:(Ljava/OutterJava;)V
    7: return
}

在 InnJava 的字节码反编译出来的内容中,主要有两个点需要注意:

小结:

在 Java 中,内部类与外部类的关系是:

Kotlin 中的内部类

同样的 Java 代码,用 Kotlin 实现:

class Outter {
  private fun printOut() {
    println("Out")
   }
​
  inner class Inner {
    fun printIn() {
      printOut()
     }
   }
}

这里如果不加inner关键字,printIn()内的printOut()会报错Unresolved reference: printOut。

不加inner关键字,反编译后的字节码:

public final class java/Outter$Inner {
  // ...
  public &l编程客栈t;init>()V
  L0
   LINENUMBER 8 L0
   ALOAD 0
   INVOKESPECIAL java/lang/Object. ()V
   RETURN
  L1
   LOCALVARIABLE this Ljava/Outter$Inner; L0 L1 0
   MAXSTACK = 1
   MAXLOCALS = 1
  // ...
}

不加inner关键字,内部类的构造方法是没有外部类实例参数的。如果加上inner,就和 Java 一样:

  // 加上了 inner 的构造方法
  public (Ljava/Outter;)V
  L0
   LINENUMBER 8 L0
   ALOAD 0
   ALOAD 1
   PUTFIELD java/Outter$Inner.this$0 : Ljava/Outter;
   ALOAD 0
   INVOKESPECIAL java/lang/Object. ()V
   RETURN
  L1
   LOCALVARIABLE this Ljava/Outter$Inner; L0 L1 0
   LOCALVARIABLE this$0 Ljava/Outter; L0 L1 1
   MAXSTACK = 2
   MAXLpythonOCALS = 2

而内部类对于外部类私有方法的访问,也是通过静态方法access$XXX来实现的:

  public final static synthetic access$printOut(Ljava/Outter;)V
  L0
   LINENUMBER 3 L0
   ALOAD 0
   INVOKESPECIAL java/Outter.printOut ()V
   RETURN
  L1
   LOCALVARIABLE $this Ljava/Outter; L0 L1 0
   MAXSTACK = 1
   MAXLOCALS = 1

总结

在 Kotlin 中java 匿名内部类 final,内部类持有外部类引用和通过静态方法访问外部类私有方法都是与 Java 一样的。唯一的不同是java 匿名内部类 final,Kotlin 中需要使用inner关键字修饰内部类,才能访问外部类中的内容。实质是inner关键字会控制内部类的构造方法是否带有外部类实例参数。

到此这篇关于Java中的Kotlin 内部类原理的文章就介绍到这了,更多相关Java Kotlin 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

本文标题: Java中的Kotlin内部类原理