一、前言
在学习javac的工作机制时,书中有提到一句“javac在做编译时会对字符串常量进行合并操作”,让我不由想起在一些中申明sql容器时,会特意使用StringBuffer或者StringBuilder来定义返回的sql串。因为众所周知,java中字符串常用的拼接方式,有以下两种
String a = "";
String b = "";
String str = "";
// 直接拼接
str = a + b;
//使用数组拼接
str = new StringBuffer().append(a).append(b).toString();
抛开并发来说,效率肯定是stringbuffer最快,所以一般会以下面形式来定义sql
public String querySqlByBuffer(){
return new StringBuffer()
.append("select * from ")
.append(" dual;").toString();
}
但是根据书中描述来看,常量和变量的定义是两码事。
二、验证
之所以stringbuffer的拼接速度会比使用运算符+直接拼接快的主要原因是String的长度一旦定义后就是固定不变的,所以在程序运行中,每一次拼接都会产生新的String对象,而stringbuffer会在业务规定内将所有需要拼接的字符串使用数组的方式定义好之后,然后一次性转换为String,只有一个对象,所以效率来说,会快很多。
但是上面有一点比较重要就是“程序运行中”,在jvm运行我们的java代码之前,还有一个重要的过程就是javac的编译动作,她会将我们所写的java文件通过 词义、语义、语法等处理后转变为jvm能识别的class字节码文件。
那么按照这个说法可以推断出,对于这一类字符串常量的定义,使用运算符+进行拼接并不会影响到程序运行的效率,因为这个拼接动作在javac进行编译时就进行了合并操作。
测试如下
package com.cn.test;
public class ConstantStringSplicing {
public String querySql(){
return "select * " +
" from " +
" dual;";
}
}
上图是java文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.cn.test;
public class ConstantStringSplicing {
public ConstantStringSplicing() {
}
public String querySql() {
return "select * from dual;";
}
}
上图是class文件
可以看到,java在进行编译时,将三个字符串拼接成了一个,那么在程序运行时,其实也只存在一个string对象。
三、小结
在刚工作时,面试一般都会询问底层的掌握情况,一直不理解这种做法的意义,因为在实际工作中,大部分小白的工作内容一般都是以业务功能开发为主。在不断的学习和处理问题之后发现,底层代码的掌握,更多的体现在代码的规范性、扩展性、原子性等方面,这些方面才是评判一位IT工程师的水平。