本文结构:

1.先看几道题

2.类的加载于初始化

(1)类的加载

(2)类的初始化

(a)会发生类的初始化的情况

(b)不会发生类的初始化的情况

首先看几道题。

解析可在看完讲解后再看

Demo1
public class Demo1 {

    public static void main(String args[]) {

        Dog woofer = new Dog();
Dog nipper = new Basenji();
woofer.bark();
nipper.bark();
}
} class Dog {
public Dog() {
} public static void bark() {
System.out.print("woof ");
}
} class Basenji extends Dog { public Basenji() {
super();
} public static void bark() {
}
} //输出两个woof //原因,第二个woof,子类没有覆盖掉父类的方法(静态变量不可被覆盖),构不成多态,故编译看左边,
//父类引用还是调用的父类方法,即使是new 的子类。
Demo2
public class Demo2 {
public static void main(String[] args) {
Father father;
father=new Son(1000);
int i=father.getI();
System.out.println(i); }
} class Father {
int i = 10; public Father() {
System.out.println(getI());
System.out.println("父类构造方法");
} public int getI() {
System.out.println("父类get方法");
return i;
}
} class Son extends Father {
int i = 100; public Son(int i) {
super();
System.out.println("子类构造方法");
this.i = i;
} @Override
public int getI() {
System.out.println("子类get方法");
return i; }
}
//输出
// 子类get方法
// 0
// 父类构造方法
// 子类构造方法
// 子类get方法
// 1000 讲一下流程:先父类加载,然后子类加载,这样jvm知道了每个类都有哪些变量和方法。
这时候new Son(1000),先不传参,先要进行初始化。先对父类初始化,再对子类进行初始化。
故先进入Son的构造方法,这时候第一句是默认单独super()方法,由此进入父类的构造方法,
先对父类进行初始化。结果父类构造方法第一句是调用,因为子类覆盖了父类的方法,故调用的是子类的方法。
因此先输出“子类get方法”,这时子类还没有初始化完成(父类还没呢,因为父类构造方式是初始化的最后一步)
故返回的是默认值0,输出“0”
这时再输出“父类构造方法”,至此父类构造方法结束,父类初始化完成。开始子类初始化,输出“子类构造方法”。 因为形成了多态,故调用的是子类的getI方法,因此输出“子类get方法”,并且此时子类初始化完成了,
故输出“1000”
Demo3
class SingleTon {
private static SingleTon singleTon = new SingleTon();
public static int count1;
public static int count2 = 0; private SingleTon() {
count1++;
count2++;
} public static SingleTon getInstance() {
return singleTon;
}
} public class Demo3 {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
System.out.println("count1=" + singleTon.count1);
System.out.println("count2=" + singleTon.count2);
}
}
1:SingleTon singleTon = SingleTon.getInstance();调用了类的SingleTon调用了类的静态方法,触发类的初始化
2:类加载的时候在准备过程中为类的静态变量分配内存并初始化默认值 singleton=null count1=0,count2=0
3:类初始化化,因为是SingleTon.getInstance()这种初始化只会初始化静态变量和执行静态代码块儿和执行getInstance()方法,
但这时第一句是private static SingleTon singleTon = new SingleTon();
这一句给singleton分配了一块儿内存空间并且进行初始化,因为静态变量只能初始化一次并且只要初始化开始那么这次的初始化就占住了位置只能由他来初始化,
所以这些静态变量只能由SingleTon.getInstance()这次初始化来完成,new SingleTon()的这次初始化就是初始化非静态成员变量和构造方法
4:这时conunt1=1,count2=2,然后new的初始化完毕,之后再继续初始化静态变量(给静态变量赋值)count1不变为1;count2=0;
再执行SingleTon.getInstance()把值赋给外面的singleTon; 5:继续为count1与count2赋值,此时count1没有赋值操作,所有count1为1,但是count2执行赋值操作就变为0

类的加载与初始化

加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的。

(1)类的加载

  • 创建类的实例(首次创建该类对象)

    关于构造方法的执行时机,构造方法,在创建对象的最后一步,才会执行

  • 访问类的静态变量(首次)

  • 调用类的静态方法(首次)

  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

  • 加载某个类的子类,会先触发父类的加载

  • 直接使用java.exe命令来运行某个主类

(2)类的初始化

类的初始化主要就是对静态的类变量进行初始化:

(1)执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中所有类变量的显式赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)

(2)当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化

(3)虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步,每一个类在内存中都只有唯一的一个Class对象。

虽然类的加载大多数时候和类初始化是一气呵成的,但其实类的加载不一定就会触发类的初始化。

(a)会发生类的初始化的情况:

(1)当虚拟机启动,先初始化main方法所在的类

(2)使用new关键字创建一个类的对象

(3)调用该类的静态变量(final的常量除外)和静态方法

(4)使用java.lang.reflect包的方法对类进行反射调用

(5)当初始化一个类时,如果其父类没有被初始化,则先会初始化他的父类

(b)不会发生类的初始化的情况:

(1)引用静态常量不会触发此类的初始化,静态代码块不会执行,去掉final会执行

public class ClinitTest {
public static void main(String[] args) {
System.out.println(Son.NUM);
System.out.println(Father.NUM);
}
} class Father {
public static final int NUM = 10; static {
System.out.println("Father类静态代码块");
}
} class Son extends Father {
static {
System.out.println("Son类静态代码块");
}
} //输出:
// 10
/// 10

(2)当访问一个静态成员时,只有真正声明这个静态成员的类才会被初始化,下面代码中Son类不会初始化,Son类的静态代码块不会执行

public class ClinitTest {
public static void main(String[] args) {
System.out.println(Son.NUM);
}
} class Father {
public static int NUM = 10;
static {
System.out.println("Father类静态代码块");
}
} class Son extends Father {
static {
System.out.println("Son类静态代码块");
}
} //输出:
// Father类静态代码块
// 10

(3)某类型数组的动态初始化,不会触发此类的初始化

public class ClinitTest {
public static void main(String[] args) {
//没有创建Person类的对象,创建的是准备用来装Person对象的数组对象
Person[] people = new Person[10];
}
} class Person {
static {
System.out.println("Person类静态代码块");
}
}

Java 类的加载与初始化的更多相关文章

  1. Java类的加载 链接 初始化

    原文地址 Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够 ...

  2. java类的加载以及初始化顺序

    类的加载和初始化的了解对于我们对编程的理解有很大帮助,最近在看类的记载方面的问题.从网上查阅了若干文章,现总结如下: 我们通过一段代码来了解类加载和初始化的顺序: package com.classl ...

  3. Java类的加载及初始化

    每个类的编译代码都存在于它自己的独立文件中,该文件在需要使用该程序代码时才会被加载.通常有以下三种加载情况: (1) 访问了子类的静态变量或静态方法:仅对类的静态变量,静态块执行初始化操作,并仅初始化 ...

  4. java类的加载与初始化

    https://blog.csdn.net/u013349237/article/details/71076617 1在命令行启动虚拟机jvm进行加载, 2用class.forname()方法进行动态 ...

  5. Java类的加载、链接和初始化

    一.Java的类加载机制回顾与总结: 我们知道一个Java类要想运行,必须由jvm将其装载到内存中才能运行,装载的目的就是把Java字节代码转换成JVM中的java.lang.Class类的对象.这样 ...

  6. java 类的加载,链接,初始化

    本篇的话题,讨论Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码 ...

  7. JAVA类的加载、连接与初始化

    JAVA类的加载.连接与初始化 类的声明周期总共分为5个步骤1.加载2.连接3.初始化4.使用5.卸载 当java程序需要某个类的时候,java虚拟机会确保这个类已经被加载.连接和初始化,而连接这个类 ...

  8. java 类的加载、连接和初始化

    JVM和类 调用Java命令运行Java程序时,该命令将会启动一条Java虚拟机进程,不管该Java程序启动了多少条线程,创建了多少个变量,它们都处于该Java虚拟机进程里,共享该JVM进程的内存区. ...

  9. java类从加载、连接到初始化过程

    类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JV ...

随机推荐

  1. 强大的动态SQL

    1 动态SQL# 那么,问题来了: 什么是动态SQL? 动态SQL有什么作用? 传统的使用JDBC的方法,相信大家在组合复杂的的SQL语句的时候,需要去拼接,稍不注意哪怕少了个空格,都会导致错误.My ...

  2. 166个最常用的Linux命令,哪些你还不知道?

    linux命令是对Linux系统进行管理的命令.对于Linux系统来说,无论是中央处理器.内存.磁盘驱动器.键盘.鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心.     线上查 ...

  3. JAVA Executor(线程池)框架

    一.Executor概述 为更好控制线程,jdk提供一套线程管理框架Executor,帮助开发人员有效地进行线程控制.它们都位于java.util.concurrent包中,是jdk并发包的核心.其中 ...

  4. GitHub上的开源复刻:暗黑破坏神2

    现在的00后少年可能已经不太了解<暗黑破坏神2>这款由暴雪打造的经典游戏. 该游戏上市的时候,国内个人家用电脑还没有那么普及,网络游戏也没有那么风靡,现在的孩子可能无法想象,那时候网吧里的 ...

  5. vue中携带token以及发送ajax

    在项目中基本登录都会存在token,而我们也就需要在每次发送ajax的时候就必须携带他.从而最有效的办法,就是在设置请求头携带token,这样设置一次后面的每一次都会携带着这个token. 一:设置请 ...

  6. WixVersionControl Wix项目版本控制

    原文链接:https://www.swack.cn/wiki/001565675133949eff0d3d5a51f48288cf6d8248905e28f000/001569821278313e6b ...

  7. WPF TreeView Indent 减少节点的缩进

    www.swack.cn - 原文链接:WPF TreeView Indent 减少节点的缩进 问题 最近一个需求,需要在界面中实现Windows资源管理器TreeView的界面.但是我发现,我做出的 ...

  8. js如何替换字符串中匹配到多处中某一指定节点?

    抛出一个问题,如图,搜索关键字,匹配到四处,那我鼠标放在第二处,我想把它变个颜色,该怎么实现呢?回到文章的标题,js如何替换字符串中匹配到多处中某一指定节点? 字符串的替换,我们首先想到的一个属性是r ...

  9. Assuming that agent dropped connection because of access permission

    Assuming that agent dropped connection because of access permission

  10. 【Linux】awk想打印制定列以后的所有列

    今天偶然研究awk,有一个文件,文件内容是全篇的1 2 3 4 5 6 7 8 9 0 现在想打印除了第一列意外的所有列 文件内容: [root@localhost ~]# cat test.txt ...