从内存角度理解static与final关键字

jvm内存整体架构

jvm存储结构.png
  1. 栈内存:每一个线程都会产生一个栈内存,每次遇到方法都会进栈,方法里面的所有局部变量,产生的运算的中间数据,对象的引用都存在栈中。
  2. 堆内存:堆内存是所有线程共享的一块内存,里面存储对象。
  3. 方法区:存放类的基本信息(全限定类名,是类还是接口等)、已装载类的详细信息(类中全局变量字段的信息,类中的方法名,参数,类型等)
  4. 运行时常量池:在1.7版本之前,运行时常量池是在方法区中的,在1.7及以后的版本中,将运行时常量池移到了堆中,运行时常量池中,每个类型对应一个常量池,例如字符串常量池,基本数据类型的常量池,它们存储运行时所有用到的常量,例如文字字符串,final定义的变量。
  5. 静态区:方法区中一个模块,用于存放静态变量和静态代码块,也就是static定义的变量都存在这里,类的所有的实例都共享,在类的加载过程中,就已经静态的方法、变量、代码块执行了,执行时到new出来的对象、常量等引用都存在静态区中。
常量池.png

字面量属于运行时常量池,而符号引用属于静态常量池。

存储位置

成员变量:

  1. private int a = 1;常量池
  2. prviate static a = 1;常量池
  3. private final int a = 1;常量池
  4. prviate A a = new A();堆
  5. private static A a = new A();堆,静态区存引用
  6. private final A a = new A();堆,方法区存引用

final关键字修饰成员变量不会改变存储的位置,static修饰成员变量时,会将其引用存放在静态区中。特别注意一点String s = "abc",和String s = new String("abc"),前者是存放在常量池中,后者存放在堆中。

局部变量

  1. private int a = 1;栈
  2. private final int a = 1;常量池
  3. prviate A a = new A();堆,栈中存引用
  4. prviate final A a = new A();堆,方法区中存引用

static关键字不能修饰局部变量,局部变量中的常量都存在栈中,方法结束后立即被销毁。final无论修饰成员变量还是局部变量,最终的引用都存在方法区中。

总结

  1. 静态变量:static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
  2. 静态方法:static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
  3. 被 final 修饰的实例变量必须显式指定初始值。final 修饰符通常和 static 修饰符一起使用来创建类常量。
  4. 父类中的 final 方法可以被子类继承,但是不能被子类重写。声明 final 方法的主要目的是防止该方法的内容被修改。
  5. final 类不能被继承,没有类能够继承 final 类的任何特性。
  6. static方法一般用于工具类。
  7. static静态代码块用于初始化成员变量的配置,保证所有的类都用同一套配置,如果有特异化的需求,则不能用静态代码块来做初始化,考虑用有参构造函数。

你可能感兴趣的:(从内存角度理解static与final关键字)