java代码块 静态、非静态

Java虚拟机的内存分区:Java栈、堆、方法区、本地方法栈、PC寄存器。还有一个常量池的概念,虚拟机会为每种类型分配一个常量池,而不是实例。

例如有一个类有很多子类,那么在父类定义的final变量,在子类是不能被改变的。可以说明是在类型上分配的。

被static修饰的变量或者方法是属于类本身,而不属于类的实例。在类被加载进虚拟机的时候就已经初始化了,他存在与方法区,方法区和堆区的时候是共享的,因此他被设计为线程安全的。假设同时有两个线程都企图访问一个名为A的类,而这个类还没有被转入虚拟机,此时只应该有一个线程去装载它,而另一个线程只能等着。所以为什么我们可以说static定义的变量是共享数据。

我们举两个例子看下他们的不同。

public interface Angry {
    String greeting = "Girl!!!";

    int angryLevel = Dog.getAngryLevel();
}
public class Dog {

    static final String greeting = "Woof,woof";

    public Dog() {
        System.out.println("DOg");
    }

    static{

        System.out.println("Dog is in");
    }

    static int getAngryLevel(){
        System.out.println("Angry is in");
        return 1;
    }
}
public class Example1 {

    public static void main(String[] args) {
        System.out.println(Angry.greeting);
        System.out.println(Dog.greeting);
        //new Dog();

    }
    static {
        System.out.println("Exampl1");
    }
}

这个的输出结果是:

Exampl1
Girl!!!
Woof,woof

把new Dog();注释的代码打开,在看看结果。

Exampl1
Girl!!!
Woof,woof
Dog is in
DOg

再来看看下面的代码:

public class A{
    static int a = 10;

    static{
        System.out.println("初始化A");
    }
}
public class B extends A{
    static int b = 5;

    static{
        System.out.println("初始化B");
    }
}
public class Example2{

    public static void main(String[] args){

        int c = B.b;
        System.out.println(c);
    }

    static{
        System.out.println("初始化Example2");
    }
}

他的输出结果是:

初始化Example1

初始化A

5

开始我一直以为调用到了这个类的方法或者变量的时候,就会执行静态代码块或者是非静态代码块。看了《深入java虚拟机》之后明白了很多。

总结下:

第一个例子:3个类都没有继承关系。接口定义的变量默认是public static final的,方法默认是public abstract。

main方法是程序的入口,虚拟机会初始化该线程所在的类,那么他会先执行静态代码块的内容,然后程序再从上往下执行,执行Angry.greeting,打印他的值,执行Dog.greeting,打印他的值。Angry和Dog都没有实例化。所以不会调用静态代码块的方法。

new 一个Dog对象,此时程序主动实例化一个对象,那么他会调用Dog的静态代码块、非静态代码块、无参构造函数。

第二个例子:B类继承了A类。在Example2中也没有主动的创建B类对象,但是程序调用了B类的静态变量,而B类又继承了A类,虚拟机会先加载并实例化A类(B的父类),所以会执行A类的静态代码块、非静态代码块、无参构造函数。

但是他却没有执行B类的静态代码块,因为程序没有主动的实例化B类对象。

有六种情形属于主动使用初始化。

1、当创建某个类的新实例时(new、克隆、反序列化、反射)

2、调用静态方法。

3、使用到某个类或接口的静态字段,或者对该字段赋值,用final修饰的静态字段除外,他被初始化为一个编译时的常量表达式。

4、当初始化某个类的子类时。

5、使用某个类的Class中的反射方法时。

6、启动有main方法的类。

时间: 2024-10-26 07:13:15

java代码块 静态、非静态的相关文章

java 成员变量、局部变量、静态变量、类变量、非静态变量、实例变量、向前引用、非法向前引用、静态代码块、非静态代码块

①java类的成员变量有俩种: 一种是被static关键字修饰的变量,叫类变量或者静态变量 另一种没有static修饰,为成员变量 ②通俗点说: 类的静态变量在内存中只有一个,java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享.静态变量可以直接通过类名进行访问,其生命周期取决于类的生命周期. 而实例变量取决于类的实例.每创建一个实例,java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中,其生命周期取决于实例的生命周期. 注意点: 1.JAVA中初始化

java中静态代码块,非静态代码块,构造函数执行顺序

关于静态代码块 静态代码块的写法: static { System.out.println("我是静态代码块"); } 静态代码块的特点: 1.执行优先级高于非静态的初始化块,它会在类初始化的时候执行一次,执行完成便销毁,它仅能初始化类变量,即static修饰的数据成员. 2.随着类的加载而执行,而且只执行一次 先说一下类加载,一个程序要想运行,首先要把代码加载到内存中,然后才能去和CPU交流,这是冯诺依曼计算机规定的.Java也是一样,Java的.class字节码文件要想执行,首先也

Java静态代码块和非静态代码块、类加载、构造对象的机制

温故而知新,代码块这东西时间一长一些东西容易忘记,比如静态代码块.非静态代码款.静态成员变量初始化.动态成员变量初始化.构造方法调用.类加载等等的顺序机制是怎么样的? 话不多说了,一个例子足以说明一切: package com.collectiontest; import org.junit.Test; public class BasicTest { @Test public void testBlock() { System.out.println("m1:"); Mimi m1=

静态代码块、非静态代码块(普通代码块)和构造方法的执行顺序

Java中经常有一些静态块,这是用来在生成类之前进行的初始化,无论java还C++语言中的static,都是最先初始化好的.结构如下: static { 静态语句代码块 } { 非静态语句代码块 }  相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,一般在代码块中对一些static变量进行赋值. 不同点:静态代码块在非静态代码块之前执行(静态代码块-->非静态代码块-->构造函数). 1 public class Test_Static_Class { 2 //静态

静态代码块、非静态代码块、构造方法的执行顺序

java中经常有一些静态块,这是用来在生成类之前进行的初始化,无论java还C++语言中的static,都是最先初始化好的.结构如下: static { 静态语句代码块 } { 非静态语句代码块 } 异同点 相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,一般在代码块中对一些static变量进行赋     值. 不同点:静态代码块在非静态代码块之前执行(静态代码块-->非静态代码块-->构造方法).     静态代码块只在第一次new执行一次,之后不在执行,而非静态

静态代码块--》非静态代码块--》构造方法

class ccc1 { static { System.out.println("ccc1---1"); } public ccc1() { System.out.println("ccc1---2"); } { System.out.println("ccc1---3"); } }   public class ccc extends ccc1 {   static { System.out.println("ccc1")

static{}(静态代码块)与{}(非静态代码块)的异同点(转自 べ袽猓柯苡づ)

static{}(静态代码块)与{}(非静态代码块)的异同点 相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个, 一般在代码块中对一些static变量进行赋值. 不同点:静态代码块在非静态代码块之前执行(静态代码块->非静态代码块->构造方法). 静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new 一次就执行一次.非静态代码块可在普通方法中定义(不过作用不大):而静态代码块不行. 例: //普通类 publicclass PuTong {   

静态代码块、非静态代码块、构造函数之间的执行顺序

1.执行顺序 静态代码块>非静态代码块>构造函数 public class staticCode { public staticCode() { System.err.println("构造函数"); } { System.err.println("非静态代码块"); } static{ System.err.println("静态代码块"); } public static void main(String[] args) { ne

静态代码块、非静态代码块、构造函数的输出顺序

情况一:没有继承父类时 1 class HelloA { 2 3 public HelloA() { 4 System.out.println("I'm A class"); 5 } 6 7 static { 8 System.out.println("static A"); 9 } 10 11 { 12 System.out.println("A"); 13 } 14 15 public static void main(String[] ar

Java子父类间静态代码块、非静态代码块、构造方法的执行顺序

子类A继承父类B,A a=new A(); 正确的执行顺序是:父类B静态代码块->子类A静态代码块->父类B非静态代码块->父类B构造函数->子类A非静态代码块->子类A构造函数 也就是说非静态初始化块的执行顺序要在构造函数之前. class FatherStaticTest { static { System.out.println("执行父类的静态代码块."); } FatherStaticTest() { System.out.println(&qu