Java面试知识点解析-03 —— Java基础知识点

借参加过的多场Java开发面试,应聘岗位均为Java开发方向,在不断的面试中,又仔细对Java知识点进行复习和总结,也算是重新学习一下Java吧。

推荐收藏链接:Java 面试知识点解析


11)Integer 的缓存机制

解析:考察的是对源码的熟悉程度

  • 看一个例子:
    在这里插入图片描述

第一个返回true很好理解,就像上面讲的,a和b指向相同的地址。

第二个返回false是为什么呢?这是因为 Integer 有缓存机制,在 JVM 启动初期就缓存了 -128 到 127 这个区间内的所有数字。

第三个返回false是因为用了new关键字来开辟了新的空间,i和j两个对象分别指向堆区中的两块内存空间。

我们可以跟踪一下Integer的源码,看看到底怎么回事。在IDEA中,你只需要按住Ctrl然后点击Integer,就会自动进入jar包中对应的类文件。
在这里插入图片描述
跟踪到文件的700多行,你会看到这么一段,感兴趣可以仔细读一下,不用去读也没有关系,因为你只需要知道这是 Java 的一个缓存机制。Integer 类的内部类缓存了 -128 到 127 的所有数字。(事实上,Integer类的缓存上限是可以通过修改系统来更改的,了解就行了,不必去深究。)

12)下述两种方法分别创建了几个 Sring 对象?
// 第一种:直接赋一个字面量
String str1 = "ABCD";
// 第二种:通过构造器创建
String str2 = new String("ABCD");

解析:考察的是对 String 对象和 JVM 内存划分的知识。

答:String str1 = "ABCD";最多创建一个String对象,最少不创建String对象.如果常量池中,存在”ABCD”,那么str1直接引用,此时不创建String对象.否则,先在常量池先创建”ABCD”内存空间,再引用。

String str2 = new String("ABCD");最多创建两个String对象,至少创建一个String对象。new关键字绝对会在堆空间创建一块新的内存区域,所以至少创建一个String对象。

我们来看图理解一下:
在这里插入图片描述

  • 当执行第一句话的时候,会在常量池中添加一个新的ABCD字符,str1指向常量池的ABCD
  • 当执行第二句话的时候,因为有new操作符,所以会在堆空间新开辟一块空间用来存储新的String对象,因为此时常量池中已经有了ABCD字符,所以堆中的String对象指向常量池中的ABCD,而str2则指向堆空间中的String对象。

String 对象是一个特殊的存在,需要注意的知识点也比较多,需要大家多注意。

13)i++ 与 ++i 到底有什么不同?

解析:对于这两个的区别,熟悉的表述是:

  • 前置++是先将变量的值加 1,然后使用加 1 后的值参与运算;
  • 后置++则是先使用该值参与运算,然后再将该值加 1 ;
  • 但事实上,前置++和后置++一样,在参与运算之前都会将变量的值加 1

答:实际上,不管是前置 ++,还是后置 ++,都是先将变量的值加 1,然后才继续计算的。二者之间真正的区别是:前置 ++ 是将变量的值加 1 后,使用增值后的变量进行运算的,而后置 ++ 是首先将变量赋值给一个临时变量,接下来对变量的值加 1,然后使用那个临时变量进行运算。

14)交换变量的三种方式

答:

  • 第一种:通过第三个变量

      public class Test{
              public static void main(String[] args) {
                  int x = 5;
                  int y = 10;
                  swap(x,y);
                  System.out.println(x);
                  System.out.println(y);
          
                  Value v = new Value(5,10);
                  swap(v);
                  System.out.println(v.x);
                  System.out.println(v.y);
              }
          
              // 无效的交换:形参的改变无法反作用于实参
              public static void swap(int x,int y) {
                  int temp = x;
                  x = y;
                  y = temp;
              }
          
          // 有效的交换:通过引用(变量指向一个对象)来修改成员变量
          public static void swap(Value value) {
              int temp = value.x;
              value.x = value.y;
              value.y = temp;
          }
      }
    
      class Value{
    
      		int x;
      		int y;
      	
      		public Value(int x,int y) {
      			this.x = x;
      			this.y = y;
       		}
    
      }
    

输出的结果:
5
10
10
5

这有点类似于C/C++语言中的指针,不过相对来说更加安全。

事实上,其实如果把基础类型int改成对应的包装类的话其实可以更加简单的完成这个操作,不过需要付出更多的内存代价。

  • 第二种:通过通过相加的方式(相同的 Value 类不再重复展示)

      public class Test{
          public static void main(String[] args) {
              Value v1 = new Value(5,10);
              swap(v1);
              System.out.println("v1交换之后的结果为:");
              System.out.println(v1.x);
              System.out.println(v1.y);
          }
      
          public static void swap(Value v) {
              v.x = v.x + v.y;
              v.y = v.x - v.y;
              v.x = v.x - v.y;
          }
      }
    

    输出的结果:
    v1的交换结果:
    10
    5

核心的算法就是swap方法:

v.x = v.x + v.y;    // 把v.x与v.y的和存储在v.x中
v.y = v.x - v.y;    // v.x减掉v.y本来的值即为v.x
v.x = v.x - v.y;    // v.x减掉v.y的值也就是以前x.y的值

这样就可以不通过临时变量,来达到交换两个变量的目的,如果觉得上面的方法不太容易理解,我们也可以用另一个参数z来表示上述过程:

int z = v.x + v.y;    // 把v.x与v.y的和存储在z中
v.y = z - v.y;        // z减掉以前的v.y就等于v.x
v.x = z - v.y;        // z减掉现在的v.y即以前的v.x,即为v.y

但并不推荐这种做法,原因在于当数值很大的时候,16进制的求和运算可能造成数据的溢出,虽然最后的结果依然会是我们所期望的那样,但仍然不是十分可取。

  • 第三种:通过异或的方式:

位异或运算符(^)有这样的一个性质,就是两个整型的数据x与y,有:
(x ^ y ^ y) == x 这说明,如果一个变量x异或另外一个变量y两次,结果为x。通过这一点,可以实现交换两个变量的值:

    public class Test{
        public static void main(String[] args) {
            Value v1 = new Value(5,10);
            swap(v1);
            System.out.println("v1交换之后的结果为:");
            System.out.println(v1.x);
            System.out.println(v1.y);
        }
        
        public static void swap(Value v) {
            v.x = v.x ^ v.y;
            v.y = v.x ^ v.y;
            v.x = v.x ^ v.y;
        }
    }

输出的结果:
v1交换之后的结果为:
10
5

跟上面相加的方式过程几乎类似,只不过运算的方式不同而已。异或的方法比相加更加可取的地方在于,异或不存在数据溢出。


我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。扫描二维码加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/alogtech6/article/details/89455798