JAVA学习之反射(1):Class类和java.lang.reflect包的使用

2020-12-14 14:08:35 浏览数 (1)

参考链接: Java中的反射数组类reflect.Array

一,能够分析类能力的程序称为“反射”,反射库(java.lang.reflect)提供了精心设计的工具集,以便编写能够动态操作Java代码的程序。 

用一句经典的话概括反射:反射就是把java类中的各种成分映射成相应的java类。 

二,在程序运行期间,java运行时系统始终为所有的对象维护一个类型标识。这个标识跟踪着每个对象所属的类。虚拟机利用该标识选择相应的方法执行。可以通过专门的Java类访问这些信息。保存这些信息的类被称为Class类。 

如同一个Person对象表示一个特定的人一样,一个Class对象表示一个特定类的属性。 

三,创建Class类对象有3中形式: 

1,已知某对象,调用该对象的getClass()方法将返回一个Class类型的实例。 

Person p;

Class cc = p.getClass();2,调用静态方法forName获得类名对应的Class对象。 

String ss = "java.util.Date";

Class cc = Class.forName(ss);3,若T是任意的Java类型,T.class将代表匹配的类对象。 

Class cc1 = java.util.Date.class;

Class cc2 = int.class;

Class cc3 = Double[].classClass对象表示的是一个类型,而这个类型未必是一种类,如整型(int),数组(double[]) 

四,最常见的关于Class对象的两个操作 

1,getName()方法获得类的名字 

Person pp;

syso(pp.getClass().getName()); //syso是System.out.println()的简写。2,newInstance()方法快速创建一个类的实例 

Person pp;

Person pp2 = pp.getClass().newInstance();pp和pp2是2个不同的对象,newInstance()方法调用默认构造器初始化新对象,若没有默认构造器,会抛出异常。 

五,在java.lang.reflect包中有3个类Field,Method和Constructor分别用于描述类的域(成员变量),方法和构造器。 

Class类中的getField(),getMethod(),getConstructor()方法分别返回类提供的公有域,公有方法和公有构造器。 

Class类中的getDeclaredField(),getDeclaredMethod(),getDeclaredConstructor()方法分别返回类提供的私有域,私有方法和私有构造器。 

下面是一个关于上述这几个类和方法使用的示例。 

package com.jimmy.reflect;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

//创建一个类

class Son2{

    //私有的成员变量

    private double i;

    //默认构造函数和有参构造函数

    public Son2() {}

    public Son2(double i) {this.i = i;}

    //成员变量的set和get方法

    public void setter(double i) {this.i = i;}

    public double getter() {return i;}

}

//测试Class类的函数和反射库中的函数

public class test2 {

    public static void main(String[] args) throws Exception {

        //获得Son2类的Class对象。

        Class<?> cc = Son2.class;

        //先得到有参构造器的信息,再根据构造器的信息,由newInstance()函数创建一个Son2对象

        Constructor<?> constructor = cc.getConstructor(double.class);//要指定构造器参数的类型

        Son2 son = (Son2)constructor.newInstance(123);//newInstance()带上参数类型的实例。

        System.out.println(son.getter()); //输出被实例化对象son的成员变量的值:123.0。

        //先得到无参构造器的信息,再创建Son2对象

        Constructor<?> constructor1 = cc.getConstructor();

        Son2 son2 = (Son2)constructor1.newInstance();//Son2类中要有默认构造器

        System.out.println(son2.getter());//输出被实例化对象son2的成员变量的值:0.0。

        //由无参构造器创建对象时,可不必获得构造器,直接由Class对象调用newInstance()方法。

        Class<?> cc2 = Son2.class;

        Son2 son22 = (Son2)cc2.newInstance();

        System.out.println(son22.getter()); //输出被实例化对象son的成员变量的值:0.0

        //下面2个输出语句可看出cc保存类信息,输出的是“class 类名”。cc.newInstance()是具体类的对象。

        System.out.println(cc);  //输出:class com.jimmy.reflect.Son2

        System.out.println(cc.newInstance());  //输出:com.jimmy.reflect.Son2@15db9742(对象的地址)

        //首先得到有参构造函数的信息,然后根据构造函数实例化一个对象。

        //由getDeclaredField()函数得到类里面的私有成员变量,访问私有成员变量要用setAccessible()函数设置访问权限。

        //Field类对象得到成员变量后还可以设置该变量的值,使用set()方法。

        Constructor<?> constructor2 = cc.getConstructor(double.class);

        Son2 son23 = (Son2)constructor2.newInstance(321);

        Field field = cc.getDeclaredField("i");

        field.setAccessible(true);

        field.set(son23, 213);

        System.out.println(field.get(son23));  //field.get(对象)返回获得的对应域的值。

        //首先根据获得的构造函数信息实例化一个对象

        //然后由函数名获得类中的公有函数,getMethod("函数名")

        //invoke()方法执行由getMethod()获得的函数,这里获得的函数是getter()

        //对于获得的无参函数,invoke(对象)里只添加对象名。

        Constructor<?> constructor3 = cc.getConstructor(double.class);

        Son2 son24 = (Son2)constructor3.newInstance(231);

        System.out.println(cc.getMethod("getter").invoke(son24)); //输出函数执行返回的结果

        //对于获得到的有参函数,在调用getMethod()函数时,要在getMethod()中指定被获得函数的"函数名"和"参数类型"

        //并且在执行该函数(即调用invoke()函数时),要指定对象和参数类型的具体实例。

        Son2 son25 = (Son2)cc.newInstance(); 

        Method method = cc.getMethod("setter", double.class);

        method.invoke(son25, 123);

        System.out.println(son25.getter());  //输出函数执行返回的结果。

        //反射包里还有一个重要的类:Modifier,该类是静态类,其中的方法也都是静态方法

        //Class类中getModifiers()函数返回一个用于描述类,构造器,方法和域的修饰符的整形数值。、

        //调用Modifier.toString()方法将整型数值转变成字符串,也是就我们熟悉的public,private,static,final等修饰符。

        System.out.println(Modifier.toString(cc.getModifiers()));

        System.out.println(Modifier.toString(constructor.getModifiers()));

        System.out.println(Modifier.toString(field.getModifiers()));

        System.out.println(Modifier.toString(method.getModifiers()));

        //同时,Modifier类还有一些判断修饰符是不是某一类型的方法。

        System.out.println(Modifier.isPublic(cc.getModifiers()));

        System.out.println(Modifier.isPublic(constructor.getModifiers()));

    }

}

六,应用反射调用其他类的main()方法 

首先有一个类,main()方法输出信息: 

package com.jimmy.reflect;

public class testPrint {

    public static void main(String[] args) {

        for(String ss:args)

            System.out.println(ss);

    }

}

 在其他类中反射调用上面类的main()方法。 

package com.jimmy.reflect;

import java.lang.reflect.Method;

public class getMain {

    public static void main(String[] args) throws Exception {

        //传统方法

        testPrint.main(new String[]{"haha","xixi"});

        //反射调用

        Class<?> cc = Class.forName("com.jimmy.reflect.testPrint");

        Method mm = cc.getMethod("main", String[].class);

        mm.invoke(null, (Object)new String[]{"hello","jimmy"});//实例化字符串数组对象时要在前面加(Object),不然会报参数个数不匹配的错误。

    }

}

七,数组的反射 

package com.jimmy.reflect;

import java.lang.reflect.Array;

public class test3 {

    public static void main(String[] args) throws Exception {

        //新建4个不同的数组

        int[] a = new int[3];

        int[] b = new int[4];

        int[][] c = new int[3][4];

        String[] d = new String[3];

        //可以对比各个数组所属的类是否相同

        System.out.println(a.getClass() == b.getClass());

//        System.out.println(a.getClass() == c.getClass()); //不同的类不能比较是否相等,会报错

//        System.out.println(a.getClass() == d.getClass());

        System.out.println(a.getClass().getName());

        System.out.println(d.getClass().getName());

        System.out.println(a.getClass().getSuperclass().getName());

        //利用静态方法反射生成一个数组

        int[] aa = (int[]) Array.newInstance(int.class, 3);

        Array.set(aa, 0, 123);//set()静态方法赋值

        Array.set(aa, 1, 321);

        Array.set(aa, 2, 213);

        System.out.println(Array.get(aa, 0));//get()静态方法取值

        System.out.println(Array.get(aa, 1));

        System.out.println(Array.get(aa, 2));

        //获得数组类型的常用方式

        Class<?> cc = String[].class;

        Class<?> cc1 = Class.forName("[I");

        Class<?> cc2 = Class.forName("[Ljava.lang.String;");        

        System.out.println(cc);

        System.out.println(cc1);

        System.out.println(cc2);

        //通过已有对象获取数组类型

        Class<?> cc3 = aa.getClass();

        System.out.println(cc3);

        Class<?> cc4 = cc3.getComponentType();//根据类型信息获取数组内成员的类型

        System.out.println(cc4);

    }

}

0 人点赞