Contents

常见面试题-1

Java SE 与 Java EE

  • Java SE是Java的基础版本,适合开发桌面引用程序和简单的服务的程序,Java EE是Java的高级版本,适合开发复杂的服务的程序和Web程序

JVM VS JDK VS JRE

  • JDK包含JRE,JRE包含JVM
  • JVM是Java虚拟机,用来执行Java字节码。虚拟机不是固定的,而是一个规范,只要符合要求,不同的公司具有不同的虚拟机。不同的代码文件都需要通过对应的编译器编译成.class的字节码文件再交给虚拟机运行,例如Java的编译器就是javac
  • JDK是Java开发软件包,用于创建和编辑Java程序。
  • JRE用来运行已经编译好的Java程序,主要包含JVM和基础类库,基础类提供常用的操作,包含I/O,网络通信等。
  • 简单的说就是JRE只包含运行Java程序的环境和类库,而JDK不仅仅包含JRE还包含编译调试Java程序的工具。

什么是字节码

  • 字节码就是虚拟机可以理解的代码
  • 在Java中代码需要经过编译器编译成 .class 字节码文件,再交给JVM虚拟机,经过解释器一行一行的解释成机器可以理解的代码
  • 由于一行一行解释效率很慢,就引入了JIT编译器,JIT是运行时编译,并且编译一次后就将对应字节码的机器码存下来下次直接使用,一般热点代码会使用JIT编译。
  • Java语言是解释和编译并存的语言就是因为Java代码需要先由javac编译成.class字节码文件再通过解释器或则JIT编译器转化为机器可以理解的代码执行。

Java和C++的区别

  • Java不提供指针访问内存
  • Java不允许多继承,但是接口可以多实现。C++可以多继承
  • Java由有垃圾回收机制,无需手动释放不需要的内存
  • C++同时支持方法和操作符重载,Java只支持方法重载

标识符和关键之

  • 标识符是用户定义的一组符号,例如变量名、方法名,关键字是Java中定义好的有特殊含义的标识符。

移位运算符

  • 将二进制表示的数左移或则右移n位。
  • 左移高位丢弃,低位补零。
  • 无符号右移高位补零, 低位丢弃。
  • 带符号右移高位补符号位置,低位丢弃。
  • float和double不支持移位运算,并且实际上只有int和long支持移位运算,因为其他类型的例如short、byte最终都会提升为int和long进行运算
  • 移位运算超出上限会先将要移动的位置mod上上限再进行运算,例如int类型移动42位就是移动42mod32,移动10位。long类型的mod数就是64。

基本类型和包装类型的区别

  • 基本类型占用内存比包装类型小
  • 基本类型不同类型有各自的默认值,包装类型的默认值都是null
  • 基本类型的局部变量存在栈中的局部变量表,成员变量存储在堆中。而包装类型都是对象,全部存储在堆中。
  • 基本类型 == 比较的是值,包装类型 == 比较的是对象的地址,因此包装类型值的比较用equals

包装类型的缓存机制

  • 包装类型Integer、Long、Shart都初缓存了[-128,127]的范围,创建包装类型时在这个范围内则直接使用。因此创建两个包装类型值都为10,== 实际是相同的。
  • Float和Double无缓存,因此创建两个相同值的对象==比较是flase
  • 直接创建一个Integer a1 = 11和Integer a2 = new Ingeter(11),实际上是两个不同的对象,因为第一个自动装箱使用的是缓存的对象,第二个实际上创建了一个新的对象

自动装箱与自动拆箱

  • 自动装箱就是创建基本类型时调用对应包装类的valueOf()方法
  • 自动拆箱就是创建包装类型时自动调用对应的xxxValue()方法
  • 当返回值的类型是包装类(基本类型)时,创建了一个基本类型(包装类型)的局部变量进行返回时,就会触发自动装箱(拆箱),由于频繁的自动装箱和拆箱也会影响性能,所以要避免。

成员变量和局部变量的区别

  • 成员变量属于类的,可以被private、public、static修饰,局部变量是属于方法的,不可以被上述的修饰符进行修饰,但是二者都可以被final进行修饰。
  • 成员变量存储在堆中,局部变量存储在栈帧中
  • 成员变量的存活时间长,随着对象的创建而创建,随着垃圾回收而销毁。局部变量的存活时间短,随着方法的创建而创建,随着方法的结束而销毁。
  • 成员变量有默认值,因为,成员变量随着对象创建,而他的值可能在后续的setter方法中进行赋值,也可能不赋值,是不可预测的,为了出现未初始化而被使用的错误情况,所有的成员变量都有一个默认值。局部变量是没有默认值的,因为他一定要赋值才能使用。

方法的返回值和类型

  • 简单来说,无参无返回值、有参无返回值、有参有返回值、无参有返回值

静态方法为什么不能调用非静态成员

  • 静态方法是是static修饰的方法,在类加载时就创建了,而非静态成员是只有实例被创建时才会创建,因此如果允许静态方法可以调用非静态成员就会出现非法操作。

静态方法和成员法的区别

  • 静态方法可以通过类名.方法名或则对象名.方法名的方式使用,而成员方法只能通过对象名.方法名的方式使用

重写与重载

  • 重载是发生在一个类中的,指一个方法只需要方法名相同即可,参数名、参数数量、返回值、修饰符都可以不相同
  • 重写是指子类对父类允许的重写的方法进行逻辑的重写。方法的重写需要遵循两同两小一大,即方法名和参数需要相同;返回类型必须小于或等于父类,抛出的异常必须小于或等于父类;修饰符需要大于等于父类

什么是可变参数

  • 用修饰符 …变量名的方式定义,允许调用时传入多个参数
  • 可变参数只能作为最后一个参数,前面可以有其他的参数