Java经典面试题最详细版(面试必备)

本文详细探讨了Java的各个方面,包括JVM、JRE、JDK的关系,Java语言特点,与C++的区别,基本数据类型,类型转换,装箱拆箱,String对象,以及面向对象的特性。此外,还深入讲解了Java的内存模型,反射,异常处理,注解,泛型,序列化,深拷贝和浅拷贝,以及Object类的重要方法。这些都是Java开发者面试和工作中需要掌握的关键知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JVM、JRE及JDK的关系 **

​ JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。

​ Java Runtime Environment(JRE)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。

​ JVM是Java Virtual Machine(Java虚拟机)的缩写,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。

​ 简单来说就是JDK是Java的开发工具,JRE是Java程序运行所需的环境,JVM是Java虚拟机.它们之间的关系是JDK包含JRE和JVM,JRE包含JVM.

JAVA语言特点 **

  • Java是一种面向对象的语言
  • Java通过Java虚拟机实现了平台无关性,一次编译,到处运行
  • 支持多线程
  • 支持网络编程
  • 具有较高的安全性和可靠性

JAVA和C++的区别 **

面试时记住前四个就行了
  • Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
  • Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
  • Java 支持自动垃圾回收,而 C++ 需要手动回收。
  • Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
  • Java 不支持操作符重载,虽然可以对两个 String 对象执行加法运算,但是这是语言内置支持的操作,不属于操
    作符重载,而 C++ 可以。
  • Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。

Java的基本数据类型  **

注意 String不是基本数据类型
类型 关键字 包装器类型 占用内存(字节)(重要) 取值范围 默认值
字节型 byte Byte 1 -128(-2^7) ~ 127(2^7-1) 0
短整型 short Short 2 -2^15 ~ 2^15-1 0
整型 int Integer 4 -2^31 ~ 2^31-1 0
长整型 long Long 8 -2^63 ~ 2^63-1 0L
单精度浮点型 float Float 4 3.4e-45 ~ 1.4e38 0.0F
双精度浮点型 double Double 8 4.9e-324 ~ 1.8e308 0.0D
字符型 char Character 2 '\u0000'
布尔型 boolean Boolean 1 true/flase flase

隐式(自动)类型转换和显示(强制)类型转换 **

  • 隐式(自动)类型转换:从存储范围小的类型到存储范围大的类型。byteshort(char)intlongfloatdouble
  • 显示(强制)类型转换:从存储范围大的类型到存储范围小的类型。doublefloatlongintshort(char)byte。该类类型转换很可能存在精度的损失。

看一个经典的代码

short s = 1;
s = s + 1;

这是会报错的,因为1是int型,s+1会自动转换为int型,将int型直接赋值给short型会报错。

做一下修改即可避免报错

short s = 1;
s = (short)(s + 1);

或这样写,因为s += 1会自动进行强制类型转换

short s = 1;
s += 1;

自动装箱与拆箱 **

  • 装箱:将基本类型用包装器类型包装起来
  • 拆箱:将包装器类型转换为基本类型

    这个地方有很多易混淆的地方,但在面试中问到的频率一般,笔试的选择题中经常出现,还有一个 String创建对象和这个比较像,很容易混淆,在下文可以看到
  • 下面这段代码的输出结果是什么?

    public class Main {
        public static void main(String[] args) {
            
                Integer a = 100;
                Integer b = 100;
                Integer c = 128;
                Integer d = 128;
    
                System.out.println(a==b);
                System.out.println(c==d);
        }
    }
    true
    false

    很多人看到这个结果会很疑惑,为什么会是一个true一个flase.其实从源码中可以很容易找到原因.首先找到Integer方法中的valueOf方法

    public static Integer valueOf(int i) {
          if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
          return new Integer(i);
      }

    可以看到当不满足if语句中的条件,就会重新创建一个对象返回,那结果必然不相等。继续打开IntegerCache可以看到

        private static class IntegerCache {
              static final int low = -128;
            static final int high;
              static final Integer cache[];
      
              static {
                  // high value may be configured by property
                  int h = 127;
                  String integerCacheHighPropValue =
                      sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                  if (integerCacheHighPropValue != null) {
                      try {
                          int i = parseInt(integerCacheHighPropValue);
                          i = Math.max(i, 127);
                          // Maximum array size is Integer.MAX_VALUE
                          h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                      } catch( NumberFormatException nfe) {
                          // If the property cannot be parsed into an int, ignore it.
                      }
                  }
                  high = h;
      
                  cache = new Integer[(high - low) + 1];
                  int j = low;
                  for(int k = 0; k < cache.length; k++)
                      cache[k] = new Integer(j++);
      
                  // range [-128, 127] must be interned (JLS7 5.1.7)
                  assert IntegerCache.high >= 127;
              }
      
              private IntegerCache() {}
          }

    代码挺长,大概说的就是在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。所以上面代码中ab相等,cd不相等。

  • 在看下面的代码会输出什么

    public class Main {
        public static void main(String[] args) {
    
                Double a = 1.0;
                Double b = 1.0;
                Double c = 2.0;
                Double d = 2.0;
    
                System.out.println(a==b);
                System.out.println(c==d);
    
        }
    }
    
    flase
    flase

    采用同样的方法,可以看到DoublevalueOf方法,每次返回都是重新new 一个新的对象,所以上面代码中的结果都不想等。

    public static Double valueOf(double d) {
              return new Double(d);
    }
  • 最后再看这段代码的输出结果

    public class Main {
        public static void main(String[] args) {
    
            Boolean a = false;
            Boolean b = false;
            Boolean c = true;
            Boolean d = true;
    
            System.out.println(a==b);
            System.out.println(c==d);
        }
    }
    true
    true

    老方法继续看valueOf方法

    public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }

    再看看TRUEFALSE是个什么东西,是两个静态成员属性。

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);

说下结论 IntegerShortByteCharacterLong这几个类的valueOf方法的实现是类似的。DoubleFloatvalueOf方法的实现是类似的。然后是BooleanvalueOf方法是单独一组的。

  • Integer i = new Integer(xxx)Integer i =xxx的区别

    这两者的区别主要是第一种会触发自动装箱,第二者不会

    最后看看下面这段程序的输出结果

    public class Main {
        public static void main(String[] args) {
            Integer a = 1;
            Integer b = 2;
            Integer c = 3;
            Long g = 3L;
            int int1 = 12;
            int int2 = 12;
            Integer integer1 = new Integer(12);
            Integer integer2 = new Integer(12);
            Integer integer3 = new Integer(1);
    
            System.out.println("c==(a+b) ->"+ (c==(a+b)));
            System.out.println("g==(a+b) ->" + (g==(a+b)));
            System.out.println( "c.equals(a+b) ->" + (c.equals(a+b)));
            System.out.println( "g.equals(a+b) ->" + (g.equals(a+b)));
            System.out.println("int1 == int2 -> " + (int1 == int2));
            System.out.println("int1 == integer1 -> " + (int1 == integer1));
            System.out.println("integer1 == integer2 -> " + (integer1 == integer2));
            System.out.println("integer3 == a1 -> " + (integer3 == a));
        }
    }
    c==(a+b) ->true
    g==(a+b) ->true
    c.equals(a+b) ->true
    g.equals(a+b) ->false
    int1 == int2 -> true
    int1 == integer1 -> true
    integer1 == integer2 -> false
    integer3 == a1 -> false

    下面简单解释这些结果。

    1.当 "=="运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。所以c==a+bg==a+btrue

    2.而对于equals方法会先触发自动拆箱过程,再触发自动装箱过程。也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。所以c.equals(a+b)true。而对于g.equals(a+b)a+b会先拆箱进行相加运算,在装箱进行equals比较,但是装箱后为IntegergLong,所以g.equals(a+b)false

    3.int1 == int2true无需解释,int1 == integer1,在进行比较时,integer1会先进行一个拆箱操作变成int型在进行比较,所以int1 == integer1true

    4.integer1 == integer2 -> falseinteger1integer2都是通过new关键字创建的,可以看成两个对象,所以integer1 == integer2 为falseinteger3 == a1 -> false , integer3是一个对象类型,而a1是一个常量它们存放内存的位置不一样,所以integer3 == a1false,具体原因可学习下java的内存模型。

String(不是基本数据类型)

String的不可变性 ***

在 Java 8 中,String 内部使用 char 数组存储数据。并且被声明为final,因此它不可被继承。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {    
    private final char value[];
}

为什么<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值