四道Java基础题,你能对几道?

一、==符的使用

首先看一段比较有意思的代码

Integer a = 1000,b=1000;  
Integer c = 100,d=100;    public void mRun(final String name){  
        new Runnable() {  
              
            public void run() {  
                System.out.println(name);  
            }  
        };  
    }  
      
  
System.out.println(a==b);  
System.out.println(c==d);  

如果这道题你能得出正确答案,并能了解其中的原理的话。说明你基础还可以。如果你的答案 是 true 和true的话,你的基础就有所欠缺了。

首先公布下答案, 运行代码,我们会得到 false true。我们知道==比较的是两个对象的引用,这里的abcd都是新建出来的对象,按理说都应该输入false才对。这就是这道题的有趣之处,无论是面试题还是论坛讨论区,这道题的出场率都很高。原理其实很简单,我们去看下Integer.java这个类就了然了。

public static Integer valueOf(int i) {  
      return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];  
  }  
  
  /** 
   * A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing 
   */  
  private static final Integer[] SMALL_VALUES = new Integer[256];  
  
  static {  
      for (int i = -128; i < 128; i++) {  
          SMALL_VALUES[i + 128] = new Integer(i);  
      }  
  }  

当我们声明一个Integer c = 100;的时候。此时会进行自动装箱操作,简单点说,也就是把基本数据类型转换成Integer对象,而转换成Integer对象正是调用的valueOf方法,可以看到,Integer中把-128-127 缓存了下来。官方解释是小的数字使用的频率比较高,所以为了优化性能,把这之间的数缓存了下来。这就是为什么这道题的答案回事false和ture了。当声明的Integer对象的值在-128-127之间的时候,引用的是同一个对象,所以结果是true。

二、String

接着看代码

String s1 = "abc";  
String s2 = "abc";  
String s3 = new String("abc");  
System.out.println(s1 == s2);  
System.out.println(s1 == s3);  

大家又来猜一猜这道题的答案是什么?

按照==的语法来看, 首先s1、s2、s3是三个不同的对象,常理来说,输出都会是false。然而程序的运行结果确实true、false。第二个输出false可以理解,第一个输出true就又让人费解了。我们知道一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,而堆内存中则存放new 出来的对象和数组。然而除此之外还有一块区域叫做常量池。像我们通常想String s1 = "abc"; 这样申明的字符串对象,其值就是存储在常量池中。当我们创建String s1 = "abc"这样一个对象之后,"abc"就存储到了常量池(也可叫做字符串池)中,当我们创建引用String s2 = "abc" 的时候,Java底层会优先在常量池中查找是否存在"abc",如果存在则让s2指向这个值,不会重新创建,如果常量池中没有则创建并添加的池中。这就是为什么答案是true 和false的原因。

三、final关键字

还是来看一段代码

    /**
    * Java学习交流QQ群:589809992 我们一起学Java!
    */
    public void mRun(final String name){  
        new Runnable() {  
              
            public void run() {  
                            try {  
                              Thread.sleep(1000);  
                           } catch (InterruptedException e) {  
                             // TODO Auto-generated catch block  
                            e.printStackTrace();  
                           }    
                           System.out.println(name);  
            }  
        }.start();  
    }  

这种代码相信大家写过很多,当内部类访问局部变量的时候,需要在局部变量前加final修饰符,不然编译器就会报错。通常我们也是这么干的。好的,第二个问题来了,为什么要加final修饰符?相信大多数小伙伴都没有思考过这个问题,但凡使用的时候,直接加上就得了,从来没去深究过其中的原理。这对于一个优秀的程序员来说是不可取,我们不仅要知其然还要知其所以然。

现在我们来分析一下,为什么要加final关键字。首先内部类的生命周期是成员级别的,而局部变量的生命周期实在方法体之类。也就是说会出现这样一种情况,当mRun方法执行,new 的线程运行,新线程里面会睡一秒。主线程会继续执行,mRun执行完毕,name属性生命周期结束。1秒之后,Syetem.out.printh(name)执行。然而此时name已经寿终正寝,不在内存中了。Java就是为了杜绝这种错误,严格要求内部类中方位局部变量,必须使用final关键字修饰。局部变量被final修饰之后,此时会在内存中保有一份局部变得的复制品,当内部类访问的时候其实访问的是这个复制品。这就好像是把局部变量的生命周期变长了。说到底还是Java工程师提前把这个坑给我们填了,不然不知道又会有多少小伙伴会为了内部类局部变量而发愁了。

四、Integer与int那些事

看下面代码

Integer a = new Integer(1000);  
int b = 1000;  
Integer c = new Integer(10);  
Integer d = new Integer(10);  
System.out.println(a == b);  
System.out.println(c == d);  

这道题是继第一题的后续,如果这道题你能很快速的得出答案,那么恭喜你,==比较符你就算掌握的比较透彻了。

--------------------------------分割线-----------------------------------

正确答案: true 、false

看到这个答案很多小伙伴又会不解,先来说下第二个,按第一题来说Integer不是把-128-127缓存起来了吗?这不是应该是true嘛,但是你仔细看,这里的Integer是我们自己new出来的,并不是用的缓存,所以结果是false。 现在来看第一个为啥又是true了呢? 首先这里的值为1000,肯定和我们所知的Integer缓存没有关系。既然和缓存没有关系,a是新new出来的对象,按理说输入应该是false才对。但是注意b这里是int类型。当int和Integer进行==比较的时候,Java会把Integer进行自动拆箱,也就是把Integer转成int类型,所以这里进行比较的是int类型的值,所以结果即为true。

我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏工科狗和生物喵

【计算机本科补全计划】C++ Primer:指针和const限定符

正文之前 今天下午看了一下午的计算机组成与设计,结果好死不死的看到了设计部分--处理器的设计。天哪,我现在还只是一个准备给人装一台电脑做实验田的家伙,连用都不咋...

2694
来自专栏工科狗和生物喵

【计算机本科补全计划】《C++ Primer》:数组全解!!

正文之前 其实我的《C++ Primer》 已经看到第五章了,但是因为码字比较费时间,所以暂时没有迅速更新实在是对不住,但是没办法, 总不能一天拿出五六个小时来...

34110
来自专栏闰土大叔

闰土说JS进阶之「戏说数组」

前言 最近一段时间,我女票跟我诉苦说他们公司很多同事(包括老板),一到中午都痴迷于玩王者荣耀,不玩的会受到排挤,参与不进话题。“什么?你居然不知道梦奇,这可是王...

35111
来自专栏cmazxiaoma的架构师之路

你应该会的一道多线程笔试题

2043
来自专栏猿人谷

总结---5

1.语义搜索 所谓语义搜索,是指搜索引擎的工作不再拘泥于用户所输入的关键字,而是准确捕捉到用户所输入语句后面的真正意图,并以此来进行搜索,微软、谷歌和Fac...

18610
来自专栏青枫的专栏

JVM对异常的默认处理方案

701
来自专栏高性能服务器开发

你一定要搞明白的C函数调用方式与栈原理

这绝对不是标题党。而是C/C++开发中你必须要掌握的基础知识,也是高级技术岗位面试中高频题。我真的真的真的希望无论是学生还是广大C/C++开发者,都该掌握此文中...

1172
来自专栏工科狗和生物喵

【计算机本科补全计划】《C++ Primer》:表达式以及运算符

正文之前 好久没写了啊!!感觉自己都已经不爱简书了。不过其实我的《C++ Primer》已经看到400多页了。然而网络笔记还停留在120页,这个很骚啊,意味着我...

3357
来自专栏Android干货

Python面向对象编程

面向对象最重要的概念就是类(Class)和实例(Instance),Java比较熟了,下面贴代码注释

611
来自专栏Coding迪斯尼

使用普拉特分析法解析极为复杂的算术表达式

803

扫码关注云+社区