Java_反射机制

一、理解Class类并获取Class实例

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

  • 反射就是把java类中的各种成分映射成一个个的Java对象:
    例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

1、关于java. Lang.Class类的理解

1、类的加载过程:
程序经过javac.exe命令以后,会生成一个或多个字节码文件(.cLass结尾)。
接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为CLass的一个实例。

2、换句话说,Class的实例就对应着一个运行时类。

Class c1 = 运行时类

3、加载到内存中的运行时类,会缓存一定的时间,在此时间内,我们可以通过不同的方式来获取此运行时类

2、获取Class的实例方式:

方式一:调用运行时类的属性:.class
方法二:调用运行时类的对象,调用getClass()方法
方式三:调用Class的静态方法:forName(String classPath)(常用)
(注意此字符串必须是真实路径,就是带包名的类路径,包名.类名)
方法四:使用类的加载器:ClassLoader

 //获取Class的实例方法
    @Test
    public void test1() throws ClassNotFoundException {
        //方法一:调用运行时类的属性:.class
        Class c1= Person.class;
        System.out.println(c1);
        //方法二:调用运行时类的对象,调用getClass()方法
        Person p1=new Person();
        Class c2=p1.getClass();
        System.out.println(c2);
        //方式三:调用Class的静态方法:forName(String classPath)
        Class c3= Class.forName("D1.Person");//(需要指明那个包下的类)
        System.out.println(c3);
        //方法四:使用类的加载器:ClassLoader
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class<?> c4 = classLoader.loadClass("D1.Person");
        System.out.println(c4);
        
        System.out.println(c1==c4);

        System.out.println(c1==c2);
        System.out.println(c2==c3);
    }

class D1.Person
Person()
class D1.Person
class D1.Person
class D1.Person
true
true
true

二、创建运行时类的对象

newInstance():调用此方法,创建对应的运行时类的对象,内部调用了运行时类的空参构造器

 //通过反射创建运行时类的对象
    @Test
    public void test1() throws InstantiationException, IllegalAccessException {
        Class clazz = Person.class;
        Object obj = clazz.newInstance();
        Person p=(Person)clazz.newInstance();
        //newInstance():调用此方法,创建对应的运行时类的对象,内部调用了运行时类的空参构造器
        System.out.println(obj);
        System.out.println(p);

    }

Person()
Person()
Person{age=0, name=‘null’}
Person{age=0, name=‘null’}

三、调用运行时类的完整结构(属性、方法、构造器等)

1、获取当前运行时类的属性结构(Field)

方法一:getFields():获取当前运行时类及其父类中声明为public访问权限的属性
方法二:getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)

public void test1(){
        Class clazz=Person.class;

        //获取属性结构
        //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = clazz.getFields();
        for(Field f:fields){
            System.out.println(f);
        }

        System.out.println("------");

        //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f:declaredFields){
            System.out.println(f);
        }
    }

2、获取当前运行时类的方法结构(Method)

方法一:getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
方法二:getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)

@Test
    public void test1(){

        Class clazz= Person.class;

        //getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
        Method[] methods = clazz.getMethods();
        for(Method m: methods){
            System.out.println(m);
        }

        System.out.println("---------");

        //getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m:declaredMethods){
            System.out.println(m);
        }
    }

3、获取构造器结构

方法一:getConstructors():获取当前运行时类中声明为public的构造器
方法二:getDeclaredConstructors():获取当前运行时类中声明的所有的构造器

4、获取其他结构

1、获取运行时类的父类

getSuperclass()方法

2、获取运行时类的带泛型的父类

getGenericSuperclass()方法

3、获取运行时类的带泛型的父类的泛型

  //获取运行时类的带泛型的父类的泛型(以下代码会用就行,知道干什么的)(会用)
    @Test
    public void test3(){
        Class clazz= Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType=(ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();

        System.out.println(actualTypeArguments[0].getTypeName());
    }

4、获取运行时类实现的接口(会用)

getInterfaces()方法

5、获取当前运行时类所在的包

getPackage()方法

6、获取当前运行时类声明的注释

getAnnotations()方法

四、调用运行时类的指定结构:属性、方法、构造器(主要是方法和属性)

1、调用运行时类中指定的属性

在已有Class实例和运行时类对象的基础上
step1:getDeclaredField(String fieldName):
获取运行时类中指定变量名的属性
step2:保证当前属性是可访问的(不管什么访问权限的属性,都加上下句)获取属性名.setAccessible(true);
step3:根据需求获取、设置指定对象的此属性值

//非常重要:如何操作运行时类中的指定的属性-----必须掌握
    @Test
    //开发中用如下方法
    public  void testField1() throws Exception {
        Class clazz= Person.class;

        //创建运行时类对象
        Person p= (Person) clazz.newInstance();

        //1、getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
        Field name = clazz.getDeclaredField("name");

        //2、保证当前属性是可访问的(不管什么访问权限的属性,都加上下句)
        name.setAccessible(true);

        //3、根据需求获取、设置指定对象的此属性值
        name.set(p,"cxc");
        System.out.println(name.get(p));
    }

2、调用运行时类中指定的方法

在已有Class实例和运行时类对象的基础上
step1:获取指定的某个方法:
getDeclaredMethod():参数1:指明获取方法的名称,参数2:指明获取的方法的形参列表(因为同名的方法很多,根据形参区分具体哪一个方法)
step2:保证当前的方法是可访问的:调用的方法名.setAccessible(true);
step3:调用方法的invoke():
参数1:方法的调用者,参数2:给方法形参赋值的实参,invoke()的返回值即为对应类中调用的方法的返回值

   @Test
    public void testMethod() throws Exception {
        Class clazz= Person.class;
        //创建运行时类对象
        Person p= (Person) clazz.newInstance();

        /*
            1、获取指定的某个方法
               getDeclaredMethod():参数1:指明获取方法的名称,参数2:指明获取的方法的形参列表(因为同名的方法很多,根据形参区分具体哪一个方法)
         */
        Method show = clazz.getDeclaredMethod("show", String.class);

        //2、保证当前的方法是可访问的
        show.setAccessible(true);

        /*
        3、调用方法的invoke():参数1:方法的调用者,参数2:给方法形参赋值的实参
        invoke()的返回值即为对应类中调用的方法的返回值
         */
        show.invoke(p,"CHN");//String nation =p.show("CHN“)

        Object returnValue = show.invoke(p,"CHN");
        System.out.println(returnValue);



        System.out.println("-------如何调用静态方法--------");
        //private static void showDesc()
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        //如果调用的运行时类中的方法没有返回值,则此invoke()返回null
        showDesc.setAccessible(true);
    //    Object returnVal =showDesc.invoke(Person.class);
        Object returnVal =showDesc.invoke(null);//(这两种方法都可以)
        System.out.println(returnVal);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值