Java基础面试(String,泛型,关键字等)
Java基础
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中
- 包装类型可用于泛型,而基本类型不可以
- 基本类型比包装类型更高效
基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用
缓存池
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 等包装类也不能被继承)
不可变的好处
-
可以缓存 hash 值
因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。 -
String Pool(线程池)
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。 -
安全性
String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 的那一方以为现在连接的是其它主机,而实际情况却不一定是。 -
线程安全
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
JVM创建String的2中方法
- 直接赋值:String str = “apple”
先去字符串常量池中检查是否有此值,如果有就把引用地址直接指向此值,若没有就再常量池中创建,然后在把引用指向此值。 - String str = new String();
一定会现在对上创建一个字符串对象,然后再去常量池中查询,如果不存在会先在常量池中创建此字符串,然后在把引用的值指向此字符串
subString方法
左闭右开的复制String
在1.6前产生OOM问题,因为是先复制String后拷贝;
1.7之后直接从原来的String拷贝
equals和compareTo
- equals会先判断是否是String类型,如果不是直接false;若是,则会循环比较所有字符,相同返回true
- compareTo,会循环比较所有的字符,如果有不相同,则返回char1-char2;所以返回0时,表示字符串相同
关键字
final
数据(不可改变);
方法(不能被子类重写);
类(不能被继承);
static
- 静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
- 静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
- 静态语句块在类初始化时运行一次。
存在继承的情况下,初始化顺序为:
父类(静态变量、静态语句块)
子类(静态变量、静态语句块)
父类(实例变量、普通语句块)
父类(构造函数)
子类(实例变量、普通语句块)
子类(构造函数)
接口和抽象类
- 从设计层面上看,抽象类提供了一种 IS-A 关系,需要满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
- 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
- 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
- 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。
文章主要参考来自于github上的cs_notes,通过我面试考到的知识点,做了一个常考题目的汇总。
github连接