爪哇基础题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新年愿望##悬赏#
java基础知识 文章被收录于专栏

我是一个转码的小白,平时会在牛客中做选择题,在做题中遇到不会的内容就会去找视频或者文章学习,以此不断积累知识。这个专栏主要是记录一些我通过做题所学到的基础知识,希望能对大家有帮助

全部评论
test()方法中定义其实就是自动装箱了,然后你传递到add方法自增操作就是自动拆箱,你传递的不是地址,而是值,就是基本数据类型的传递,你见过地址还能自增的吗,只不过是自动拆箱进行了自增操作,所以add方法就没啥用,因为拷贝的副本到add方法中,对test方法中的a,b没影响,但是你++a,a自增了所以a的值就是 -128,b也一样,没变就是127 所以答案 -128 127
1 回复 分享
发布于 2023-01-07 11:38 山西
围观学术大佬
点赞 回复 分享
发布于 2023-01-06 10:58 湖北

相关推荐

10-05 23:02
东北大学 Java
我说句实话啊:那时候看三个月培训班视频,随便做个项目背点八股,都能说3 40w是侮辱价
点赞 评论 收藏
分享
评论
34
3
分享
牛客网
牛客企业服务