静态域、非静态域、Final、父类以及抽象类正常实例化
设置Initalized用于初始化时对于结果进行输出
//被实例化类,设置初始方法用于显示初始化标记
public class Initalized {
public Initalized(String s) {
System.out.println(s);
}
}
设置接口类用于测试类继承,设置内容如下
interface InitalizeaedInterface {
//接口中变量默认都是static final
Initalized s1 = new Initalized("Initalizeaed Interface");
//usual method
public void test1();
//static method
//public void test2();
//final method
public void test3();
//static final method
//public void test4();
}
设置抽象类作为实现类父类
package com.cunchen.practice.init;
//设置被实例化类的父类
public abstract class InitalizedAbstract {
//父类中域中对于被实例化类进行实习化
Initalized a = new Initalized("Initalizeaed Abstract");
Initalized b;
static Initalized c;
//被实例化类的父类的构造方法
public InitalizedAbstract() {
b = new Initalized("Abstract Constractor");
}
//父类的非静态方法
public void test5() {
b = new Initalized("Abstract method");
}
//父类的非静态方法,此方法在子类中被覆盖
public void test6() {
b = new Initalized("Abstract covered method");
}
//父类静态方法
public static void test7() {
c = new Initalized("Abstract static method");
}
}
最终实现类如下
//实例化类
public class InitalizationTest extends InitalizedAbstract implements InitalizeaedInterface{
//变量域中实例化
Initalized s1 = new Initalized("Usual declared");
//变量域中静态变量实例化
static Initalized s2 = new Initalized("Static declared");
//变量域中常量实例化
final Initalized s5 = new Initalized("Final declared");
//变量域中静态常量实例化
static final Initalized s6 = new Initalized("Static final declared");
Initalized s3;
static Initalized s4;
//静态方法域中执行静态方法
static {
getReply();
}
//构造方法
public InitalizationTest() {
super();
s3 = new Initalized("Constructor");
}
//普通方法
public void test1() {
s3 = new Initalized("Method");
}
//静态方法
public static void test2() {
s4 = new Initalized("Static Method");
}
//Final方法
public final void test3() {
s4 = new Initalized("Final Method");
}
//静态Final方法
public static final void test4() {
s4 = new Initalized("Static final Method");
}
//重写父类方法
public void test6() {
s3 = new Initalized("Test covered method");
}
//静态域执行方法
public static void getReply() {
s4 = new Initalized("Static block");
}
public static void main(String[] args) {
//初始化过程
InitalizationTest test = new InitalizationTest();
System.out.println("-------------------------------");
//方法执行过程
test.test1(); //普通方法
test.test2(); //静态方法
test.test3(); //Final方法
test.test4(); //Static Final 方法
test.test5(); //父类方法
test.test6(); //重写方法
System.out.println("-------------------------------");
//空对象访问
test = null;
test.test2(); //普通方法
test.test1(); //静态方法
}
}
实际运行结果如下
Static declared
Static final declared
Static block
Initalizeaed Abstract
Abstract Constractor
Usual declared
Final declared
Constructor
-------------------------------
Method
Static Method
Final Method
Static final Method
Abstract method
Test covered method
-------------------------------
Static Method
Exception in thread "main" java.lang.NullPointerException
at com.cunchen.practice.init.InitalizationTest.main(InitalizationTest.java:74)
得出结论如下:
1.类内部初始化顺序为 静态域->非静态域->构造方法
2.类实例化过程中不会对于实现的接口的域进行初始化
3.类实例化过程中会在其构造方法之前对父类初始化
4.无论是静态方法还是非静态方法,在实例化过程中不直接执行
5.子类重写父类方法之后调用重写方法将不会对父类方法调用
6.静态域静态方法会在类加载时就直接进行初始化
7.空对象可以访问静态化区域,但不可以访问非静态化区域,,这个问题还引出对象在JVM存储结构的问题,不同对象在虚拟机中不同的存储策略决定了其不同的实现方式
反射方式
新建RunTest类
public class RunTest {
public static void main(String[] args) throws ClassNotFoundException {
//反射看class初始化情况
Class.forName("com.cunchen.practice.init.InitalizationTest");
System.out.println("-------------------------------");
InitalizationTest test = new InitalizationTest();
System.out.println("-------------------------------");
test.test1();
test.test6();
System.out.println("-------------------------------");
}
}
执行之后得到结果如下
Static declared
Static final declared
Static block
-------------------------------
Initalizeaed Abstract
Abstract Constractor
Usual declared
Final declared
Constructor
-------------------------------
Method
Test covered method
-------------------------------
得出结论:
- 反射仅会目标类静态域进行初始化,而对非静态域不初始化
- 静态域只会在类初次加载初始化,再次加载不进行初始化
- 反射之后,类并未真正实例化,并未调用其构造方法
ClassLoader加载类
修改main方法如下:
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader.getSystemClassLoader().loadClass("com.cunchen.practice.init.InitalizationTest");
System.out.println("-------------------------------");
//反射看class初始化情况
Class.forName("com.cunchen.practice.init.InitalizationTest");
System.out.println("-------------------------------");
InitalizationTest test = new InitalizationTest();
System.out.println("-------------------------------");
test.test1();
test.test6();
System.out.println("-------------------------------");
}
结果如下
-------------------------------
Static declared
Static final declared
Static block
-------------------------------
Initalizeaed Abstract
Abstract Constractor
Usual declared
Final declared
Constructor
-------------------------------
Method
Test covered method
-------------------------------
得到结论:ClassLoader在进行类加载之后并不对类进行任何初始化操作
深入理解
Class的装载包括3个步骤:加载(loading),连接(link),初始化(initialize)
Class.forName重载了两种实现方法,
public static Class<?> forName(String className)
throws ClassNotFoundException
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
第二个方法中的initialize方法其实就是指定Class被loading后是不是必须被初始化
实际上第一个方法执行结果等同于Class.forName(className, true, currentLoader)
ClassLoader.loadClass(String name)源码如下
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
实际执行情况为loadClass(name, false),装载的class将不会被link。
这两个方法都用于装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。相信到此大家也能明白在JDBC中经常用到的加载JDBC驱动程序是什么原理了把。
深入了解推荐
对象生命周期详解
Java ClassLoader详解