四道Java基础题

一、==符的使用

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


  1. Integer a = 1000,b=1000;
  2. Integer c = 100,d=100; public void mRun(final String name){
  3. new Runnable() {
  4. public void run() {
  5. System.out.println(name);
  6. }
  7. };
  8. }
  9. System.out.println(a==b);
  10. System.out.println(c==d);

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

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

  
  1. public static Integer valueOf(int i) {
  2. return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
  3. }
  4. /**
  5. * A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing
  6. */
  7. private static final Integer[] SMALL_VALUES = new Integer[256];
  8. static {
  9. for (int i = -128; i < 128; i++) {
  10. SMALL_VALUES[i + 128] = new Integer(i);
  11. }
  12. }

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

二、String

接着看代码


  1. String s1 = "abc";
  2. String s2 = "abc";
  3. String s3 = new String("abc");
  4. System.out.println(s1 == s2);
  5. 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关键字

还是来看一段代码


  1. public void mRun(final String name){
  2. new Runnable() {
  3. public void run() {
  4. try {
  5. Thread.sleep(1000);
  6. } catch (InterruptedException e) {
  7. // TODO Auto-generated catch block
  8. e.printStackTrace();
  9. }
  10. System.out.println(name);
  11. }
  12. }.start();
  13. }

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

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

四、Integer与int那些事

看下面代码

    
  1. Integer a = new Integer(1000);
  2. int b = 1000;
  3. Integer c = new Integer(10);
  4. Integer d = new Integer(10);
  5. System.out.println(a == b);
  6. 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。

来自为知笔记(Wiz)

时间: 2024-08-03 07:09:11

四道Java基础题的相关文章

【原创】这道Java基础题真的有坑!我也没想到还有续集。

前情回顾 自从我上次发了<这道Java基础题真的有坑!我求求你,认真思考后再回答.>这篇文章后.我通过这样的一个行文结构: 解析了小马哥出的这道题,让大家明白了这题的坑在哪里,这题背后隐藏的知识点是什么. 但是我是万万没想到啊,这篇文章居然还有续集.因为有很多读者给我留言,问我为什么?怎么回事?啥情况? 问题片段一:到底循环几次? 有很多读者针对文章的下面的这个片段: 来问了一些问题:为什么会循环三次?循环二次?循环一次? 源码看的脑袋疼.那我觉得我需要"拯救"一下这个哥们

转载 java基础题(面试必知)

1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二是数据抽象.2.继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法.对象的一个新类可以从现有的类中派生,这个过程称为类继承.新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类).派生类可以从它的基类那

Java基础题十道2

1 collection与collections的有什么区别? java.util.Collection 是一个集合接口.它提供了对集合对象进行基本操作的通用接口方法. Collection接口在Java 类库中有很多具体的实现. Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式. java.util.Collections 是一个包装类.它包含有各种有关集合操作的静态多态方法. 此类不能实例化,就像一个工具类,服务于Java的Collection框架. package

Java基础题

1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 答:可以包括多个类:限制:一个文件只能有一个public类,且与文件名同名. 2.Java有没有goto? 答:没有. 3.说说&和&&的区别. 答:两者都是(and)逻辑运算符,&是非短路,&&是短路的. 4.在JAVA中如何跳出当前的多重嵌套循环? 答:1.return 2.循环语句定义一个标签,再使用带有标签的break语句. 5.switch语句能否作用

java基础 题和知识点总结, 关于String s是否默认初始化为null......,new一个对象和类静态域,是不是在内存中不是一个地方

一道笔试题 22. 下面代码的运行结果为:() import java.io.*; import java.util.*; public class foo{ public static void main (String[] args){ String s; System.out.println("s=" + s); } } A 代码得到编译,并输出“s=” B 代码得到编译,并输出“s=null” C 由于String s没有初始化,代码不能编译通过 D 代码得到编译,但捕获到 N

java基础题集

1.什么是java虚拟机?为什么java被称作是"平台无关的编程语言"? java虚拟机是一个可以执行java字节码的虚拟机进程.java源文件被编译成能被java虚拟机执行的字节码文件. java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译.java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其特性. 2.JDK和JRE的区别是什么? JRE:java运行时环境,它包括java虚拟机.java核心类库和支持文件,它不包括开发工

四道java小题

一:分析以下需求,并用代码实现     1.定义List集合,存入多个字符串     2.删除集合中字符串"def"     3.然后利用迭代器遍历集合元素并输出 1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class Topic1 5 { 6 public static void main(String[] args) { 7 ArrayList<String> arrayList =

JAVA基础50题

package package0530; import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.text.DecimalFormat;import java.util.ArrayList;import java.util.Arrays;import java.util.LinkedList;import java.util

Java面试题及答案(基础题122道,代码题19道)

转载自:http://www.blogjava.net/fanyingjie/archive/2007/06/27/126467.aspx JAVA相关基础知识1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二是数据抽象.2.继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法.对象的