zoukankan      html  css  js  c++  java
  • 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方法的类。

  • 相关阅读:
    XCode Playground Overview
    Swift开发学习(二):Playground
    swift网址
    swift关于is和as的解释
    Swift之 ? 和 !
    Swift 学习之二十一:?和 !(详解)
    Swift学习三
    Makefile project
    20171110面试笔记 服务器端程序员+C/C++开发
    关键字
  • 原文地址:https://www.cnblogs.com/hjy9420/p/4273073.html
Copyright © 2011-2022 走看看