重学jvm

重学jvm

Java的类存在哪里?

误区:常规认为基本数据类型存放在栈中,引用类型存放在堆中

1
2
3
Class Text{
int a = 1;
}

这里面的a是存在堆里面的。

而方法:
public void text(){
int b = 1;
}

在text局部方法中基本数据类型的变量b是存储在栈中的

如果你将一个实例变量放在栈内,那么就不存在多个线程访问同一个对象资源了,这显然是不对的,所以实例变量要在堆上创建,但是对于局部变量,是在栈上创建的,调用一次方法创建一个帧,独享一份内存区域,其他的线程是不会访问到该线程的资源,在栈上创建也会减轻GC的压力,随着该方法的结束,帧出栈,相对应的内存消除,这种局部变量占用的内存自然就消失了。


java中静态方法的作用是什么?

  1. 声明为static的变量实质上是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。
  2. 只会分配一块存储空间,所有此类的对象都可以操控此块存储空间。
  3. 没有创建对象时也可以利用类使用该方法。静态方法可以调用静态方法、静态成员,但不能调用成员方法。

java静态变量存放在堆还是方法区?

  1. 静态变量是被对象共享的,随着类加载而产生(不用实例化即可访问)
  2. java8之前存放在方法区
  3. java8及以后:存放在堆中反射的class对象的尾部

java栈空间包括哪些内容?

由一个个栈帧组成

  1. 局部变量表:主要存放编译器可知的各种数据类型、对象引用(可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)

  2. 操作数栈:主要是存放方法运行过程中产生的中间变量。

  3. 动态链接:主要服务一个方法需要调用其他方法的场景。

  4. 返回地址。


final、finally、finalize的区别?

  1. 修饰变量:

修饰基本数据类型:这个数据的值在初始化后将不能被改变。

修饰引用数据类型:引用在初始化后将永远指向一个内存地址,不可修改。里面的值是可以修改的

  1. final修饰的常量在编译阶段会被放入常量池中。

  2. final类:被修饰的类不能被继承,所有方法不能被重写。

try-catch-finally

finally里面的语句是否一定会被执行?

如果在try或catch中停止了jvm,则finally不会执行,例如停电。或者使用System.exit(0)可以阻断finally执行。

finally中的代码会执行,流程为:

  1. 先计算返回值,并将返回值存储起来,等待返回

  2. 执行finally代码块

  3. 将存储的返回值,返回出去

注:返回值是在finally运算之前就确定了,并且缓存(副本)了,不管finally对该值做任何的改变,返回的值都不会改变(不在finally中return)

finalize是在java.lang.Object里定义的方法,也就是说每一个对象都有这么一个方法,这个方法在gc启动,该对象被回收的时候被调用。

一个对象的 finalize 方法只会被调用一次,finalize 被调用不一定会立即回收该对象,所以有可能调用finalize 后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会再次调用 finalize了,进而产生问题,因此不推荐使用 finalize 方法。


java静态变量、代码块、和静态方法的执行顺序是什么?

  1. 静态代码块->构造代码块->构造函数->普通代码块(构造代码块是每次执行构造函数之前执行)

  2. 父类->子类


java多态:

编译时多态:重载,编译时多态在编译时就已经确定,运行的时候调用的是确定的方法

运行时多态:继承、重写和向上转型

继承:在多态中必须存在有继承关系的子类和父类

重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能调用父类的方法,又能调用子类的方法。