String源码中的"avoid getfield opcode"

引言:

之前一篇文章梳理了String的不变性原则,还提到了一段源码中注释"avoid getfield opcode",当时通过查阅资料发现,这是为了防止 getfield(获取指定类的实例域,并将其值压入到栈顶)这个操作码的执行,这篇文章想从字节码的角度去分析一下。



先看一段代码吧

/**
 * Created by chenqimiao on 16/11/29.
 */
public class Main {

    public   char[] chars = new char[10];

    public void test() {
        System.out.println(chars[0]);
        System.out.println(chars[1]);
        System.out.println(chars[2]);
    }

    public static void main(String args[]) {
        Main m = new Main();
        m.test();
    }
}

  执行 javap -c Main ,分析一下字节码,查看一下分析后生成的操作码:

查阅"深入理解JVM虚拟机"一书中的虚拟机字节码指令表,试着分析一下test方法下面的code.

4.获取指定的实例域,并将其值压入栈顶

7.将int型0推送至栈顶

8.将char数组指定索引的值推至栈顶

9.调用实例方法

总结一下的话,就是每次获取实例域 推到栈顶,然后推被操作的索引到栈顶,然后取到对应数组的指定索引的值推到栈顶,然后就是调用输出方法了。可以看到输出三次,getfield操作码就调用了三次,假想我们在遍历这个char数组,那象上述写法,要频繁调用getfield操作码了。

我们学一下String源码中的写法,可能能改善一下这个问题。

/**
 * Created by chenqimiao on 16/11/29.
 */
public class Main {

    public   char[] chars = new char[10];

    public void test() {
        char[] chars = this.chars;
        System.out.println(chars[0]);
        System.out.println(chars[1]);
        System.out.println(chars[2]);
    }

    public static void main(String args[]) {
        Main m = new Main();
        m.test();
    }
}

  

  执行 javap -c Main ,分析一下字节码,查看一下分析后生成的操作码:

好了,我把实例变量的数组的引用赋给了一个局部引用了。

我们还是分析一下test方法中的code把

0.将第一个引用类型本地变量推送至栈顶(就是将局部变量引用chars放到栈顶)

1.获取实例域的引用推到栈顶(实例变量的成员chars放到栈顶)

4.将栈顶顶引用类型数值存入指定本地变量(就是把成员变量chars的引用给到局部变量的引用chars,这里是引用值拷贝,不是引用指向内存的值的拷贝)

5.获取指定的实例域,并将其值压入栈顶

8.将第二个引用类型本地变量推送至栈顶

9.将int型0推到栈顶

10.将char数组指定的索引的值压入到栈顶

11.调用实例方法(输出)

在14-20的过程中没有再发生"getfield"操作,而是用aload_1操作码将第二个本地引用(被赋值后的本地引用chars)推至栈顶,就可以执行接下来的一系列操作。

到这里的话"avoid getfield opcode"的意思已经非常清楚明了,在遍历实例的char数组的时候,将实例数组的引用赋值给一个本地引用,不需要频繁调用操作用码"getfield",只需要在第一次对本地引用赋值的时候,调用一次getfield,接下来的遍历取值的时候,只需要将本地引用压入到栈顶。

 

 

时间: 2024-08-27 02:20:32

String源码中的"avoid getfield opcode"的相关文章

浅析String of "avoid getfield opcode" and "invariance"

在所有编程语言领域,我想字符串应该是地球上最常用的表达手段了吧. 在java的世界里,String是作为类出现的,核心的一个域就是一个char数组,内部就是通过维护一个不可变的char数组,来向外部输出的. 这是jdk一段String类定义,首先类是final,表明类不可被继承:核心域是private final的,final表明这个引用所指向的内存地址不会改变,但这还不足说明value[]是不可变的:因为引用所指向的内存的值有可能发生变化,但是jdk是不会让这样的事情发生的.private 保

String源码分析之Java中的String为什么是不可变的以及replace方法源码分析

什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变. 区分对象和对象的引用 对于Java初学者, 对于String是不可变对象总是存有疑惑.看下面代码: String s = "ABCabc";

Java String 源码浅析

引言 从一段代码说起: public void stringTest(){     String a = "a"+"b"+1;     String b = "ab1";     System.out.println(a == b); } 大家猜一猜结果如何?如果你的结论是true.好吧,再来一段代码: public void stringTest(){     String a = new String("ab1");   

java学习笔记-String源码分析(2)

承接上篇文章关于String源码的分析,我们继续总结String中的方法 方法汇总 4.subString方法 public String substring(int beginIndex) public String substring(int beginIndex, int endIndex) subString()有2个重载版本,beginIndex指定开始索引(包括),endIndex指定结束索引(不包括).两个方法实现类似,我们关注一个即可. public String substri

基于JDK1.8的String源码学习笔记

String,可能是学习Java一上来就学习的,经常用,但是却往往只是一知半解,甚至API有时也得现查.所以还是老规矩,倒腾源码. 一.java doc 这次首先关注String的doc,因为其实作为这么完备的语言,我感觉java 的doc是写的非常清楚的. /*Strings are constant; their values cannot be changed after they * are created. String buffers support mutable strings.

Java String源码解析

String类概要 所有的字符串字面量都属于String类,String对象创建后不可改变,因此可以缓存共享,StringBuilder,StringBuffer是可变的实现 String类提供了操作字符序列中单个字符的方法,比如有比较字符串,搜索字符串等 Java语言提供了对字符串连接运算符的特别支持(+),该符号也可用于将其他类型转换成字符串. 字符串的连接实际上是通过StringBuffer或者StringBuilder的append()方法来实现的 一般情况下,传递一个空参数在这类构造函

String源码分析

String类内部维护了一个char[]类型的value用来存储字符串,相对来说源码较为简单些. 1.不可变性 String的不可变主要体现在三个方面: String类被定义为final类型,不可被继承 String中的value[]被定义为final String中的所有生成新的String的操作底层都调用Array.copy或者System.copy来生成一个新的String对象 2.构造函数,String的构造函数较为简单,但以下几个较为特殊 public String(String or

String源码学习笔记

前言:他山之石,可以攻玉 (1)  String最重要的属性,用来存放字符串,很多String的方法就是通过此操作此字符数组实现的 /** 用来存放字符(s)的值 */ private final char value[]; (2)  String类的构造器比较多 列举以下两个 1. public String(char value[], int offset, int count) { //通过char[]创建String对象 offset:开端 count:个数 if (offset < 0

死磕 Java 系列(一)&mdash;&mdash; 常用类(1) String 源码解析

写在前面 这是博主新开的一个 java 学习系列,听名字就可以看出来,在这一些系列中,我们学习的知识点不再是蜻蜓点水,而是深入底层,深入源码.由此,学习过程中我们要带着一股钻劲儿,对我们不懂的知识充满质疑,力求把我们学过的知识点都搞清楚,想明白. 一.引言 在 java 的世界里,存在一种特殊的类,它们的创建方式极为特别,不需要用到 new XXX(当然也可以用这种方式创建), 但是却大量出现在我们的代码中,那就是 String 类.作为日常中使用频率最高的类,它是那么普通,普通到我们从来都不会