1、自动装箱
自动装箱指的是将基本数据类型自动转换为对应的封装类对象。例如,将int
自动转换为Integer。如下代码例子:
Integer i = 10; //装箱
int n = i; //拆箱
- 普通数据类型:直接在栈内存中分配空间,存储的是具体的值。
- 包装类:作为对象在堆内存中分配空间。包装类实际上是对普通数据类型的封装,每个包装类都包含了对应的数据类型的值,并且包含一些方法(如类型转换、比较等)。
2、静态变量有什么作用?
静态变量也就是被 static
关键字修饰的变量。它可以被类的所有实例共享,无论一个类创建了多少个对象,它们都共享同一份静态变量。也就是说,静态变量只会被分配一次内存,即使创建多个对象,这样可以节省内存。
3、GC,Java内存区域
JAVA内存区有方法区、堆、虚拟机栈、本地方法栈、程序计数器。
程序计数器:程序计数器是一块很小的区域,记录当前线程下一条字节码指令地址,每个线程都有一个独立的计数器。如果执行的是本地方法,则计数器为空。
虚拟机栈:虚拟机栈描述的是Java方法执行的线程内存模型,是线程私有,生命周期与线程等同。每个方法执行时,虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、返回地址等信息。
本地方法栈:与虚拟机栈作用类似,区别是执行本地方法,而非Java方法,hotspot将本地方法栈和虚拟机栈合二为一,不同虚拟机实现有所不一样。
堆:堆是所有线程共享的一块区域,在虚拟机启动时创建,存放几乎所有的对象实例和数组。但随着即时编译,尤其是逃逸分析技术,栈上分配、变量替换优化手段已经可以将部分对象存放在栈上。
从内存分配的角度看,Java堆中也划分出多个线程私有的缓冲区(TLAB),以提升对象分配效率。
方法区:方法区存储被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
4、MinorGC、MajorGC、Full GC?
新生代内存不够用时候发生Minor GC 也叫 Yong GC ,老年代内存不够的时候发生 Major GC, Minor GC 相比 Major GC 更频繁,回收速度也更快。 还有一种GC 负责整个新生代 + 老年代的回收称为 Full GC。
G1垃圾收集器是JAVA7引入的一款垃圾收集器,软实时是指G1允许设置一个限定值,G1会努力控制每一次GC所造成的停顿都在限定时间之内,但是并不保证每一次GC造成的停顿都能满足要求。停顿时间的限定可以通过-XX:MaxGCPauseMillis参数设置
CMS是一种更为古老的垃圾回收算法。
无法被垃圾回收的内存,称为内存泄漏
ZGC为更高版本Java使用的垃圾回收器,Java14可使用。
CMS收集器关注低延迟,垃圾收集算法采用并发标记-清除算法。cms作用于老年代。老年代是指多次清楚没清楚到,然后转为老年代。还有个复制算法(Copying):将存活对象从一个区域复制到另一个区域,非存活对象的空间被清除。
cms的过程(初始标记,并发标记,再次标记,并发清除)、
(初始标记和并发标记会stop the world)。
cms优点:并发收集、低延迟。
cms缺点:会产生内存碎片。
G1是JDK 9以后的默认垃圾回收器,
G1是一个并行回收器,它把堆内存分割为很多不相关的区域(Region)(物理上不连续的)。使用不同的Region来表示Eden、幸存者0区,幸存者1区,老年代等。G1 GC有计划地避免在整个Java堆中进行全区域的垃圾收集。他跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。
g1在延时最好上跟不上cms,但是在最差情况下,比cms好得多。
5、Java泛型类是什么?
一般为定义一个T,作为泛型。泛型可以让我们编写更加通用、可重用的代码,减少代码的重复量。通过使用泛型,由于泛型避免了不必要的类型转换,所以在一定程度上可以提高程序的性能。比如定义一个泛型类,在创建integer和string的时候,都可以使用这个泛型类的泛型变量。
然后两者用相同名字的泛型变量,但是表达的是不同的变量内容,这样不用定义两个类。
// 定义一个泛型类
public class Box<T> {
// 泛型类可以在实例化时指定具体的数据类型
private T t;
public Box(T t) {
this.t = t;
}
public void setData(T t) {
this.t = t;
}
public T getData() {
return t;
}
// 泛型方法,可以在任意方法上使用泛型
public <U> Box<U> convert(U u) {
return new Box<>(u);
}
}
// 使用泛型类
public class Main {
public static void main(String[] args) {
// 创建一个Integer类型的Box实例
Box<Integer> integerBox = new Box<>(10);
System.out.println("The data is: " + integerBox.getData());
// 创建一个String类型的Box实例
Box<String> stringBox = new Box<>("Hello World");
System.out.println("The data is: " + stringBox.getData());
// 使用泛型方法
Box<Double> doubleBox = stringBox.convert(123.456);
System.out.println("The data is: " + doubleBox.getData());
}
}
6、hashtable和hashmap的区别详解
hashtable是线程安全的,hashmap是线程不安全的。hashtable的性能较低,hashmap的性能较高。因为 Hashtable
内部的方法基本都经过synchronized
修饰。Hashtable的底层实现就是数组+链表,而没有红黑树,因此各种操作都要简单很多。HashMap的底层数据结构改成了数组+链表+红黑树的实现,在链表的节点大于TREEIFY_THRESHOLD=8时,链表转为红黑树。可以