重学jvm
Java的类存在哪里?
误区:常规认为基本数据类型存放在栈中,引用类型存放在堆中
1 | Class Text{ |
这里面的a是存在堆里面的。
而方法:
public void text(){
int b = 1;
}
在text局部方法中基本数据类型的变量b是存储在栈中的
如果你将一个实例变量放在栈内,那么就不存在多个线程访问同一个对象资源了,这显然是不对的,所以实例变量要在堆上创建,但是对于局部变量,是在栈上创建的,调用一次方法创建一个帧,独享一份内存区域,其他的线程是不会访问到该线程的资源,在栈上创建也会减轻GC的压力,随着该方法的结束,帧出栈,相对应的内存消除,这种局部变量占用的内存自然就消失了。
java中静态方法的作用是什么?
- 声明为static的变量实质上是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。
- 只会分配一块存储空间,所有此类的对象都可以操控此块存储空间。
- 没有创建对象时也可以利用类使用该方法。静态方法可以调用静态方法、静态成员,但不能调用成员方法。
java静态变量存放在堆还是方法区?
- 静态变量是被对象共享的,随着类加载而产生(不用实例化即可访问)
- java8之前存放在方法区
- java8及以后:存放在堆中反射的class对象的尾部
java栈空间包括哪些内容?
由一个个栈帧组成
-
局部变量表:主要存放编译器可知的各种数据类型、对象引用(可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)
-
操作数栈:主要是存放方法运行过程中产生的中间变量。
-
动态链接:主要服务一个方法需要调用其他方法的场景。
-
返回地址。
final、finally、finalize的区别?
- 修饰变量:
修饰基本数据类型:这个数据的值在初始化后将不能被改变。
修饰引用数据类型:引用在初始化后将永远指向一个内存地址,不可修改。里面的值是可以修改的
-
final修饰的常量在编译阶段会被放入常量池中。
-
final类:被修饰的类不能被继承,所有方法不能被重写。
try-catch-finally
finally里面的语句是否一定会被执行?
如果在try或catch中停止了jvm,则finally不会执行,例如停电。或者使用System.exit(0)可以阻断finally执行。
finally中的代码会执行,流程为:
-
先计算返回值,并将返回值存储起来,等待返回
-
执行finally代码块
-
将存储的返回值,返回出去
注:返回值是在finally运算之前就确定了,并且缓存(副本)了,不管finally对该值做任何的改变,返回的值都不会改变(不在finally中return)
finalize是在java.lang.Object里定义的方法,也就是说每一个对象都有这么一个方法,这个方法在gc启动,该对象被回收的时候被调用。
一个对象的 finalize 方法只会被调用一次,finalize 被调用不一定会立即回收该对象,所以有可能调用finalize 后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会再次调用 finalize了,进而产生问题,因此不推荐使用 finalize 方法。
java静态变量、代码块、和静态方法的执行顺序是什么?
-
静态代码块->构造代码块->构造函数->普通代码块(构造代码块是每次执行构造函数之前执行)
-
父类->子类
java多态:
编译时多态:重载,编译时多态在编译时就已经确定,运行的时候调用的是确定的方法
运行时多态:继承、重写和向上转型
继承:在多态中必须存在有继承关系的子类和父类
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能调用父类的方法,又能调用子类的方法。