Java反射专题1

-1-类的加载

当程序主动使用某个类时,如果该类还没有被加载到内容中,则系统会通过加载,连接,初始化三个步骤来对该类进行初始化。(如果没有出意外,JVM会连续完成这三个动作),所以有时将这三个步骤统称为类的加载或类的初始化。

类加载指的是将类的Class文件读入内存中,并为之创建一个java.lang.Class对象(该Java.lang.Class对象是单实例的,无论这个类创建了多少个对象,它的Class对象时唯一的)。

类的加载是由类加载器完成,类的加载器通常由JVM提供。开发者可以通过继承ClassLoader基类来创建自己的类的加载器。加载类的二进制数据通常有如下来源:

(1)从本地文件系统加载class文件 (2)从JAR包加载class文件
(2)通过网络加载class文件

-2-类的连接

当类被加载后,系统为之生成一个对应的Class对象,接着就会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。

-3-类的初始化

在类的初始化阶段,虚拟机负责对类进行初始化,主要就是对类变量(静态变量)进行初始化。在Java类中对类变量指定初始值有两种方式:(1)声明变量时指定初始值;(2)使用静态初始化块为类变量指定初始值。JVM会按这些语句在程序中的排列顺序依次执行它们。

在 连接和初始化阶段,其实静态变量经过了两次赋值:第一次是静态变量类型的默认值;第二次是我们真正赋给静态变量的值。

-4-类初始化的时机

(1)创建类的实例。包括如下情况:使用new操作符来创建实例,通过反射来创建实例;

(2)调用某个类的类方法(静态方法);

(3)访问某个类或接口的类变量,或为该类变量赋值;

(4)使用反射方式来强制创建某个类或者接口对应的java.lang.Class对象,如:Class.forName(“Person”),这段代码会导致Person类被加载,初始化,并返回对应的java.lang.Class对象。

(5)初始化某个类的子类,该子类的所以父类都会被初始化。

(6)直接使用java.exe命令来运行某个主类。

-5-以下情况并不导致初始化

(1)对于一个final型的类变量,如果该类变量的值在编译时就可以确定下来,那么这个类变量相当于宏变量。因此即使程序使用该静态类变量,也不会导致该类的初始化。

(2)使用ClassLoader类的loadClass()方法来加载某个类时,该方法只是加载该类,并不会执行初始化。如:

public class ClassLoaderTest
{
    public static void main(String[] args) throws ClassNotFoundException
    {
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        cl.loadClass("Tester");
        Log.d("Tester" , "系统加载Tester类");
        //下面语句才会初始化Tester类
        Class.forName("Tester");
    }
}
class Tester
{
    static
    {
        Log.d("Tester" , "Tester类的静态初始化块...");
    }
}

-6-获取Class对象的三种方法

例子:

public class TestClassType
{
    public static final String TAG = "TestClassType";

    //构造器
    public TestClassType()
    {
        Log.d(TAG , "----构造函数----");
    }

    //静态初始化块
    static
    {
        Log.d(TAG , "----静态初始化代码块----");
    }

    //非静态初始化块
    {
        Log.d(TAG , "----非静态初始化块----");
    }
}

Class testTypeClass = TestClassType.class;
Log.d(TAG , testTypeClass.toString());

try
{
        Class testTypeForName = Class.forName("com.test.zhangtao.activitytest.TestClassType");
        Log.d(TAG , testTypeForName.toString());
}
catch (ClassNotFoundException e)
{
        e.printStackTrace();
}

TestClassType testClassType = new TestClassType();
Log.d(TAG , testClassType.getClass().toString());

- 输出-
D/TestClassType: class com.test.zhangtao.activitytest.TestClassType
D/TestClassType: ----静态初始化代码块----
D/TestClassType: class com.test.zhangtao.activitytest.TestClassType
D/TestClassType: ----非静态初始化块----
D/TestClassType: ----构造函数----
D/TestClassType: class com.test.zhangtao.activitytest.TestClassType
(1)Class cl=A.class; JVM将使用类A的类装载器,将类A装入内存(前提是:类A还没有装入内存),不对类A做类的初始化工作.返回类A的Class的对象;

(2)Class cl=对象引用o.getClass();返回引用o运行时真正所指的对象(因为:儿子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象 ;

(3)Class.forName(“类名”); JAVA人都知道.装入类A,并做类的初始化。

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用Class对象的newInstance()方法的时候,就必须保证:1、这个 类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器。

现在可以看出,Class对象的newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。

最后用最简单的描述来区分new关键字和newInstance()方法的区别:
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值