学以致用,内部类中访问外部类实例

作者:计算机知识

目录:

            原理:当须要在里头类的中间访问外部类实例时,可以将代表外部类的实例的this关键字作为四个参数字传送递给内部类,那样就足以实现在内部类的在这之中访问外部类实例,其实质照旧在个中类中用外表类的实例去拜谒自己的章程而已。如下小编写的实例首借使看卡这种作用,可以参照他事他说加以考查一下:

       写了几年的Java业务代码,开掘天天基本不是在各类牛逼的框架下搬砖,正是在if/else、for、BeanUtils.copy里浪费青春(请见谅本人的直接)。是否足以能够扭转一下思路,既然接触不到可能是还没手艺去触碰那几个让您虎躯一震的代码,那好不好从Java最基础的代码入手,搞懂那个从前诸多时候只略知一贰结果(有些依旧都答不上来),却不知器材体原因的代码,致以升高小编的水准呢?那就是干吗写那边文章的来由。(PS:以上全是小编胡扯的,其实本人是被七个主题材料搞懵逼了)。

参照他事他说加以考察链接:一文让你掌握Java字节码

  • 内部类的定义及用途
  • 开荒字节码精晓个中类

       废话十分的少说,直接上代码:

Java字节码

 

using System;

namespace TestinerClass
{
    class OutClass
    {
        string name = "外部类实例字段";
        public void display()
        {
            Console.WriteLine("调用外部实例方法!");
        }
        public class InternalClass
        {
            OutClass o;//保存外部实例
            public InternalClass(OutClass outobj)
            {
                o = outobj;
            }
            public void G()
            {
                //该方法实现了在内部类中访问外部类的实例成员
                Console.WriteLine(o.name   "n");
                o.display();
            }

        }
        public void callOutClass()
        {
            InternalClass i = new InternalClass(this);
            i.G();//该方法实现了在内部类中访问外部类的实例成员
        }
        public static void Main()
        {
            OutClass outobj = new OutClass();
            outobj.callOutClass();
            Console.ReadKey();
        }
    }
}

图片 1

学以致用,内部类中访问外部类实例。Java虚拟机字节码指令

1、内部类的概念及用途

其间类(inner class)是概念在另3个类中的类。使用在那之中类,我们得以:

  • 做客该类定义所在的效能域中的数据,包蕴个人的数量
  • 能够对同3个包中的别的类隐藏起来
  • 当想要定义3个回调函数且不想编写大批量代码时,使用佚名(anonymous)内部类相比较方便

正文意在讲明当中类与外表类能够相互走访对方的私有域的规律,内部类的用法等豪门能够自动查阅(官方网址介绍轻巧明了:Nested Class);


       这段代码笔者乍壹看,五个都以true啊,都应有针对"hello world"那个字符串的在常量池中的地址啊,那有吗难的哎,自身跑了下代码,交欢的脸都被打肿了(大家能够轻视本人须臾间):

Java堪当是壹门“一遍编写翻译四处运行”的言语,但是大家对那句话的明亮深度又有个别许吧?从大家写的java文件到通过编写翻译器编译成java字节码文件(也正是.class文件),这几个历程是java编写翻译过程;而笔者辈的java虚拟机试行的正是字节码文件。不论该字节码文件来自何地,由哪一类编写翻译器编写翻译,甚至是手写字节码文件,只要符合java虚拟机的正儿8经,那么它就能够奉行该字节码文件。

 

再正是注意:

图片 2

字节码是Java程序的中间表示,就好比汇编是C或C 程序的高级中学级表示。字节码是Java文件通过javac编译器爆发的(约等于.class文件)。程序中的字节码,不管是运维时JIT照旧HotSpot,字节码都以您程序大小和推行进程的最首要的一有个别。注意,你具备的字节码愈来愈多,.class文件就越大,JIT或HotSpot运维时也就要求编写翻译更加多的代码。

贰、展开字节码明白里面类

作者们领略,内部类其实是Java语言的1种语法糖。经过编译会生成二个"外部类名$内部类名.class"的class文件。如下:

图片 3

特别轻易的1个类OuterCls,包罗了1个InnerCls内部类。通过javac编写翻译,我们得以看看列表中多了三个文件:OuterCls$InnerCls.class。

紧接着,大家通过javap -verbose查看生成的OuterCls.class:

图片 4图片 5

 1 $ javap -verbose OuterCls
 2 Warning: File ./OuterCls.class does not contain class OuterCls
 3 Classfile /Users/ntchan/code/demo/concepts/src/com/ntchan/nestedcls/OuterCls.class
 4   Last modified Aug 14, 2018; size 434 bytes
 5   MD5 checksum b9a1f41c67c8ae3be427c578ea205d20
 6   Compiled from "OuterCls.java"
 7 public class com.ntchan.nestedcls.OuterCls
 8   minor version: 0
 9   major version: 53
10   flags: (0x0021) ACC_PUBLIC, ACC_SUPER
11   this_class: #3                          // com/ntchan/nestedcls/OuterCls
12   super_class: #4                         // java/lang/Object
13   interfaces: 0, fields: 1, methods: 2, attributes: 2
14 Constant pool:
15    #1 = Fieldref           #3.#18         // com/ntchan/nestedcls/OuterCls.outerField:I
16    #2 = Methodref          #4.#19         // java/lang/Object."<init>":()V
17    #3 = Class              #20            // com/ntchan/nestedcls/OuterCls
18    #4 = Class              #21            // java/lang/Object
19    #5 = Class              #22            // com/ntchan/nestedcls/OuterCls$InnerCls
20    #6 = Utf8               InnerCls
21    #7 = Utf8               InnerClasses
22    #8 = Utf8               outerField
23    #9 = Utf8               I
24   #10 = Utf8               <init>
25   #11 = Utf8               ()V
26   #12 = Utf8               Code
27   #13 = Utf8               LineNumberTable
28   #14 = Utf8               access$000
29   #15 = Utf8               (Lcom/ntchan/nestedcls/OuterCls;)I
30   #16 = Utf8               SourceFile
31   #17 = Utf8               OuterCls.java
32   #18 = NameAndType        #8:#9          // outerField:I
33   #19 = NameAndType        #10:#11        // "<init>":()V
34   #20 = Utf8               com/ntchan/nestedcls/OuterCls
35   #21 = Utf8               java/lang/Object
36   #22 = Utf8               com/ntchan/nestedcls/OuterCls$InnerCls
37 {
38   public com.ntchan.nestedcls.OuterCls();
39     descriptor: ()V
40     flags: (0x0001) ACC_PUBLIC
41     Code:
42       stack=2, locals=1, args_size=1
43          0: aload_0
44          1: invokespecial #2                  // Method java/lang/Object."<init>":()V
45          4: aload_0
46          5: iconst_5
47          6: putfield      #1                  // Field outerField:I
48          9: return
49       LineNumberTable:
50         line 3: 0
51         line 4: 4
52 
53   static int access$000(com.ntchan.nestedcls.OuterCls);
54     descriptor: (Lcom/ntchan/nestedcls/OuterCls;)I
55     flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC
56     Code:
57       stack=1, locals=1, args_size=1
58          0: aload_0
59          1: getfield      #1                  // Field outerField:I
60          4: ireturn
61       LineNumberTable:
62         line 3: 0
63 }
64 SourceFile: "OuterCls.java"
65 InnerClasses:
66   #6= #5 of #3;                           // InnerCls=class com/ntchan/nestedcls/OuterCls$InnerCls of class com/ntchan/nestedcls/OuterCls

View Code

里面,大家发现OuterCls多了3个静态方法access$000:

图片 6

我们看一下这么些静态方法做了怎么样:

  1. 缺省修饰符,表示那一个措施的域是包可知
  2. 本条静态方法惟有1个参数:OuterCls
  3. ACC_SYNTHETIC:表示这些办法是由编写翻译器自动生成的
  4. aload_0象征把有些变量表的第二个变量加载到操作栈
  5. get田野(field) 访问实例字段 outerField
  6. ireturn 重返传参进来的OuterCls的outerFiled的值

临近开掘了哪些,比较代码,大家在里面类使用了表面类的私家域outerField,编写翻译器就自行帮我们转移了贰个仅包可见的静态方法来回到outerField的值。

紧接着,大家后续翻看里面类InnerCls的字节码:

图片 7图片 8

 1 $ javap -verbose OuterCls$InnerCls
 2 Warning: File ./OuterCls$InnerCls.class does not contain class OuterCls$InnerCls
 3 Classfile /Users/ntchan/code/demo/concepts/src/com/ntchan/nestedcls/OuterCls$InnerCls.class
 4   Last modified Aug 14, 2018; size 648 bytes
 5   MD5 checksum 344420034b48389a027a2f303cd2617c
 6   Compiled from "OuterCls.java"
 7 class com.ntchan.nestedcls.OuterCls$InnerCls
 8   minor version: 0
 9   major version: 53
10   flags: (0x0020) ACC_SUPER
11   this_class: #6                          // com/ntchan/nestedcls/OuterCls$InnerCls
12   super_class: #7                         // java/lang/Object
13   interfaces: 0, fields: 1, methods: 2, attributes: 2
14 Constant pool:
15    #1 = Fieldref           #6.#18         // com/ntchan/nestedcls/OuterCls$InnerCls.this$0:Lcom/ntchan/nestedcls/OuterCls;
16    #2 = Methodref          #7.#19         // java/lang/Object."<init>":()V
17    #3 = Fieldref           #20.#21        // java/lang/System.out:Ljava/io/PrintStream;
18    #4 = Methodref          #22.#23        // com/ntchan/nestedcls/OuterCls.access$000:(Lcom/ntchan/nestedcls/OuterCls;)I
19    #5 = Methodref          #24.#25        // java/io/PrintStream.println:(I)V
20    #6 = Class              #26            // com/ntchan/nestedcls/OuterCls$InnerCls
21    #7 = Class              #29            // java/lang/Object
22    #8 = Utf8               this$0
23    #9 = Utf8               Lcom/ntchan/nestedcls/OuterCls;
24   #10 = Utf8               <init>
25   #11 = Utf8               (Lcom/ntchan/nestedcls/OuterCls;)V
26   #12 = Utf8               Code
27   #13 = Utf8               LineNumberTable
28   #14 = Utf8               printOuterField
29   #15 = Utf8               ()V
30   #16 = Utf8               SourceFile
31   #17 = Utf8               OuterCls.java
32   #18 = NameAndType        #8:#9          // this$0:Lcom/ntchan/nestedcls/OuterCls;
33   #19 = NameAndType        #10:#15        // "<init>":()V
34   #20 = Class              #30            // java/lang/System
35   #21 = NameAndType        #31:#32        // out:Ljava/io/PrintStream;
36   #22 = Class              #33            // com/ntchan/nestedcls/OuterCls
37   #23 = NameAndType        #34:#35        // access$000:(Lcom/ntchan/nestedcls/OuterCls;)I
38   #24 = Class              #36            // java/io/PrintStream
39   #25 = NameAndType        #37:#38        // println:(I)V
40   #26 = Utf8               com/ntchan/nestedcls/OuterCls$InnerCls
41   #27 = Utf8               InnerCls
42   #28 = Utf8               InnerClasses
43   #29 = Utf8               java/lang/Object
44   #30 = Utf8               java/lang/System
45   #31 = Utf8               out
46   #32 = Utf8               Ljava/io/PrintStream;
47   #33 = Utf8               com/ntchan/nestedcls/OuterCls
48   #34 = Utf8               access$000
49   #35 = Utf8               (Lcom/ntchan/nestedcls/OuterCls;)I
50   #36 = Utf8               java/io/PrintStream
51   #37 = Utf8               println
52   #38 = Utf8               (I)V
53 {
54   final com.ntchan.nestedcls.OuterCls this$0;
55     descriptor: Lcom/ntchan/nestedcls/OuterCls;
56     flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
57 
58   com.ntchan.nestedcls.OuterCls$InnerCls(com.ntchan.nestedcls.OuterCls);
59     descriptor: (Lcom/ntchan/nestedcls/OuterCls;)V
60     flags: (0x0000)
61     Code:
62       stack=2, locals=2, args_size=2
63          0: aload_0
64          1: aload_1
65          2: putfield      #1                  // Field this$0:Lcom/ntchan/nestedcls/OuterCls;
66          5: aload_0
67          6: invokespecial #2                  // Method java/lang/Object."<init>":()V
68          9: return
69       LineNumberTable:
70         line 5: 0
71 
72   public void printOuterField();
73     descriptor: ()V
74     flags: (0x0001) ACC_PUBLIC
75     Code:
76       stack=2, locals=1, args_size=1
77          0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
78          3: aload_0
79          4: getfield      #1                  // Field this$0:Lcom/ntchan/nestedcls/OuterCls;
80          7: invokestatic  #4                  // Method com/ntchan/nestedcls/OuterCls.access$000:(Lcom/ntchan/nestedcls/OuterCls;)I
81         10: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
82         13: return
83       LineNumberTable:
84         line 7: 0
85         line 8: 13
86 }
87 SourceFile: "OuterCls.java"
88 InnerClasses:
89   #27= #6 of #22;                         // InnerCls=class com/ntchan/nestedcls/OuterCls$InnerCls of class com/ntchan/nestedcls/OuterCls

View Code

第2,大家开采访编辑写翻译器自动生成了多个注明为final的积极分子:

图片 9

我们驾驭,final修饰的成员都以编写翻译器能够规定的常量。透过final修饰的变量,都会停放class的常量池。

下一场再看一下编写翻译器自动生成的构造函数:

图片 10

实际的字节码指令笔者就不再壹壹贴出来,笔者差相当的少解释一下,这么些构造函数通过外部传参OuterCls实例,赋值给this$0(上边十二分被final修饰的变量)

末段看一下我们的printOutField方法:

图片 11

我们看来,原来调用outerField的地点,变成了OuterField.access$000(this$0),意思便是,通过OuterField的静态方法,重临this$0的Outer菲尔德。

 

总的来说,内部类访问外部类的个体成员的规律,是透过编写翻译器分别给外部类自动生成访问私有成员的静态方法access$000及给当中类自动生成外部类的final引用、外部类初始化的构造函数及修改调用外部类民用成员的代码为调用外部类包可知的access$000完结的。同理,无名氏内部类、静态内部类都能够通过这种艺术剖析完结原理

 

一.非嵌套类能够具有public或internal修饰符,私下认可为internal,可是在这之中类具备种种访问修饰符(public,private,protected internal,internal,protectde)中的大肆二个。

        这是咋回事啊,经过我1番百度,最多的回答:Java 中宏变量/宏替换指的是在编译期有些变量能够直接被其本人的值所替换,编译到.class文件中,因而,编写翻译后的.class文件中早就不存在此变量了。final修饰符修饰的变量在由于其本人的风味,在编写翻译期就能够间接分明其值,且此值不可变,但是要留意,惟有在编写翻译时期能方便知道final变量值的情况下,编写翻译器才会进展如此的优化。不晓得大家理解了不,作者是没弄明白,直到不经常间窥得大道之真言:能够经过查阅class文件的字节码,查看Java在编写翻译时期到底做了何等业务来搞掌握这么些流程,OK,那就来试一下吗:

图片 12java字节码文件

二.当在那之中类的成员与概念它的类成员重名时,内部类成员会隐藏外部类的积极分子。内部类成员的访问域越发访问修饰符决定,为注解它的类的可访问修饰符的子集。

先来编写翻译一下以此测试类:javac -verbose FinalTest.java

用javac命令或然ide工具将该java源文件编写翻译成java字节码文件,编译好的字节码文件,大家得以看来一批16进制的字节。假使运用IDE去开发,大概看到的是现已被反编写翻译的大家所耳闻则诵的java代码,而那才是正经的字节码,那也是本文的故事情节重视。对这么一群字节码感觉头痛,但是没什么,逐步试着看懂它。

 

图片 13

图片 14java字节码的总览图

 

在意尾数第一行,突然间乱入了StringBuilder,明明小编的代码里面唯有String啊,那注解肯定有个地点用到了它,在什么样地点呢?大家承接看:Javap -verbose FinalTest.class(只截取了有的)

小编们也正是依据地点的相继来对字节码进行解读的。1共含有10局地,包罗魔数,版本号,常量池等等,接下去大家根据顺序一步一步解读。

图片 15

前多少个字节表示的是魔数,对应德姆o的是 0XCAFE BABE。魔数是用来区分文件类型的一种标识,一般都以用文件的前多少个字节来代表。比方0XCAFE BABE表示的是class文件,那么有人会问,文件类型能够经过文件名后缀来剖断啊?是的,不过文件名是能够修改的,那么为了确认保障文件的安全性,将文件类型写在文书之中来保管不被篡改。从java的字节码文件类型大家来看,CAFE BABE翻译过来是咖啡珍宝之意,CAFE BABE = 咖啡。

本文由bwin必赢发布,转载请注明来源

关键词: 日记本 Java 亚洲必赢网址 C#面向对象编程 字节