`
Rolandz
  • 浏览: 6885 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

对象和数组:JVM中,处理对象和数组的字节码介绍

 
阅读更多

欢迎来到“Under The Hood”第五期。本期我们来看看JVM中处理对象和数组的字节码。你可能需要阅读往期的文章才能更好的理解本文。

 

面向对象的机器

 

JVM中的数据有3种形式:对象(object),对象引用(object reference)和原始类型(primitive type)。对象存放在垃圾收集堆中;对象引用和原始类型,根据它们作用域范围的不同,分别存放在不同的地方:作为本地变量,存放在Java栈中;作为实例变量,存放在垃圾收集堆上;作为类变量,存放在方法区上。

在JVM中,垃圾收集堆上只能给对象分配内存空间。原始类型,除了作为对象的一部分,没有其他方式可以给它在堆上分配空间。在需要对象引用的地方,如果你想使用原始类型,你可以给原始类型分配java.lang包中相应的包装对象。只有对象引用和原始类型可以作为本地变量,存放在Java栈中,对象是不可能存放在栈中的。

 

JVM中,对象和原始类型在架构上的分离,体现在Java编程语言中就是:对象不能被声明成本地变量,只有对象引用才行。在声明时,对象引用不会指向具体对象,只有引用被显式的初始化之后(指向已存在对象,或者通过new关键字创建新对象),引用才会指向实际对象。

 

在JVM指令集中,除了数组,所有的对象都通过相同的操作符集来实例化和访问。在Java中,数组也是对象,并且就像Java程序中任何其他对象一样,是动态创建的。数组引用可以用在任何需要Object类型的引用的地方,Object中的任何方法,都可以在数组上调用。但是,在JVM里,数组是使用有别于对象的特殊字节码来处理的。

 

就像任何其他对象一样,数组不能被声明为本地变量;只有数组引用可以。数组对象本身,总是包含一组原始类型或者一组对象引用。如果你声明一个对象数组,你会得到一组对象引用。对象们自己必须用new显式创建,并被赋值给数组的元素。

 

处理对象的字节码

 

实例化新对象是通过操作码new来实现的,它需要2个单字节的操作数。这2个单字节操作数合并成16位的常量池索引。常量池中对应的元素给出了新对象的类型信息。就像下面所展示的,JVM在堆上创建新的对象实例,并把它的引用压入栈中。

 

new indexbyte1, indexbyte2 creates a new object on the heap, pushes reference

 

接下来的表格,列出了存取对象字段(field)的字节码。操作符putfield和getfield只负责处理实例变量。静态变量使用putstatic和getstatic访问,这个我们待会再说。操作符putfield和getfield都有2个单字节操作数,它们合并成16位的常量池索引。相应的常量池位置上存放着关于字段的类型,大小和偏移量的信息。putfield和getfield都会从栈中取得操作对象的引用。putfield从栈上获取所要赋给实例变量的值,而getfield则把取到的实例变量的值压进栈中。

 

putfield indexbyte1, indexbyte2 set field, indicated by index of object to value (both taken from stack)
getfield indexbyte1, indexbyte2 pushes field, indicated by index of object (taken from stack)

 

如下表所示,静态变量通过putstatic和getstatic来访问。它们所拥有的2个单字节的操作数,会由JVM合并成16位的常量池索引。对应的常量池位置上存有静态变量的相关信息。由于静态变量不跟任何对象关联,putstatic和getstatic也不会使用对象引用。putstatic从栈中取得所要附给静态变量的值,而getstatic则把静态变量的值压入栈中。

 

putstatic indexbyte1, indexbyte2 set field, indicated by index, of object to value (both taken from stack)
getstatic indexbyte1, indexbyte2 pushes field, indicated by index, of object (taken from stack)

 

下面的操作码用来检查栈顶的对象引用,是不是指向由操作数所索引的类或接口的实例。

 

当对象不是指定类或接口的实例时,checkcast指令会抛出CheckCastException异常;反之,checkcast什么也不做,对象引用仍保留在栈顶,继续执行下一个指令。checkcast指令保证了运行时的类型转换是安全的,它是JVM安全系统的一部分。

 

instanceof指令弹出栈顶的对象引用,最后把true或false压入栈中。如果对象确实是指定类或接口的实例,则把true入栈;反之,false入栈。instanceof指令实现了Java语言中的instanceof关键字,它允许程序员测试一个对象是不是某个类或接口的实例。

 

checkcast indexbyte1, indexbyte2 Throws ClassCastException if objectref on stack cannot be cast to class at index
instanceof indexbyte1, indexbyte2 Pushes true if objectref on stack is an instanceof class at index, else pushes false

 

处理数组的字节码

 

可以通过指令newarray,anewarray,和multianewarray实例化数组。

 

newarray用来创建原始类型的数组,具体类型由它的单字节操作数指定。它可以创建的数组类型有byte,short,char,int,long,float,double和boolean。

 

anewarray创建对象引用数组,它的2个单字节操作数合并成16位常量池索引,由此获取到要创建的包含在数组中的对象类型信息。anewarray为数组中的对象引用分配控件,并把它们都设置为null。

 

multianewarray用来分配多维数组(数组的数组),可以通过重复调用newarray和anewarray来实现。multianewarray指令只是简单的把创建多维数组的多条字节码压缩成一个指令。它的开头2个单字节操作数合并成常量池索引,由此获取多维数组中的对象类型。第3个单字节操作数指明了多维数组的维数。至于每维的数组大小需从栈上获取。该指令为多维数组中所有的数组分配空间。

 

newarray atype pops length, allocates new array of primitive types of type indicated by atype, pushes objectref of new array
anewarray indexbyte1, indexbyte2 pops length, allocates a new array of objects of class indicated by indexbyte1 and indexbyte2, pushes objectref of new array
multianewarray indexbyte1, indexbyte2, dimensions pops dimensions number of array lengths, allocates a new multidimensional array of class indicated by indexbyte1 and indexbyte2, pushes objectref of new array

 

下表列出的指令把栈顶的数组引用弹出,把它的长度压入栈中。

 

arraylength (none) pops objectref of an array, pushes length of that array

 

下面的操作码获取数组中的元素。数组索引和数组引用从栈上弹出,数组中指定索引处的值被压入栈中。

 

baload (none) pops index and arrayref of an array of bytes, pushes arrayref[index]
caload (none) pops index and arrayref of an array of chars, pushes arrayref[index]
saload (none) pops index and arrayref of an array of shorts, pushes arrayref[index]
iaload (none) pops index and arrayref of an array of ints, pushes arrayref[index]
laload (none) pops index and arrayref of an array of longs, pushes arrayref[index]
faload (none) pops index and arrayref of an array of floats, pushes arrayref[index]
daload (none) pops index and arrayref of an array of doubles, pushes arrayref[index]
aaload (none) pops index and arrayref of an array of objectrefs, pushes arrayref[index]

 

下表列出了把值存入数组元素中的操作码。值、索引和数组引用均从栈顶弹出。

 

bastore (none) pops value index, and arrayref of an array of bytes, assigns arrayref[index] = value
castore (none) pops value index, and arrayref of an array of chars, assigns arrayref[index] = value
sastore (none) pops value index, and arrayref of an array of shorts, assigns arrayref[index] = value
iastore (none) pops value index, and arrayref of an array of ints ,assigns arrayref[index] = value
lastore (none) pops value index, and arrayref of an array of longs, assigns arrayref[index] = value
fastore (none) pops value index, and arrayref of an array of floats, assigns arrayref[index] = value
dastore (none) pops value index, and arrayref of an array of doubles, assigns arrayref[index] = value
aastore (none) pops value index, and arrayref of an array of objectrefs, assigns arrayref[index] = value

 

本文译自:Objects and Arrays

原创文章,转载请注明: 转载自码农合作社
本文链接地址: 对象和数组:JVM中,处理对象和数组的字节码介绍

1
0
分享到:
评论

相关推荐

    一个java对象占多少个字节的总结和理解_javajvm_

    首先,Java对象主要存在于JVM的堆内存中,堆是Java程序运行时的主要内存区域,用于存储所有实例对象和数组。堆内存由Java虚拟机自动管理,包括分配和回收。 1. **对象头**:每个Java对象都有一个对象头,它包含两...

    java JVM 详解

    Java JVM 是 Java 语言的核心组件之一,负责将 Java 字节码翻译成机器语言并执行。要深入了解 JVM,可以从 Java 的特性入手,描绘 JVM 的大致应用,然后细细阐述 JVM 的原理及内存管理机制和调优。最后,还需要讲述...

    JVM指令手册_jvm指令手册_

    10. **类和数组操作指令**:`newarray`用于创建数组,`anewarray`创建引用类型数组,`multianewarray`创建多维数组,`ldc`用于加载常量池中的类名或字符串。 理解JVM指令手册对于优化Java代码、进行内存分析、理解...

    JVM指令码表.zip

    5. **对象和数组操作指令**:如`new`创建新对象,`getfield`和`putfield`访问或修改实例字段,`aaload`和`aastore`用于数组元素的加载和存储。 6. **方法调用与返回指令**:`invokevirtual`用于调用对象的虚方法,`...

    jvm指令手册 +JVM必知必会,掌握虚拟机编译过程.rar

    JVM指令主要分为:本地变量表到操作数栈类指令、操作数栈到本地变量表类指令、常数到操作数栈类指令、将数组指定索引的数组推送至操作数栈类指令、将操作数栈数存储到数组指定索引类指令、操作数栈其他相关类指令、...

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

    3.4.3 第三趟:字节码验证 3.4.4 第四趟:符号引用的验证 3.4.5 二进制兼容 3.5 java虚拟机中内置的安全特性 3.6 安全管理器和java api 3.7 代码签名和认证 3.8 一个代码签名示例 3.9 策略 3.10...

    JVM指令集.zip

    - **对象和数组操作指令**:涉及对象的创建、引用、方法调用以及数组的访问(如`new`创建新对象,`getfield`获取对象字段值,`invokevirtual`调用虚方法,`aaload`取数组元素)。 - **类和接口操作指令**:处理类...

    JVM 50道面试题和答案.docx

    - 堆(Heap):所有对象实例和数组都在堆中分配。 - 方法区(Method Area):存储类和接口的信息,包括运行时常量池。 - 运行时常量池(Run-Time Constant Pool):属于方法区,存储常量和符号引用。 - 本地方法...

    JVM.rar_jvm_虚拟机

    JVM虚拟机指令集是Java字节码的基石,它由一系列低级、简单的操作码组成,这些操作码负责执行基本的计算和控制任务。每条指令通常对应一个字节,并且有特定的含义和作用。例如: 1. **加载和存储指令**:如`iload`...

    Java数组详细资料.pdf

    程序计数器记录线程执行的字节码行号,本地方法栈服务于native方法,方法区存储类信息、常量、静态变量等,Java虚拟机栈存储方法的局部变量和操作栈,而Java堆是所有线程共享的内存区域,用于存放对象实例和数组。...

    JVM与性能优化--知识点整理.pdf

    2. **字节码指令**:Java字节码是一系列基于16位的指令,包括加载和存储指令、运算或算术指令、类型转换指令、创建对象和数组的指令等。 - **加载和存储指令**:如`iload`用于从局部变量表加载整数到操作数栈,`...

    JVM详解及调优

    然后,字节码文件被加载到JVM中执行。JVM负责解释字节码并在目标平台上执行。 **1.4 半编译半解释** Java的执行方式被称为“半编译半解释”。编译是指将源代码转换成字节码的过程,而解释是指JVM动态地执行这些...

    浅谈JAVA虚拟机JVM及工作原理

    堆是 JVM 中的内存区域,用于存储对象实例和数组。 3. 方法区(Method Area) 方法区是 JVM 中的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区是各个线程共享...

    Inside+the+Java+Virtual+Machine.pdf

    - **对象和数组**(Chapter 15)、**控制流**(Chapter 16)、**异常处理**(Chapter 17):这些章节涵盖了Java编程中的核心概念,如对象创建、数组操作、条件语句、循环控制以及异常捕获等。 - **最终子句**...

    inside the java virtual machine 英文版

    - **字节码**: Java编译器将源代码编译成中间格式——字节码,这些字节码可以在任何支持JVM的平台上运行。 - **JVM实现**: 不同操作系统上的JVM实现会有所不同,但它们都遵循相同的规范,确保字节码可以正确执行。 ...

Global site tag (gtag.js) - Google Analytics