Java基础面试(String,泛型,关键字等)

Java基础

基本类型和包装类型

byte/8
char/16
short/16
int/32
float/32
long/64
double/64
boolean/~
boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的。

包装类与基本类型的不同

  • 包装类型可以为 null,而基本类型不可以,尤其运用在pojo中
  • 包装类型可用于泛型,而基本类型不可以
  • 基本类型比包装类型更高效
    基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用
    Java基础面试(String,泛型,关键字等)

缓存池

new Integer(123) 与 Integer.valueOf(123) 的区别在于:

new Integer(123) 每次都会新建一个对象;
Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。

在创建Integer对象,尽量少用new创建,尽量使用valueOf,利用整型池的提高系统性能,通过包装类的valueOf生成包装实例可以提高空间和时间性能。

基本类型对应的缓冲池如下:
boolean values true and false
all byte values
short values between -128 and 127
int values between -128 and 127
char in the range \u0000 to \u007F

泛型

泛型的本质是为了参数化类型。在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

泛型擦除

泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如List在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。

  • List<? extends T>和List <? super T>之间有什么区别 ?
    这两个List的声明都是限定通配符的例子,List<? extends T>可以接受任何继承自T的类型的List,而List<? super T>可以接受任何T的父类构成的List。例如List<? extends Number>可以接受List或List。

String

String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)

不可变的好处

  1. 可以缓存 hash 值
    因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。

  2. String Pool(线程池)
    如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。

  3. 安全性
    String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 的那一方以为现在连接的是其它主机,而实际情况却不一定是。

  4. 线程安全
    String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

JVM创建String的2中方法

  1. 直接赋值:String str = “apple”
    先去字符串常量池中检查是否有此值,如果有就把引用地址直接指向此值,若没有就再常量池中创建,然后在把引用指向此值。
  2. String str = new String();
    一定会现在对上创建一个字符串对象,然后再去常量池中查询,如果不存在会先在常量池中创建此字符串,然后在把引用的值指向此字符串

subString方法

左闭右开的复制String
在1.6前产生OOM问题,因为是先复制String后拷贝;
1.7之后直接从原来的String拷贝

equals和compareTo

  1. equals会先判断是否是String类型,如果不是直接false;若是,则会循环比较所有字符,相同返回true
  2. compareTo,会循环比较所有的字符,如果有不相同,则返回char1-char2;所以返回0时,表示字符串相同

关键字

final

数据(不可改变);
方法(不能被子类重写);
类(不能被继承);

static

  1. 静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
  2. 静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
  3. 静态语句块在类初始化时运行一次。

存在继承的情况下,初始化顺序为:

父类(静态变量、静态语句块)
子类(静态变量、静态语句块)
父类(实例变量、普通语句块)
父类(构造函数)
子类(实例变量、普通语句块)
子类(构造函数)

接口和抽象类

  1. 从设计层面上看,抽象类提供了一种 IS-A 关系,需要满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
  2. 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
  3. 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
  4. 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。

文章主要参考来自于github上的cs_notes,通过我面试考到的知识点,做了一个常考题目的汇总。
github连接