乐趣区

关于java:反射基本概念和应用

反射的基本概念

  • 什么是反射:反射就是把 java 中的各个局部,映射成一个个的 java 对象,也能够了解为这是一种创建对象的形式,而后利用这个对象来做一些事件。既然说反射是反射 java 类中的各个组成部分,那么一个类的组成部分都有些啥呢,例如一个类中有:成员办法、成员变量、构造方法等信息。利用反射技术咱们能够把这些组成部分映射成一个个对象。
  • Class ; 一个类对象
  • Constuructor; 类中的构造方法
  • Method;类中的办法
  • Field;类中的属性
获取 class 文件的三种形式
  1. 应用 Class 类中的静态方法 forName(“文件名”)来获取 class 文件。(如果是 java 原生态的类,就要写上在那个包外面)
  2. 间接用文件名获取
  3. 调用 Object 外面的 getclass()办法。援用.getclass();
@java
    public class Test01 {public static void main(String[] args) throws Exception {

         // 第一种获取 class 文件的形式
         Class c1 = Class.forName("java.util.Date");
         
         // 第二种获取 class 文件的形式。Class c2  = Date.class;
        
        // 第三种获取 class 文件的形式
        Date date = new Date();    
        Class c3 =date.getClass();
        
        System.out.println(c1==c2);
        System.out.println(c2==c3);

    }

}

验证获取的是不是同一个 class 文件,就去判断是否指向同一个内存地址。
运行后果:

@java

true
true

Process finished with exit code 0
利用反射创立实例

newInstance(); 创立此类对象示意类的新实例。就是创立一个无参的构造方法。
如果此类对象没有无参的构造方法,会报 java.lang.InstantiationException(类实例化失败)异样。

@java
      public class ReflectTest01 {public static void main(String[] args) throws Exception {

              // 执行了动态块,A 这个类加载了,阐明这个办法能够将 A 类扔到 java 虚拟机外面。//            Class.forName("com.qh. 利用反射创立实例.A");



//            不执行动态块
//            Class c1= A.class;



              //newInstance ; 创立一个新的实例
              Object o = Class.forName("com.qh. 利用反射创立实例.A").newInstance();
              if (o instanceof A){A a = (A)o;
                  a.m1();}
          }
      }

      class A{
          // 动态块,类加载的时候加载,而且只加载一次
          static <u>{</u>
              System.out.println("Just I miss you !");
          }

          public void m1(){System.out.println("张三!");
          }
      }

利用可变参数创立多个类的实例

@java
      public class ReflectTest02 {public static void m1(Class...c) throws Exception{for (int i = 0; i < c.length; i++) {Object o = c[i].newInstance();

                  System.out.println(o);

              }

          }

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

              <u>Class</u> a = <u>Date</u>.class;

              <u>Class</u> b= Exception.class;

              m1(a,b);

          }

      }

运行后果

@java
Thu Oct 08 15:42:25 CST 2020
java.lang.Exception

Process finished with exit code 0
通过反射机制获取类的属性(Field)
  1. Class 类 Api:

String getSimplename(); 返回源代码中给出的根底类的简略名称。
int getModifiers()返回此类或接口的 Java 语言修饰符,以整数编码。
Field getDeclaredField(String name)返回一个 Field 对象,它反映此示意的类或接口的指定已申明字段 类对象。
Field [] getDeclaredFields()返回的数组 Field 对象反映此示意的类或接口申明的所有字段 类对象。
Field getField(String name)返回一个 Field 对象,它反映此示意的类或接口的指定 公共成员 字段类对象。
Field[] getFields()返回蕴含一个数组 Field 对象反射由此示意的类或接口的所有可拜访的 公共成员 字段类对象。

  1. Field 类 Api:

String getName(); 返回由此 Field 对象示意的字段的名称。
Class<?> getType()返回一个类对象标识了此示意的字段的申明类型 Field 对象。
int getModifiers()返回此类或接口的 Java 语言修饰符,以整数编码。

  1. Modifier 类 Api:

String toString()返回对象的字符串示意模式。

反编译一个类的所有属性包含修饰符、申明类型


@java
      public class ReflectTest03 {public static void main(String[] args) throws Exception {

              //1. 获取一个类
              Class c = Class.forName("java.util.Date");
              //2. 利用类获取一个属性数组
              <u>Field</u>[] fie = c.getDeclaredFields();
              StringBuffer sb = new StringBuffer();
              sb.append(<u>Modifier</u>.toString(c.getModifiers())+"class"+c.getSimpleName());
              sb.append("{\n");
              for (<u>Field</u> field:
                   fie) {
                  //3. 获取属性的修饰符
                  sb.append("\t"+<u>Modifier</u>.toString(field.getModifiers())+" ");
                  //4. 获取属性的类型
                  sb.append(field.getType().getSimpleName()+" ");
                  //5. 获取属性的名字
                  sb.append(field.getName()+"\n");
              }
              sb.append("}");
              System.out.println(sb.toString());
          }
      }

      class Person {
          private String <u>name</u> ;
          public int age;
          protected String sex;
          boolean hird;
      }

运行后果:

public class Date{
    private static final BaseCalendar gcal
    private static BaseCalendar jcal
    private transient long fastTime
    private transient Date cdate
    private static int defaultCenturyStart
    private static final long serialVersionUID
    private static final String[] wtb
    private static final int[] ttb}

利用反射机制获取类的单个属性:

  1. Field 类 Api:

void set(Object o,Object valut); 给对象的属性赋值
Object get(Object o); 查看这个对象的属性值

  1. Field 继承 AccessibleObject 类 Api:

void setAccessible(boolean b); 突破属性的封装性。

@java
public class ReflectFieldTest01 {public static void main(String[] args) throws Exception {Properties p = new Properties();
        Reader rea = new FileReader("D:\\Fieldreflect.properties");
        p.load(rea);
        rea.close();
        String fieldName = p.getProperty("FieldName");
        
        // 获取一个类
        Class c = Class.forName("com.qh. 利用反射取得类中的属性.Persion");
        Field field = c.getDeclaredField(fieldName);
        Object o = c.newInstance();
        
        // 突破属性的封装性
        field.setAccessible(true);
        
        // 给 o 对象外面的属性赋值。Scanner input = new Scanner(System.in);
        System.out.println("请为该属性赋值:");
        field.set(o,input.next());
        
        // 输入 o 对象外面的 field 属性值
        System.out.println("该属性的值:"+field.get(o));
    }
}

运行后果:

请为该属性赋值:男
该属性的值:男
利用反射机制获取一个类的办法(Method)

1. 利用反射机制获取一个类的所有办法
Class 类 Api:
Method[] getDeclaredMethods(); 返回一个 Method 类型的数组
Method getDeclaredMethod(String name, 类 <?>… parameterTypes); 返回一个 办法对象,它反映此表 示的类或接口的指定申明的办法 类对象。
Method getMethod(String name, 类 <?>… parameterTypes) 返回一个 办法对象,它反映此示意的类或接口的指定公共成员办法 类对象。
Method getMethods(); 返回蕴含一个数组 办法对象反射由此示意的类或接口的所有公共办法 类对象,包含那些由类或接口和那些从超类和超接口继承的申明。
Method 类 Api:
int Modifiers();返回一个办法修饰符所代表的 int 类型的值
String getname(); 返回办法的名字
String getReturnType(); 返回办法的返回值
String getParameterTypes(); 返回一个办法内的形式参数类型数组

@java

public class MethodReflectTest01 {public static void main(String[] args) throws Exception {
        // 获取一个类
        Class c= Class.forName("com.qh. 利用反射取得类中的办法.Register");
        // 通过一个类获取所有办法
        Method[] m = c.getDeclaredMethods();
        // 将所有的办法遍历
        for (Method me:
             m) {
            // 办法的修饰符
            int modifiers = me.getModifiers();
            System.out.println(Modifier.toString(modifiers));
            // 办法的返回值
            Class returnType = me.getReturnType();
            System.out.println(returnType.getSimpleName());
            // 办法名字
            System.out.println(me.getName());
            // 办法的参数类型
            Class[] parameterTypes = me.getParameterTypes();
            for (Class parameterType:
                 parameterTypes) {System.out.println(parameterType.getSimpleName());
            }
        }
    }
}

运行后果:

public
void
love
public
boolean
login
String
String

通过反射机制获取特定的指定办法:
Object invoke(Object o,Object..age);运行 o 对象的办法,传入 age 参数,返回一个 Object 后果。

@java

public class MethodReflectTest03 {public static void main(String[] args) throws Exception {
        // 获取一个类
        Class c= Class.forName("com.qh. 利用反射取得类中的办法.Register");
        // 获取指定的办法, 与获取属性不同的是,属性非凡的属性名,而调用单个办法是办法名和形参列表
        Method m = c.getDeclaredMethod("login",String.class,String.class);
        // 运行 login 办法
        Object autonomo = m.invoke(c.newInstance(), "Autonomo", "123");
        System.out.println(autonomo);
    }
}

外面的办法名,传入的参数都能够写一个 properties 配置文件来代替,这样写不会吧代码写死,反射就是考究代码的灵活性。
运行后果:

true

运行了 login 办法

利用反射机制获取一个类的构造方法(Constuructor)

反编译一个类的所有构造方法
所用的办法与 Method 类外面的一样

@java

public class ConstructorReflectTest02 {public static void main(String[] args) throws Exception {
        // 获取一个类
        Class c = Class.forName("java.lang.String");
        // 获取这个类外面所有的构造方法,返回一个 Constructor 类型的数组
        Constructor[] co = c.getDeclaredConstructors();
        // 创立一个 StringBuffer 进行间断的字符串拼接
        StringBuffer sb = new StringBuffer();
        sb.append(Modifier.toString(c.getModifiers())+ "class"+c.getSimpleName()+"{\n");
        for (Constructor con:
             co) {sb.append("\t");
            // 获取办法的修饰符
            sb.append(Modifier.toString(con.getModifiers())+" ");
            // 获取办法名,办法名就是类名,能够间接获取类名
            sb.append(c.getSimpleName()+"(");
            // 形参列表类型
            Class[] parameterTypes = con.getParameterTypes();
            for (int i = 0; i < parameterTypes.length; i++){if (i<parameterTypes.length-1){sb.append(parameterTypes[i].getSimpleName()+",");
                }else{sb.append(parameterTypes[i].getSimpleName());
                }
            }
            sb.append("){}\n");
        }
        sb.append("}");
        System.out.println(sb.toString());
    }
}

这里是输入了 String 类外面所有的构造方法,只输入了构造,并没有输入具体内容
运行后果:

public final class String{public String(byte[],int,int){}
    public String(byte[],Charset){}
    public String(byte[],String){}
    public String(byte[],int,int,Charset){}
    public String(byte[],int,int,String){}
     String(char[],boolean){}
    public String(StringBuilder){}
    public String(StringBuffer){}
    public String(byte[]){}
    public String(int[],int,int){}
    public String(){}
    public String(char[]){}
    public String(String){}
    public String(char[],int,int){}
    public String(byte[],int){}
    public String(byte[],int,int,int){}}

获取一个类特有的构造方法
Constructor:Object newInstance(Object…args); 应用此 Constructor 对象示意的构造函数,应用指定的初始化参数来创立和初始化构造函数的申明类的新实例。
(调用了构造方法就是调用了 tostring 办法)

@java

public class ConstructorReflectTest03 {public static void main(String[] args) throws Exception {
        // 获取一个类
        Class c = Class.forName("com.qh. 利用反射取得类中的构造方法.Person");
        // 获取指定的构造方法,构造方法名字都一样,只是参数不一样
        Constructor con = c.getDeclaredConstructor(String.class,int.class);
        //
        Object con1 = con.newInstance("张三", 15);
        System.out.println(con1);
 

运行后果

Person{name='张三', age=15}
利用反射机制获取类的父接口和父类

Class 类:
Class getSuperclass(); 返回 类示意此所示意的实体(类,接口,根本类型或 void)的超类 类。
Class[] getInterfaces(); 确定由该对象示意的类或接口实现的接口。

@java

public class ConstructorReflectTest03 {public static void main(String[] args) throws Exception {
        // 获取一个类
        Class c = Class.forName("com.qh. 利用反射取得类中的构造方法.Person");
        // 获取指定的构造方法,构造方法名字都一样,只是参数不一样
        Constructor con = c.getDeclaredConstructor(String.class,int.class);
        //
        Object con1 = con.newInstance("张三", 15);
        System.out.println(con1);
    }
}

运行后果:

继承的父类:Object
实现的父接口:Serializable
Comparable
CharSequence
退出移动版