深入理解反射

反射:

2020-04-11:补充
重要:将类的各个组成部分封装成其他对象,这就是反射。
在这里插入图片描述
重要结论:同一个字节码文件在一次运行过程中,只会被加载一次。

一、定义:
发生在运行时期,对于任意一个类都能知道这个类的所有属性和方法,对于任意一个对象都能调用它的任意方法和属性。这种动态的获取信息动态调用对象的方法的功能,称为java反射机制。

对每一种对象,JVM 都会实例化一个 java.lang.Class 的实例,java.lang.Class 为我们提供了在运行时访问对象的属性和类型信息的能力。Class 还提供了创建新的类和对象的能力。最重要的是,Class 是调用其他反射 API 的入口,我们必须先获得一个 Class 实例才可以进行接下来的操作。

使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(即字节码文件))
2个重要概念:
静态编译:编译时确定对象,绑定对象
动态编译:运行时确定类型,绑定对象
反射就是运动动态编译创建对象。
二、反射中常用的方法(都是Class对象的功能

/**
 * 反射 练习
 * 2019-06-14 wx
 */
public class ReflectText {
    //一、得到类的三种方式
   public static void main(String[] args) throws Exception{
      //1.CLass类的静态方法获取Class 类对象  常用这种方法,字符串可以传入也可以写在配置文件等,比较灵活
        Class<?> class1 = Class.forName("test.reflect.Student");
        System.out.println("1.通过Class的静态方法forName获取Class对象。"+class1);
        //2.通过实例变量getCLass()方法 。对象都有了,还要反射干啥
        Student st = new Student();
        Class class2 = st.getClass();
        System.out.println("2.通过实例变量getClass()获取Class对象。"+class2);

         //3.使用字面量.class来获取Class对象。需要导入类的包,依赖太强
        Class class3= Student.class;
        System.out.println("3.通过字面量.class来获取Class对象。"+class3);
        Class s = int.class;
        Class s1 = Integer.TYPE;//TYPE 是基本数据类型的包装类型的一个标准字段,是一个引用,指向对应的进本类型的Class对象

        Class v =void.class;
        Class v1=Void.TYPE;
        System.out.println("通过三种方式获取的CLass 对象是否一致:"+class1.equals(class2)+class2.equals(class3));
        //二、通过Java反射可以得到类的一些信息
        //例如有:类名,类修饰符,父类,实现的接口,构造器,方法,属性,包信息,注解
        //2.1 获取类名
        String name = class3.getName();
        System.out.println("2.1 通过反射,调用getName()方法,获取类名:"+name);

        String name1 = class3.getCanonicalName();
        System.out.println("2.1 通过反射,调用getCanonicalName(),获取类名:"+name1);

        String name2 = class3.getSimpleName();//不包含包名
        System.out.println("2.1 通过反射,调用getSimpleName(),获取类名:"+name2);

         //2.2 通过反射,得到类的修饰符
         int modifies = class3.getModifiers();//修饰符被封装进一个int 内,每一个修饰符都是一个标志位
         Modifier.isPublic(modifies);
         System.out.println("2.2 通过反射 得到类的修饰符"+modifies +" "+Modifier.isPublic(modifies));

         //2.3 通过反射 ,得到类的包信息
         Package package1 = class3.getPackage();
         package1.getName();
         package1.getImplementationVersion();
         System.out.println("2.3 通反射,获取类的 包信息:"+package1 +" | "+package1.getName()+ " | "+package1.getImplementationVersion());

         //2.4 通过反射,得到类的 父类信息
         Class supe = class3.getSuperclass();
         supe.getSuperclass();//继续使用反射
         System.out.println("2.4 通过反射获取类的父类信息:"+supe+" | "+supe.getSuperclass());

        //2.5 通过反射 得到类的 接口信息
         Class[] interfaces = class3.getInterfaces();
         System.out.println("2.5 通过反射 ,得到类的 接口信息:"+ interfaces+"| "+interfaces.length);
         Class in =null;
           for(int i=0;i< interfaces.length;i++){
         in = interfaces[i];
         System.out.print("2.5 通过反射 ,得到类的 接口信息:"+ in.getName() +" | ");
      }
         System.out.println();
        Type[] interfacesT = class3.getGenericInterfaces();
        System.out.println(interfacesT+"| "+interfacesT.length);
        Type type =null;
        for (int i=0;i<interfacesT.length;i++){
           type=interfacesT[i];
           System.out.println(type );
        }
         AnnotatedType[] in2 = class3.getAnnotatedInterfaces();
         AnnotatedType ann=null;
         for (int i=0;i<in2.length;i++){
            ann=in2[i];
            System.out.println(ann.getType() );
         }
      //2.6 通过反射,得到类的 构造函数
        //getConstructors()
        Constructor[] cons = class3.getConstructors();
        Constructor con =null;
        for (int i=0;i<cons.length;i++){
           con = cons[i];
           System.out.print("2.6 通过反射 ,得到类的构造函数:"+con+"| ");
        }
        System.out.println();

        //getDeclaredConstructors 得到本类的所有构造函数,不管修饰符是啥
       Constructor[] cons2 = class3.getDeclaredConstructors();
       Constructor con2 = null;
       System.out.print("2.6 通过反射 ,得到类的构造函数,使用的是getDeclaredConstructors()方法,得到的是本类所有的(All)构造函数,不管修饰符是啥:");
       for (int i=0;i<cons2.length;i++){
         con2 = cons2[i];
         System.out.print(con2+"| ");
       }
       System.out.println();

      //2.7 通过反射 ,得到类的方法
      Method[] methods = class3.getMethods();
      Method method =null;
      System.out.print("2.7 通过反射,得到类的方法,调用getMethods()方法,能得到本类和父类的public修饰的方法:");
      for (int i=0; i<methods.length;i++){
         method = methods[i];
         System.out.print(method+"| ");
      }
      System.out.println();

      Method[] methods1 = class3.getDeclaredMethods();
      Method method1 =null;
      System.out.print("2.7 通过反射,得到类的方法,getDeclaredMethods()方法,能得到本类所有的(All)方法,不管修饰符是什么:");
      for (int i=0; i<methods1.length;i++){
         method1 = methods1[i];
         System.out.print(method1+"| ");
      }
      System.out.println();
      //2.8 通过反射, 得到类的属性,即字段
      Field[] fields = class3.getFields();
      Field field = null;
      System.out.print("2.8 通过反射,得到类的字段,getFields()方法,得到本类和父类中被public 修饰的字段:");
      for (int i=0; i<fields.length;i++){
         field = fields[i];
         System.out.print(field+"| ");
      }
      System.out.println();

      Field[] fields1 = class3.getDeclaredFields();
      Field field1 = null;
      System.out.print("2.8 通过反射,得到类的字段,getDeclaredFields()方法,得到本类中所有的(All)字段,不管修饰符是啥:");
      for (int i=0; i<fields1.length;i++){
         field1 = fields1[i];
         System.out.print(field1+"| ");
      }
      System.out.println();
      
      //2.9 通过反射,获取注解
    Class clazz = TestAnnotation.class;

       try {
           MyAnnotation.MyClassAnnotation myClassAnnotation = (MyAnnotation.MyClassAnnotation) clazz.getAnnotation(MyAnnotation.MyClassAnnotation.class);
           System.out.println("2.9 通过反射获取注解:" +myClassAnnotation.desc());
       } catch (Exception e) {
           e.printStackTrace();
       }

       //3.0 通过反射,创建对象实例 ,获取到了实例,想要什么信息就有什么信息。  很重要!!!!!
       Student c = (Student)class1.newInstance();
       c.sex="female";
       c.name="wuxia";
       c.age=18;
       c.speak();
       System.out.println(c);

三、反射灵魂三连问:
1.什么是反射?
反射是在运行期根据指定的类名获得类的各种信息。
2.为什么需要反射?
如果一个包中的类经常需要变动,可以考虑反射(增加一个包可以增加一个配置文件),提高效率。但是不建议无脑使用反射,因为反射开销昂贵
栗子:

public interface Fruit {
    public abstract void eat();
}
public class Apple implements Fruit{
    public String name ;
    public String type;
    @Override
    public void eat() {
        System.out.println("eat Apple....");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}
public class Orange implements Fruit{
    @Override
    public void eat() {
        System.out.println("eat Orange...");
    }
}
/**
 * 当使用反射,可以不用修改FruitFactory
 */
public class FruitFactory {

    //1.使用反射
    public static Fruit getInstance(String className){
        Fruit f =null;
        try {
            f =(Fruit) Class.forName(className).newInstance();//反射
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
    //2.不使用反射,每当增加一个新的类,都需要修改此类
    /*public static Fruit getInstance(String className){
        Fruit f =null;
        if("Apple".equals(className)){
            f = new Apple();
        }
        if("Orange".equals(className)){
            f = new Orange();
        }
        return f;
    }*/
    //test
    public static void main (String[] args){
        Fruit f = FruitFactory.getInstance("test.reflect.refectDemo.Apple");
        Fruit f1 = FruitFactory.getInstance("test.reflect.refectDemo.Orange");
       /* Fruit f =FruitFactory.getInstance("Apple");
        Fruit f1 = FruitFactory.getInstance("Orange");*/
        if(f != null){
            f.eat();
        }
        if(f1 != null){
            f1.eat();
        }
    }
}

3.怎么使用反射?
熟悉Class 类中的方法,例如,获取类对象,类对象的实例
,类的方法,属性等

4.补充知识点:

/**
 * 2020-04-11
 * 通过反射获取类对象的成员变量对象(主要是获取值,和设置值),
 * 构造方法对象(主要用来创建对象),成员方法对象(主要用来执行方法),以及获取之后的一些操作,
 * 重点就是获取后的一些操作
 */
public class RefectGetFieldDemo {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.wx.refect.Student");
        Student student1 =new Student();
        Field f = clazz.getDeclaredField("name");
        //Object name = f.get(new Student());// 会报这个错误,IllegalAccessException,因为成员变量是私有的,需要设置下
        //忽略访问权限修饰符的安全检测
        f.setAccessible(true);//即暴力反射,不管是不是私有的都能访问
        f.set(student1, "wuxia");//给成员变量赋值
        Object name = f.get(student1);//可以获取成员变量的值
        System.out.println("通过反射获取到了类对象的成员变量,并对其做一些操作:"+name);

        //获取构造方法
        //构造方法是用来创建对象
        Constructor constuct = clazz.getConstructor(String.class);
        Constructor constuct1 = clazz.getConstructor();
        System.out.println(constuct);
        //创建对象
        Object o = constuct.newInstance("wuxia");
        System.out.println(o);
        Object o1 = constuct1.newInstance();
        System.out.println(o1);
        System.out.println(clazz.newInstance());

        System.out.println("======通过反射获取方法对象,然后执行方法===========");
        Method method= clazz.getMethod("eat",String.class);
        method.invoke(student1,"wuxia");
    }

获得类,方法,变量的修饰符使用getModifiers(),但此方法返回的是int类型的数据,
Modifier类的toString()方法可以将其转成字符串形式。

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

toString()方法源码:

public static String toString(int mod) {
        StringBuilder sb = new StringBuilder();
        int len;

        if ((mod & PUBLIC) != 0)        sb.append("public ");
        if ((mod & PROTECTED) != 0)     sb.append("protected ");
        if ((mod & PRIVATE) != 0)       sb.append("private ");

        /* Canonical order */
        if ((mod & ABSTRACT) != 0)      sb.append("abstract ");
        if ((mod & STATIC) != 0)        sb.append("static ");
        if ((mod & FINAL) != 0)         sb.append("final ");
        if ((mod & TRANSIENT) != 0)     sb.append("transient ");
        if ((mod & VOLATILE) != 0)      sb.append("volatile ");
        if ((mod & SYNCHRONIZED) != 0)  sb.append("synchronized ");
        if ((mod & NATIVE) != 0)        sb.append("native ");
        if ((mod & STRICT) != 0)        sb.append("strictfp ");
        if ((mod & INTERFACE) != 0)     sb.append("interface ");

        if ((len = sb.length()) > 0)    /* trim trailing space */
            return sb.toString().substring(0, len-1);
        return "";
    }
    ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值