Java 基础之类信息的加载与反射使用

1、简介

在Java和Android中都有关于类的加载方面的知识点,之前也是这块比较模糊现在呢有必要确切的去了解这些信息,到底是怎么样的执行顺序,以及类加载很重要的方式反射。

2、详情

Java语言与传统语言的不同点体现在对于类而言Java程序在使用其前并非完全加载,其各个部分都是在需要的时候动态加载的,这里也必然涉及到加载的时机。类加载的条件是,该类第一次被使用,而且创建了第一个对类静态成员的使用。

反射的概念: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

案例1如下:

class A{
    static {
        System.out.println("loading A .....");
    }
}

class B{
    static {
        System.out.println("静态域 B .....");
    }

    public B(){
        System.out.println("构造B ...");
    }
}

public class Load {
    public static void main(String[] args){
        System.out.println("类A加载前..");
        new A();
        System.out.println("类A加载后.. ");
        System.out.println("--------------");
        System.out.println("类B 反射加载前.. ");
        // 从结果可以看出 Class.forName("xxx") 
        // 类加载了静态的成员和域 并未执行构造方法
        try {
            Class.forName("review_9_6.B");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("类B 反射加载后.. ");
    }
    
    
     
/*  
    output:类A加载前..
    loading A .....
    类A加载后..
    --------------
    类B 反射加载前..
    静态域 B .....
    类B 反射加载后..*/
}

这里再次指出,静态域和静态成员变量只会加载一次,并且存放于方法区中

Class.forName("xxx")  是Class(所有Class都属于这一个类 )的一个静态成员方法

案例二如下:

class InitA{
    static final int I = 47;
    static {
        System.out.println("静态域InitA ");
    }
}

class InitB{
    static final int I = 47;
    static {
        System.out.println("静态域InitB ");
    }
}

class InitC{
    static int I = 48;
    static {
        System.out.println("静态域InitC ");
    }
}

public class ClassInitTest {
    public static void main(String[] args){
        Class<InitA> initAClass = InitA.class;
        System.out.println("InitA 加载后 --------");
        System.out.println(InitA.I);
        try {
            Class.forName("review_9_6.InitB");
            System.out.println("InitB 加载后 --------");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(InitC.I);
/*      InitA 加载后 --------
        47
        静态域InitB
        InitB 加载后 --------
        静态域InitC
        48*/
    }
}

该案例说明: 类.class( ) 不会自动地初始化该Class对象 。

再有观察 InitA 和 InitC 可以发现的是, static final 修饰的 为 编译器常量,不需要对类进行初始化就能读取。

而如果只是一个static 而不是 final的如 InitC类所示,那么在对它访问时,被读取前要先进行链接(为这个域分配存储空间)和初始化(初始化该存储空间)。

案例3 invoke( )使用

public Object invoke(Object obj,
                     Object... args)
              throws IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException
public class InvokeTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        List<String> mList = new ArrayList<>();
        mList.add("aaa");
        mList.add("bbb");
        Class<? extends List> aClass = mList.getClass();
        Method method = aClass.getMethod("add", Object.class);
        // invoke为某个对象执行某个方法 args:代表参数列表
        method.invoke(mList,1234);
        System.out.println(mList);
    }
    /*[aaa, bbb, 1234]*/
}

这里 getMethod(x1,x2) x1 代表的是方法的字符串,x2代表的是方法的参数列表的类型类

猜你喜欢

转载自blog.csdn.net/crazyZhangxl/article/details/82453759
今日推荐