亚洲日韩精品无码一区二区三区
  • 首页
  • 日韩精品无码一本二本三本色
  • 97色色
  • 人妻少妇精品视频一区
  • 亚洲中文字幕久久无码精品
  • 18禁无遮挡羞羞污污污污网站
  • 色综合色狠狠天天综合色
  • 首页
  • 日韩精品无码一本二本三本色
  • 97色色
  • 人妻少妇精品视频一区
  • 亚洲中文字幕久久无码精品
  • 18禁无遮挡羞羞污污污污网站
  • 色综合色狠狠天天综合色

栏目分类

  • 日韩精品无码一本二本三本色
  • 97色色
  • 人妻少妇精品视频一区
  • 亚洲中文字幕久久无码精品
  • 18禁无遮挡羞羞污污污污网站
  • 色综合色狠狠天天综合色

热点资讯

  • 携程口试官确凿问我 Java 诬捏机栈!
  • 谦堂跑没有赢A股、仙股随天、牛股稠
  • 4个Windows造谣桌面照顾规章
  • 尾盘突袭!巨资炸谢涨停板 那些券商股
  • 赖国周末又收熟多起致生枪击案!五个

色综合色狠狠天天综合色

携程口试官确凿问我 Java 诬捏机栈!
发布日期:2022-06-18 17:15    点击次数:201

携程口试官确凿问我 Java 诬捏机栈!

环球好,我是阿谁长久 18 岁的老魔鬼~嘘

从《JVM 内存区域折柳》这篇著述中,环球应该 get 到了,Java 诬捏机内存区域不错折柳为要领计数器、Java 诬捏机栈、腹地样式栈和堆。今天,咱们来围绕其中的一个区域——Java 诬捏机栈,潜入地伸开下。

先浮现一下哈。这篇著述的标题里带了一个“携程口试官”,有标题党的嫌疑。但有一说一,确乎有读者在上一篇著述里留言说,携程口试官问他了 Java 诬捏机内存方面的常识点,是以今天的标题我就“借题推崇”了。

从“邂逅恨晚”这个词中,我估摸着这名读者在这道口试题前边折戟沉沙了。这样说吧,口试官确乎可爱问 Java 诬捏机方面的常识点,因为很能老练出又名应聘者的信得过功底,是以我狡计多写几篇这方面的著述,但愿能给环球多极少点匡助~

Java 诬捏机以样式当作基本的实施单元,“栈帧(Stack Frame)”则是用于复古 Java 诬捏机进行样式调用和样式实施的基本数据结构。每一个栈帧中都包含了局部变量表、操作数栈、动态一语气、样式复返地址和一些畸形的附加信息(比如与调试、性高手机推测的信息)。之前的著述里有提到过这些见解,并做了一些简便扼要的先容,但我认为还不够谛视,是以这篇重心要来先容一下栈帧中的这些见解。

1)局部变量表

局部变量表(Local Variables Table)用来保存样式中的局部变量,以及样式参数。当 Java 源代码文献被编译成 class 文献的时辰,局部变量表的最大容量就依然服气了。

咱们来看这样一段代码。

public class LocalVaraiablesTable {     private void write(int age) {         String name = "肃静王二";     } } 

write() 样式有一个参数 age,一个局部变量 name。

然后用 Intellij IDEA 的 jclasslib 查抄一下编译后的字节码文献 LocalVaraiablesTable.class。不错看到 write() 样式的 Code 属性中,Maximum local variables(局部变量表的最大容量)的值为 3。

按理说,局部变量表的最大容量应该为 2 才对,一个 age,一个 name,为什么是 3 呢?

当一个成员样式(非静态样式)被调用时,第 0 个变量其实是调用这个成员样式的对象援用,也即是阿谁大名鼎鼎的 this。调用样式 write(18),本质上是调用 write(this, 18)。

点开 Code 属性,查抄 LocalVaraiableTable 就不错看到谛视的信息了。

第 0 个是 this,类型为 LocalVaraiablesTable 对象;第 1 个是样式参数 age,类型为整形 int;第 2 个是样式里面的局部变量 name,类型为字符串 String。

固然了,局部变量表的大小并不是样式中系数局部变量的数目之和,它与变量的类型和变量的作用域相关。当一个局部变量的作用域贬抑了,它占用的局部变量表中的位置就被接下来的局部变量取代了。

来看底下这段代码。

public static void method() {     // ①     if (true) {         // ②         String name = "肃静王二";     }     // ③     if(true) {         // ④         int age = 18;     }     // ⑤ } 
method() 样式的局部变量表大小为 1,因为是静态样式,是以不需要添加 this 当作局部变量表的第一个元素; ②的时辰局部变量有一个 name,局部变量表的大小变为 1; ③的时辰 name 变量的作用域贬抑; ④的时辰局部变量有一个 age,局部变量表的大小为 1; ⑤的时辰局 age 变量的作用域贬抑;

对于局部变量的作用域,《Effective Java》 中的第 57 条提议:

将局部变量的作用域最小化,不错增强代码的可读性和可珍惜性,并镌汰出错的可能性。

在此,我还有极少要教导环球。为了尽可能省俭栈帧耗用的内存空间,18禁h漫免费漫画无码网站局部变量表中的槽是不错重用的,就像 method() 样式演示的那样,这就意味着,合理的作用域有助于进步要领的性能。

局部变量表的容量以槽(slot)为最小单元,一个槽不错容纳一个 32 位的数据类型(比如说 int,固然了,《Java 诬捏机法子》中莫得明确指出一个槽应该占用的内存空间大小,但我认为这样更容易通晓),像 float 和 double 这种明确占用 64 位的数据类型会占用两个紧挨着的槽。

来看底下的代码。

public void solt() {     double d = 1.0;     int i = 1; } 

用 jclasslib 不错查抄到,solt() 样式的 Maximum local variables 的值为 4。

为什么等于 4 呢?带上 this 也就 3 个呀?

查抄 LocalVaraiableTable 就显着了,变量 i 的下标为 3,也就意味着变量 d 占了两个槽。

2)操作数栈

同局部变量表同样,操作数栈(Operand Stack)的最大深度也在编译的时辰就服气了,被写入到了 Code 属性的 maximum stack size 中。当一个样式刚入手实施的时辰,操作数栈是空的,在样式实施经由中,会有多样字节码指示往操作数栈中写入和取出数据,也即是入栈和出栈操作。

来看底下这段代码。

public class OperandStack {     public void test() {         add(1,2);     }      private int add(int a, int b) {         return a + b;     } } 

OperandStack 类共有 2 个样式,test() 样式中调用了 add() 样式,传递了 2 个参数。用 jclasslib 不错看到,色综合色狠狠天天综合色test() 样式的 maximum stack size 的值为 3。

这是因为调用成员样式的时辰会将 this 和系数参数压入栈中,调用完了后 this 和参数都会逐一出栈。通过 「Bytecode」 面板不错查抄到对应的字节码指示。

aload_0 用于将局部变量表中下标为 0 的援用类型的变量,也即是 this 加载到操作数栈中;

iconst_1 用于将整数 1 加载到操作数栈中; iconst_2 用于将整数 2 加载到操作数栈中; invokevirtual 用于调用对象的成员样式; pop 用于将栈顶的值出栈; return 为 void 样式的复返指示。

再来看一下 add() 样式的字节码指示。

iload_1 用于将局部变量表中下标为 1 的 int 类型变量加载到操作数栈上(下标为 0 的是 this); iload_2 用于将局部变量表中下标为 2 的 int 类型变量加载到操作数栈上; iadd 用于 int 类型的加法运算; ireturn 为复返值为 int 的样式复返指示。

操作数中的数据类型必须与字节码指示匹配,以上头的 iadd 指示为例,该指示只可用于整形数据的加法运算,它在实施的时辰,栈顶的两个数据必须是 int 类型的,不行出现一个 long 型和一个 double 型的数据进行 iadd 敕令相加的情况。

3)动态一语气

每个栈帧都包含了一个指向运行普通量池中该栈帧所属样式的援用,持有这个援用是为了复古样式调用经由中的动态一语气(Dynamic Linking)。

来看底下这段代码。

public class DynamicLinking {     static abstract class Human {        protected abstract void sayHello();     }          static class Man extends Human {         @Override         protected void sayHello() {             System.out.println("须眉哭吧哭吧不是罪");         }     }          static class Woman extends Human {         @Override         protected void sayHello() {             System.out.println("山下的女人是老虎");         }     }      public static void main(String[] args) {         Human man = new Man();         Human woman = new Woman();         man.sayHello();         woman.sayHello();         man = new Woman();         man.sayHello();     } } 

环球对 Java 重写有了解的话,应该能看懂这段代码的情理。Man 类和 Woman 类剿袭了 Human 类,何况重写了 sayHello() 样式。来看一下运行效力:

须眉哭吧哭吧不是罪 山下的女人是老虎 山下的女人是老虎 

这个运行效力很好通晓,man 的援用类型为 Human,但指向的是 Man 对象,woman 的援用类型也为 Human,但指向的是 Woman 对象;之后,man 又指向了新的 Woman 对象。

从面向对象编程的角度,从多态的角度,咱们对运行效力是很好通晓的,但站在 Java 诬捏机的角度,它是何如判断 man 和 woman 该调用哪个样式的呢?

用 jclasslib 看一下 main 样式的字节码指示。

第 1 行:new 指示创建了一个 Man 对象,并将对象的内存地址压入栈中。 第 2 行:dup 指示将栈顶的值复制一份并压入栈顶。因为接下来的指示 invokespecial 会破费掉一个现时类的援用,是以需要复制一份。 第 3 行:invokespecial 指示用于调用构造样式进行启动化。 第 4 行:astore_1,Java 诬捏机从栈顶弹出 Man 对象的援用,然后将其存入下标为 1 局部变量 man 中。 第 5、6、7、8 行的指示和第 1、2、3、4 行雷同,不同的是 Woman 对象。 第 9 行:aload_1 指示将第局部变量 man 压入操作数栈中。 第 10 行:invokevirtual 指示调用对象的成员样式 sayHello(),把稳此时的对象类型为 com/itwanger/jvm/DynamicLinking$Human。 第 11 行:aload_2 指示将第局部变量 woman 压入操作数栈中。 第 12 行同第 10 行。

把稳,从字节码的角度来看,man.sayHello()(第 10 行)和 woman.sayHello()(第 12 行)的字节码是十足交流的,但咱们都知道,这两句指示最终实施的指标样式并不交流。

究竟发生了什么呢?

还得从 invokevirtual 这个指示入辖下手,看它是何如终了多态的。左证《Java 诬捏机法子》,invokevirtual 指示在运行时的剖判经由不错分为以下几步:

①、找到操作数栈顶的元素所指向的对象的本质类型,记作 C。

②、如若在类型 C 中找到与常量池中的刻画符匹配的样式,则进行看望权限校验,如若通过则复返这个样式的获胜援用,查找贬抑;不然复返 java.lang.IllegalAccessError 相当。

③、不然,按照剿袭关系从下往上一次对 C 的各个父类进行第二步的搜索和考据。

④、如若耐久莫得找到符合的样式,则抛出 java.lang.AbstractMethodError 相当。

也即是说,invokevirtual 指示在第一步的时辰就服气了运行时的本质类型,是以两次调用中的 invokevirtual 指示并不是把常量池中样式的记号援用剖判到获胜援用上就贬抑了,还会左证样式继承者的本质类型来选择样式版块,这个经由即是 Java 重写的骨子。咱们把这种在运行期左证本质类型服气样式实施版块的经由称为动态一语气。

4)样式复返地址

当一个样式入手实施后,只好两种表情不错退出这个样式:

经常退出,可能会有复返值传递给表层的样式调用者,样式是否有复返值以及复返值的类型左证样式复返的指示来决定,像之前提到的 ireturn 用于复返 int 类型,return 用于 void 样式;还有其他的一些,lreturn 用于 long 型,freturn 用于 float,dreturn 用于 double,areturn 用于援用类型。

相当退出,样式在实施的经由中遭逢了相当,何况莫得赢得妥善的管制,这种情况下,是不会给它的表层调用者复返任何值的。

不管是哪种表情退出,在样式退出后,都必须复返到样式领先被调用时的位置,要领材干不绝实施。一般来说,样式经常退出的时辰,PC 计数器的值会当作复返地址,栈帧中很可能会保存这个计数器的值,相当退出时则不会。

样式退出的经由本质上等同于把现时栈帧出栈,因此接下来可能实施的操作有:复原表层样式的局部变量表和操作数栈,把复返值(如若有的话)压入调用者栈帧的操作数栈中,调整 PC 计数器的值,找到下一条要实施的指示等。

本文转载自微信公众号「肃静王二」,不错通过以下二维码原谅。转载本文请推测肃静王二公众号。

 



上一篇:没有了
下一篇:4个Windows造谣桌面照顾规章
    友情链接:
  • 久久被窝亚洲精品爽爽爽
  • 曰批全过程免费视频播放
  • 欧美男男gaygay巨大粗长肥
  • 天天爽天天爽夜夜爽毛片
  • 男女啪激烈高潮喷水动态图

Powered by 亚洲日韩精品无码一区二区三区 @2013-2022 RSS地图 HTML地图