通过图片和代码来介绍反射

下面这张图(分三个阶段)说明了源码怎么变成我们的实例对象的。

阶段一 :源码 通过javac编译 ,变成.class(也称字节码文件)->

阶段二:.class通过类加载器(classloader ,对于我们来说,我们一般都是通过class.forname()来加载)  变成 class对象   -> 

阶段三:class对象 通过newInstance实例化成特定的 实例化对象

class.forname和classloader的区别
class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
Class.forName得到的class是已经初始化完成的,Classloder.loaderClass得到的class是还没有链接的。
 

而对于反射,主要是阶段二、三,下面我们来介绍什么是反射。

1.什么是反射机制

Java-Reflection(JAVA反射)是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够通过Java-Reflection来调用它的任意方法和属性(不管是公共的还是私有的)。
这种动态获取信息以及动态调用对象方法的行为被称为java的反射机制。

2.反射机制有什么用


     通过java语言中的反射机制可以操作字节码文件(可以读和修改字节码文件。)

     通过反射机制可以操作代码片段。(class文件。)
 

通过上面这张图片,我们用代码来调用他们。

不过在进行代码之前,需要讲解一下,  源代码阶段就是 .java

那么源码如何变成class类(字节码)呢,有三种方法。

获取反射中的Class对象

在反射中,要获取一个类或调用一个类的方法,我们首先需要获取到该类的 Class 对象。

在 Java API 中,获取 Class 类对象有三种方法:

第一种,使用 Class.forName 静态方法。当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。

Class clz = Class.forName("java.lang.String");

第二种,使用 .class 方法。

这种方法只适合在编译前就知道操作的 Class。

Class clz = String.class;

第三种,使用类对象的 getClass() 方法。

String str = new String("");
Class clz = str.getClass();

通过反射创建类对象

通过反射创建类对象主要有两种方式:通过 Class 对象的 newInstance() 方法、通过 Constructor 对象的 newInstance() 方法。

第一种:通过 Class 对象的 newInstance() 方法。

Class clz = Apple.class;
Apple apple = (Apple)clz.newInstance();

第二种:通过 Constructor 对象的 newInstance() 方法

Class clz = Apple.class;
Constructor constructor = clz.getConstructor();
Apple apple = (Apple)constructor.newInstance();

通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。

Class clz = Apple.class;
Constructor constructor = clz.getConstructor(String.class, int.class);
Apple apple = (Apple)constructor.newInstance("红富士", 15);

newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以
否则会抛出java.lang.InstantiationException异常。

package com.example.aoptest.controller;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class money {


   private int  possess;
   private String name;

    public int getPossess() {
        return possess;
    }

    public void setPossess(int possess) {
        this.possess = possess;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public  money(){

    }
    public money(int possess, String name) {
        this.possess = possess;
        this.name = name;
    }

    public void  hh(){
        System.out.println("我是哈哈哈");
    }



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

    //正常的实例化对象
        money  m = new money();
        m.setName("哈哈");



   //使用反射实例化对象

        Class<?> aClass = Class.forName("com.example.aoptest.controller.money");


        System.out.println("我是成员变量");
        //普通的反射获取属性
        Field[] fields = aClass.getFields();


        //通过暴力反射,才能获取私有属性
        Field name1 = aClass.getDeclaredField("name");
        System.out.println(name1);

         //获取所有的属性
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field f:declaredFields
             ) {
            System.out.println(f.getName());

        }


        
        //如何调用方法method

        System.out.println("我是成员方法");


        // 大概过程就是
// 1.先用 Class对象获取指定的方法,如果该方法中有参数,需指定参数类型
//2.通过 Class对象获取构造器,可以选着有参构造和无参构造 .
// 3. 通过构造器 new Instance 实例化一个对象 .
//4. 如果想要调用方法 ,就用 方法.invoke(实例化的具体对象,该调用方法的参数,如果没参数可以不写). 
  //比如hh.invoke(o)。

        Method setPossess = aClass.getMethod("setPossess", int.class);
        Method getPossess = aClass.getMethod("getPossess");
        Method hh = aClass.getMethod("hh");
        Constructor<?> constructor1 = aClass.getConstructor(int.class,String.class);
        Object o = constructor1.newInstance(7,"gg");
        System.out.println(setPossess.invoke(o, 5));
        System.out.println(getPossess.invoke(o));
        System.out.println(hh.invoke(o));

     /*   Method[] methods = aClass.getMethods();
        for (Method me:methods ) {
            System.out.println(me);
        }
*/


      

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

      //    具体实例.class  返回的是class<T>    a,b,d,e,T 等等其实都是泛型的意思,只是用于区分而已。
        MyAnnotation annotation = aClass.getAnnotation(MyAnnotation.class);
        System.out.println(annotation);
        System.out.println(annotation.name());
        System.out.println(annotation.value());
        System.out.println(annotation.annotationType());






    }
}

总之,要获取私用的,都是通过getDeclared。 如果有参数的,就得把参数类型写上,无论是方法还是构造方法,如果是构造方法写的是有参构造,那么获得的构造器实例化时也需要把具体参数值写上,其实就跟我们平时    money  m = new money(“参数1”,“参数2”); 一样。

对于一个类,还有类的方法,属性,相信通过上面,我们都知道如何去获取了。那么 如果一个类,或者,或者一个属性上使用了注解,那么我们怎么获取呢?

我们先自定义一个注解, 叫做MyAnnotation ,给注解定义两个属性,name和value

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)

public @interface MyAnnotation {

        public  String name();
        public  String  value();

}

在money类上,我们使用注解,并给name和value随便赋值。

通过getAnnotation(注解.Class)来获取注解

  MyAnnotation annotation = aClass.getAnnotation(MyAnnotation.class); 获得 MyAnnotation这个注解类

@MyAnnotation(name="namehh",value = "hhhvalue")
public class money {


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

    
    System.out.println("-------- 注解 ");
      //    具体实例.class  返回的是class<T>    a,b,d,e,T 等等其实都是泛型的意思,只是用于区分而已。
        MyAnnotation annotation = aClass.getAnnotation(MyAnnotation.class);
        System.out.println(annotation);
        System.out.println(annotation.name());
        System.out.println(annotation.value());
        System.out.println(annotation.annotationType());

  /*  下面是上面代码的输出
        
    -------- 注解  
@com.example.aoptest.controller.MyAnnotation(name="namehh", value="hhhvalue")
namehh
hhhvalue
interface com.example.aoptest.controller.MyAnnotation  */  


    }
}

同样的,如果你想获得所有public注解,依然是通过 

  Annotation[] annotations = aClass.getAnnotations();
        for (Annotation a:annotations  ) {
            System.out.println(a);
                    
  
        }

反射主要使用的种类

 类名                                                用途

Class类                          代表类的实体,在运行的Java应用程序中表示类和接口

Field类                           代表类的成员变量(成员变量也称为类的属性)

Method类                       代表类的方法

Constructor类                代表类的构造方法

Annotation类                  代表类的注解

具体每个东西拥有的方法,我在这里不列出来了,百度一大堆。比如

Method代表类的方法。

方法用途
invoke(Object obj, Object... args)传递object对象及参数调用该对象对应的方法
getParameterTypes()获取方法所有的参数类型
getReturnType()获取方法返回对象的类型
getParameterTypes()返回方法中参数对象的Class类型
getGenericParameterTypes()返回方法中参数对象的Type类型
getAnnotation(Class<T> annotationClass)获取方法上面的注解
isAnnotationPresent(Class<T> annotationClass)判断是否对应的注解


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值