JackLove1234 发表于 2021-2-18 09:57

java面试题,坚持复习第二天

本帖最后由 JackLove1234 于 2021-2-18 10:22 编辑

#### 一些简单的代码,我会用在线代码工具(菜鸟工具)运行一下,对于模糊的地方加以验证

#### 深入理解字符串
#### 1\. String 属于基础数据类型吗?

答:String 不是基础数据类型,它是从堆上分配来的。基础数据类型有 8
个,分别为:boolean、byte、short、int、long、float、double、char。

#### 2\. 以下可以正确获取字符串长度的是?

A:str.length
B:str.size
C:str.length()
D:str.size()

答:C

题目解析:字符串没有 length 属性,只有 `length()` 方法。

#### 3\. "==" 和 equals 的区别是什么?

答:"==" 对基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals 方法,比如
String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

**① "==" 解读**

对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

* 基本类型:比较的是值是否相同;
* 引用类型:比较的是引用是否相同。

代码示例:


​   

    String x = "string";
    String y = "string";
    String z = new String("string");
    System.out.println(x==y); // true
    System.out.println(x==z); // false
    System.out.println(x.equals(y)); // true
    System.out.println(x.equals(z)); // true


代码说明:因为 x 和 y 指向的是同一个引用,所以 `==` 也是 true,而 `new String()` 方法则重写开辟了内存空间,所以 `==`
结果为 false,而 equals 比较的一直是值,所以结果都为 true。

**② equals 解读**

equals 本质上就是 `==`,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。

首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:


​   

    class Cat {
      public Cat(String name) {
            this.name = name;
      }
      private String name;
      public String getName() {
            return name;
      }
      public void setName(String name) {
            this.name = name;
      }
    }
    Cat c1 = new Cat("王磊");
    Cat c2 = new Cat("王磊");
    System.out.println(c1.equals(c2)); // false


输出结果出乎我们的意料,竟然是 false?!

这是怎么回事,看了 equals 源码就知道了,源码如下:


​   

    public boolean equals(Object obj) {
      return (this == obj);
    }


原来 equals 本质上就是 `==`。

那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:


​   

    String s1 = new String("老王");
    String s2 = new String("老王");
    System.out.println(s1.equals(s2)); // true


同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:


​   

    public boolean equals(Object anObject) {
      if (this == anObject) {
            return true;
      }
      if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                  if (v1 != v2)
                        return false;
                  i++;
                }
                return true;
            }
      }
      return false;
    }


原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较。

总结来说,"==" 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals
方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

#### 4\. 以下代码输出的结果是?


​   

    String str = "laowang";
    str.substring(0,1);
    System.out.println(str);


A:l
B:a
C:la
D:laowang

答:D

题目解析:因为 String 的 substring() 方法不会修改原字符串内容,所以结果还是 laowang。

#### 5\. 以下字符串对比的结果是什么?


​   

    String s1 = "hi," + "lao" + "wang";
    String s2 = "hi,";
    s2 += "lao";
    s2 += "wang";
    String s3 = "hi,laowang";
    System.out.println(s1 == s2);
    System.out.println(s1 == s3);
    System.out.println(s2 == s3);


答:false true false

题目解析:String s1 = "hi," + "lao" + "wang" 代码会被 JVM 优化为:String s1 =
"hi,laowang",这样就和 s3 完全相同,s1 创建的时候会把字符"hi,laowang"放入常量池,s3
创建的时候,常量池中已经存在对应的缓存,会直接把引用返回给 s3,所以 `s1==s3` 就为 true,而 s2 使用了 `+=`
其引用地址就和其他两个不同。

#### 6\. 以下 String 传值修改后执行的结果是什么?


​   

    public static void main(String[] args) {
      String str = new String("laowang");
      change(str);
      System.out.println(str);
    }
    public static void change(String str) {
      str = "xiaowang";
    }


答:laowang

#### 7\. 以下 StringBuffer 传值修改后的执行结果是什么?


​   

    public static void main(String[] args) {
      StringBuffer sf = new StringBuffer("hi,");
      changeSf(sf);
      System.out.println(sf);
    }
    public static void changeSf(StringBuffer sf){
      sf.append("laowang");
    }


答:hi,laowang

题目解析:String 为不可变类型,在方法内对 String 修改的时候,相当修改传递过来的是一个 String 副本,所以 String
本身的值是不会被修改的,而 StringBuffer 为可变类型,参数传递过来的是对象的引用,对其修改它本身就会发生改变。

#### 8\. 以下使用 substring 执行的结果什么?


​   

    String str = "abcdef";
    System.out.println(str.substring(3, 3));


答:""(空)。

#### 9\. 判定字符串是否为空,有几种方式?

答:常用的方式有以下两种。

* str.equals("")
* str.length()==0

#### 10\. String、StringBuffer、StringBuilder 的区别?

答:以下是 String、StringBuffer、StringBuilder 的区别:

* 可变性:String 为字符串常量是不可变对象,StringBuffer 与 StringBuilder 为字符串变量是可变对象;
* 性能:String 每次修改相当于生成一个新对象,因此性能最低;StringBuffer 使用 synchronized 来保证线程安全,性能优于 String,但不如 StringBuilder;
* 线程安全:StringBuilder 为非线程安全类,StringBuffer 为线程安全类。

#### 11\. String 对象的 intern() 有什么作用?

答:intern() 方法用于查找常量池中是否存在该字符值,如果常量池中不存在则先在常量池中创建,如果已经存在则直接返回。

示例代码:


​   

    String s = "laowang";
    String s2 = s.intern();
    System.out.println(s == s2); // 返回 true


#### 12\. String s=new String("laowang") 创建了几个对象?

答:总共创建了两个对象,一个是字符串 “laowang”,另一个是指向字符串的变量 s。new String()
不管常量池有没有相同的字符串,都会在内存(非字符串常量池)中创建一个新的对象。

#### 13\. 什么是字符串常量池?

字符串常量池是存储在 Java 堆内存中的字符串池,是为防止每次新建字符串带的时间和空间消耗的一种解决方案。在创建字符串时 JVM
会首先检查字符串常量池,如果字符串已经存在池中,就返回池中的实例引用,如果字符串不在池中,就会实例化一个字符串放到池中并把当前引用指向该字符串。

#### 14\. String 不可变性都有哪些好处?

答:不可变的好处如下。

* 只有当字符串是不可变的,字符串常量池才能实现,字符串池的实现可以在运行时节约很多堆空间,因为不同的字符串变量都指向池中的同一个字符串;
* 可以避免一些安全漏洞,比如在 Socket 编程中,主机名和端口都是以字符串的形式传入,因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞;
* 多线程安全,因为字符串是不可变的,所以同一个字符串实例可以被多个线程共享,保证了多线程的安全性;
* 适合做缓存的 key,因为字符串是不可变的,所以在它创建的时候哈希值就被缓存了,不需要重新计算速度更快,所以字符串很适合作缓存的中的 key。

#### 15\. String 是否可以被继承?为什么?

答:String 不能被继承。因为 String 被声明为 final(最终类),所以不能被继承,源码如下(JDK 8)。


​   

    public final class String
      implements java.io.Serializable, Comparable<String>, CharSequence {
      //......
    }


* * *

#### Java 中的运算符和流程控制
#### 1\. Java 中 i++ 和 ++i 有什么区别?

答:i 先赋值再运算;i 先运算再赋值。

示例代码:


​   

    int i = 0;
    int i2 = i++;
    int j = 0;
    int j2 = ++j;
    System.out.println("i2=" + i2);
    System.out.println("j2=" + j2);


输出结果:i2=0,j2=1

#### 2\. 以下代码 i 的值是多少?


​   

    int i = 0;
    i = i++;
    System.out.println(i);


答:i=0

题目解析:因为 Java 虚拟机在执行 i++ 时,把这个值有赋值给了 i,而 i++ 是先赋值再相加,所以这个时候 i 接收到的结果自然是 0 了。

#### 3\. 以下代码 i2 和 i3 的值分别为多少?


​   

    int i = 0;
    int i2 = i++;
    int i3 = ++i;


答:i2=0,i3=2

#### 4\. 以下代码能不能正常执行?


​   

    if (true) System.out.println("laowang");


答:可以正常执行,其中判断条件的括号不能省略,大括号是可以省略的(作者并不建议为了省代码的而牺牲代码的可读性)。

#### 5\. 以下 switch 执行的结果是什么?


​   

    int num = 1;
    switch (num) {
      case 0:
            System.out.print("0");
      case 1:
            System.out.print("1");
      case 2:
            System.out.print("2");
      case 3:
            System.out.print("3");
      default:
            System.out.print("default");
    }


答:123default

#### 6\. switch 能否用于 byte 类型的判断上?能否用于 long 类型的判断上?

答:switch 支持 byte 类型的判断,不支持 long 类型的判断。

题目解析:switch 支持的全部类型(JDK
8):char、byte、short、int、Charachter、Byte、Short、Integer、String、enum。

#### 7\. while 必须配合 break 一起使用的说法正确吗?

答:错误,while 可以单独使用。

例如:


​   

    int i = 0;
    while (i < 3) {
      System.out.println(++i);
    }


#### 8\. 以下代码可以正常运行吗?为什么?


​   

    int i = 0;
    while (i < 3) {
      if (i == 2) {
            return;
      }
      System.out.println(++i);
    }


答:可以正常运行,这里的 return 和 break 的效果是一致的,while 可以配合 return 或 break 一起使用。

#### 9\. 以下的程序执行结果什么?


​   

    int i = 0;
    do {
      System.out.println(++i);
    } while (i < 3)


答:编译器报错,do/while 之后必须使用分号 `;` 结尾。

#### 10\. 以下程序输出的结果是?


​   

    String s = new String("laowang");
    String s2 = new String("laowang");
    System.out.println(s == s2);
    switch (s) {
      case "laowang":
            System.out.println("laowang");
            break;
      default:
            System.out.println("default");
            break;
    }


A:true,default
B:false,default
C:false,laowang
D:true,laowang

答:C

#### 11\. 以下代码循环执行了几次?


​   

    for (float i = 0; i != 10; i += 0.1) {
      System.out.println("hi");
    }


答:无数次,循环永远不会停下来。由于舍入误差,因为 0.1 无法精确的用二级制表示,所以上面代码到 0.9000001 之后,会直接跳到
1.0000001,不会等于 1,所以循环就永远不会停下来。

#### 12\. 以下代码输出的结果是?


​   

    int num = -4;
    System.out.println(num % 2 == 1 || num % 2 == -1);


A:1
B:-1
C:true
D:false

答:D

题目解析:-4 % 2 = 0 既不等于 1 也不等于 -1,所以结果为 false。

#### 13\. 以下代码输出的结果是?


​   

    int num = 4;
    num = ((num & 1) == 1);
    System.out.println(num);


A:4
B:1
C:以上都不是

答:C

题目解析:== 运算返回的是 boolean 类型,不能使用 int 接收,所以程序会报错。

冬日安好 发表于 2021-2-18 10:01

加油加油{:1_893:}{:1_893:}{:1_893:}{:1_893:}{:1_893:}

qianshang666 发表于 2021-2-18 10:08

加油加油

lwf4097 发表于 2021-2-18 10:35

优秀,赞一个

wwww7788549 发表于 2021-2-18 10:50

一起加油,HCIE努力中{:1_921:}

dhlsixsix 发表于 2021-2-18 10:52

共同加油!!!

周谋 发表于 2021-2-18 11:08

萌新进来学习了

祈愿啊 发表于 2021-2-18 13:39

学习学习

ouyangzhijiao 发表于 2021-3-1 12:35

楼主牛逼
页: [1]
查看完整版本: java面试题,坚持复习第二天