目录
摘要:所有静态的 属性也好,方法也好,代码块也好都存放在共享区,
类中可以创建多个对象,每创建一个对象都需要在 堆 中开辟一块新的空间, 供新对象使用
如果创建的多个对象有一个共同属性 我们就可以用 " static "
static 属性 : 加上static后,这个共同的属性就在方法区(共享区) 开辟一块空间, 可供所有对象使用
static 修饰 属性: 特征! 多个对象有相同的属性
static修饰属性的特点:
static修饰的属性叫做 静态属性 或 类的属性
(扩展:没用static修饰的属性,叫 非静态属性 也叫实例属性 必须使用对象名调用,对象的成员相关的都叫实例,属性叫实例属性,方法叫实例方法)
█ 与类同生死: 类存在, static修饰的 成员 就在
(类中的属性 , 只有创建对象的时候 . 属性才会在内存存在 . 而 static修饰的属性 只要 类 在, 属性就在内存中存在)
█ static 修饰的成员, 用类名 ●调用 类名 . 属性 (类名 点 属性) 【因为存在与共享区,所以对象也可以调用】
static 修饰 方法:
static修饰的方法 叫做 静态方法 或 类的方法
(扩展: 没static修饰的方法 叫 非静态方法 也叫 实例方法 )
█ 静态方法中,只能访问静态成员,不能访问非静态成员 , 否则报编译错误(无法从静态上下文访问非静态的 XXX)
█ static修饰的属性在方法区也就是共享区中,static修饰的方法,用就进栈,不用不进栈
static 修饰 代码块: static{ }
█ static修饰的代码块主要作用是完成静态属性的初始值
█ static代码块在类加载时就被执行,并且只被执行一次
以 下 为 引 申 阅 读
================== 以下为转载 ==================
static代码块只被执行一次
原因在最后,这是其中的一个小例子。
如:
SessionFactory负责保存和使用所有配置信息,消耗内存资源非常大
所以一个web项目要保证只创建一个SessionFactory
那么在使用hibernate创建一个工具类(HibernateUtils),用于获取Session对象时需要将其放在static代码块中,
又因下边的每个方法需要使用SessionFactory对象sf,所以将其单独拆出放在方法外。
static代码块只执行一次原因:
static代码块只在类加载时执行,类是用类加载器来读取的,类加载器是带有一个缓存区的,
它会把读取到的类缓存起来,所以在一次虚拟机运行期间,一个类只会被加载一次,这样的话
静态代码块只会运行一次
static代码块只执行一次原因:
static代码块只在类加载时执行,类是用类加载器来读取的,类加载器是带有一个缓存区的,
它会把读取到的类缓存起来,所以在一次虚拟机运行期间,一个类只会被加载一次,这样的话
静态代码块只会运行一次
================== 以下为转载 ==================
静态代码块的运行解析
首先要给大家区分一个观点,加载与类加载是两个截然不同的过程。Java的“类加载”是一个类从被加载到虚拟机内存中开始,到卸载出虚拟机内存为止的整个生命周期中的一个过程,包括加载,验证,准备,解析,初始化五个阶段。而“加载”指的是类加载的第一个阶段,加载阶段,虚拟机需要完成以下3件事情:
1.通过一个类的全限定名来获取定义此类的二进制字节流
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据结构的访问入口。
类中的静态块会在整个类加载过程中的初始化阶段执行,而不是在类加载过程中的加载阶段执行。初始化阶段是类加载过程中的最后一个阶段,该阶段就是执行类构造器<clinit>方法的过程,<clinit>方法由编译器自动收集类中所有类变量(静态变量)的赋值动作和静态语句块中的语句合并生成,一个类一旦进入初始化阶段,必然会执行静态语句块。所以说,静态块一定会在类加载过程中被执行,但不会在加载阶段被执行。网上关于Java中静态代码块执行时机的争论,大多是由于概念不清晰导致的。
================== 以下为转载略改动 ==================
代码块面试题
根据程序写输出结果,考察执行顺序
class Student {
static {
System.out.println("Student 静态代码块");
}
{
System.out.println("Student 构造代码块");
}
public Student() {
System.out.println("Student 构造方法");
}
}
class StudentTest {
static {
System.out.println("StudentTest静态代码块");
}
public static void main(String[] args) {
System.out.println("我是main方法");
Student s1 = new Student();
Student s2 = new Student();
}
}
测试结果:
StudentTest静态代码块
我是main方法
Student 静态代码块
Student 构造代码块
Student 构造方法
Student 构造代码块
Student 构造方法
分析:
所有程序 都是 先走 葫芦娃爷爷! mian方法
main方法是Java程序的入口,JVM先找main方法,先把有main方法的类加载到内存中,此时StudentTest 大娃金刚娃 类的静态代码块 直接随着类的加载而先执行;
随后main方法开始执行,当Student类被实例化后,二娃水娃 Student类的静态代码块先执行,并且只执行一次放入缓冲区,不管实例化多少对象;
之后,每实例化一次Student类,类中的 三娃土娃构造代码块比 四娃火娃 构造方法就会先执行,并且每实例化一次就执行一次。
类的初始化执行顺序总结
- 当程序执行时,如果需要创建某个类的对象,那么Java会
先检查是否加载
了这个类,如果没有加载,则先执行类的加载再生成对象。如果已经加载,则直接生成对象。 - 类的执行顺序过程:
- 首先类先加载到方法区内存中,类的静态域会先被加载并且初始化并且优先于main方法执行。Java中类的加载时按需加载,需要时才加载,并且只加载一次。
- 静态成员变量和静态代码块的执行顺序同代码中的顺序一致。
- 每创建一次对象时,先初始化对象中的成员变量,再执行构造代码块,其次再执行构造方法。
- 类中的变量会在任何方法(包括构造器)调用之前得到初始化,即使变量散布于方法定义之间。
- 首先类先加载到方法区内存中,类的静态域会先被加载并且初始化并且优先于main方法执行。Java中类的加载时按需加载,需要时才加载,并且只加载一次。
Java内存区域分配细节图
- 此分配图基于Java8之前版本