爪哇基础题06
今天正确率比较高,达到80%,今天的题都是一些问输出结果的题,没有概念题,概念题太难了看哪个都觉得对,就得查资料去背。第二题我有问题没有解决,希望能有高手给我指点一二,非常感谢了。
1.有如下一段代码,请选择其运行结果(C)
public class StringDemo{ private static final String MESSAGE="taobao"; public static void main(String [] args) { String a ="tao"+"bao"; String b="tao"; String c="bao"; System.out.println(a==MESSAGE); System.out.println((b+c)==MESSAGE); } }
A true true
B false false
C true false
D false true
本题考察String类型以及编译器优化,String不是基本数据类型,但是具备基本数据类型得一定特点,比如基本数据类型的变量和变量值都会存储在栈内存中,如int i = 1;变量i会存储在栈内存中,而1也会存储在栈内存中,变量i指向1。String类型创建变量赋值的时候既可以直接赋值,如String a = "taobao",又可以new一个对象出来,如String a = new String("taobao")。两者区别在于,前者变量a放在栈内存中,对象值存放在字符串常量池中,再将a指向"taobao",而后者new出来的对象"taobao"存储在堆内存,变量a存放在栈内存,a中存放的是"taobao"在堆内存地址。
字符串常量池有一个特点是数据共享,为了避免重复创建字符串对象,通过直接创建字符串对象的方式String a = "taobao",会先去字符串常量池中找一下是否已经存在了该字符串"taobao",如果有就不用创建对象,直接将该字符串对象在常量池中的地址给变量即可。如果没有,则在常量池中创建字符串对象"taobao",池中”abc“对象的引用地址返回给对象s1,这样s1的地址就在常量池中。比如你已经创建了变量a并赋值为"taobao",现在还想创建一个变量b也赋值为"taobao",此时变量b存放在栈内存中,然后查找常量池中是否有字符串"taobao",如果有就把b指向"taobao",如果没有就先在池中创建再指向。
"=="比较的是两个变量指向的地址是否一致,String a = "taobao";String b = "taobao";a==b?当然等于,两个变量指向常量池同一处。
但是堆内存可没有数据共享的特点,通过String a = new String("taobao")创建字符串对象,会把对象存储在堆内存中,变量a指向堆内存,就算创建的字符串内容是相等的,但也不是同一块内存,因此用'=='判断两个new出来的对象是否相同就肯定是false了。
现在来分析题目,第一个比较的是a和MESSAGE,MESSAGE存储在栈内存中,指向常量池,这个很容易看出,现在主要就看这个a是怎么创建的。a = "tao"+"bao",a的结果肯定是"taobao",关键是a和MESSAGE指向的内容是否是一个呢,这涉及到了编译器优化得问题,编译的时候发现有两个字符串常量相加,编译器会对其进行优化,直接将字符串合并,而不是等到运行时再合并,由此可知a和MESSAGE指向的是同一个字符串,a == MESSAGE正确。
那再来看一下(b+c)==MESSAGE,也存在加法,那这样会不会进行优化呢?答案是不能的,编译器发现这两个是变量,并不确定最后相加的内容是什么,担心b或c的值发生变化,于是编译器不会对其进行优化。那b+c的结果是什么呢,是创建了一个新对象。java对于String对象相加,并且等号右边有变量的时候,会现在堆内存中创建一个StringBuiler对象,然后通过append()方法将字符拼接,最后再用toString()方法将StringBuiler对象转成String对象,所以运算结果是在堆内存中创建了一个新对象,因此(b+c)==MESSAGE是false。
以下是扩展内容,多学了一些:
对上面的语句进行修改,System. out .println( (b+c).intern()== MESSAGE );这里返回的是true,因为intern()方法会去常量池中找有没有和(b+c)运算结果相同的常量,如果有就返回常量池相应地址,因为"taobao"已经被保存到常量池中了,所以b+c返回结果和MESSAGE一样,都指向常量池中的"taobao"。
再进行一些修改,
final String b = "tao" ;
final String c = "bao" ;
那这是后运算的b+c是什么呢?这里会使用编译器优化,因为b、c都是final修饰的,也就是说b、c之后的值都不能变化了,这样编译器就没什么可担心了,大胆的用起编译器优化,在编译时就将两个字符串合并了。但是如果有一个变量不是final,那都不会使用编译器优化。
最后做一个浅浅的总结,字符串拼接时,如果等号右边都是常量,会用编译器优化,等号右边只要有一个变量,最后都是new一个对象。这题做起来确实容易,但是要深究里面的奥秘,涉及到的知识点还真挺多呢,写完这题超累的。
2.如下代码,执行test()函数后,屏幕打印结果为()
public class Test2 { public void add(Byte b) { b = b++; } public void test() { Byte a = 127; Byte b = 127; add(++a); System.out.print(a + " "); add(b); System.out.print(b + ""); } }
A 127 127
B 128 127
C 129 128
D 以上都不对
本题考查包装类的自动装箱和拆箱。基本数据类型byte被包装成Byte类。这题我做对了是因为我知道++a之后a会越界,结果为-128,但是我看了其他人回答有关add()方法根本没作用的理由并不是很理解,都说是什么装箱拆箱的,我理解的add()方法不起作用的理由是因为Byte是引用类型,变量中理应存储的是127的地址,我把地址通过形参传递到了另一个变量,也就是说add()方法的形参b存储的也是地址,然后进入方法执行b = b++,那这就是对地址进行加1,根本不影响传入对象的值。这是我的理解,希望有高手能够指正,给我讲一下从拆箱装箱的角度判断add()方法不起作用。
#你的秋招进展怎么样了##我的2023新年愿望##悬赏#我是一个转码的小白,平时会在牛客中做选择题,在做题中遇到不会的内容就会去找视频或者文章学习,以此不断积累知识。这个专栏主要是记录一些我通过做题所学到的基础知识,希望能对大家有帮助