一、什么是反射

  反射允许对封装类的字段,方法和构造函数的信息进行编程访问
  
  
  
  idea中自动提示的功能就是反射实现的
  说白了就是能从类中拿东西

 这里类中数据的获取是从class文件得到的,而不是java文件,所以在获取之前我们需要先获取class文件的对象。


二、如何获取class对象

  ①Class.forName("全类名");
  ②类名.class
  ③对象.getClass();

这里的三个方法正好对应三个阶段

  ①源代码阶段
  ②加载阶段
  ③运行阶段

public class ReflectionDemo {  
    public static void main(String[] args) throws ClassNotFoundException {  
        //1.第一种获取class对象的方法  
        //    全类名:报名+类名        
        Class clazz = Class.forName("com.qcqc.javaStudy.Student");  
  
        //2.第二种方式获取class对象  
        Class clazz2 = Student.class;  
  
        //3.第三种方式获取class对象  
        Student s = new Student();  
  
        Class clazz3 = s.getClass();  
  
        //   注意点:  
        //这三种方式创建的class对象为同一个对象        
        //第一种方式最为常用        
        //第二种方式常作为参数传递        
        //第三种方式有一定局限性,仅当已经存在对象时才能使用  
    }  
}
       注意点:  
          这三种方式创建的class对象为同一个对象        
          第一种方式最为常用        
          第二种方式常作为参数传递        
          第三种方式有一定局限性,仅当已经存在对象时才能使用  

三、获取构造方法,成员变量和方法

  在java中万物皆对象,所以获取到的都是对象

  构造方法:Constructor类
  字段:Field类
  成员方法:Method类

一、利用反射获取构造方法

public class ReflectionDemo2 {  
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {  
        Class clazz = Class.forName("com.qcqc.javaStudy.Student");  
  
        System.out.println("--------getConstructors--------");  
        Constructor[] cons = clazz.getConstructors();  
        for (Constructor con : cons) {  
            System.out.println(con);  
        }  
        System.out.println("--------getDeclaredConstructors--------");  
        Constructor[] dcons = clazz.getDeclaredConstructors();  
        for (Constructor dcon : dcons) {  
            System.out.println(dcon);  
        }  
        System.out.println("--------getConstructor--------");  
        Constructor con = clazz.getConstructor();  
        System.out.println(con);  
        
        System.out.println("--------getDeclaredConstructor--------");  
        Constructor dcon = clazz.getDeclaredConstructor(String.class,int.class);  
        System.out.println(dcon);  
    }  
}

    获取单个构造函数时,需要传入与构造函数相同的参数!

  构造器的方法:

变量和类型方法描述
booleanequals(Object obj)将此 构造器与指定的对象进行比较。
AnnotatedTypegetAnnotatedReceiverType()返回一个 AnnotatedType对象,该对象表示使用类型来指定此 Executable对象所表示的方法/构造函数的接收器类型。
AnnotatedTypegetAnnotatedReturnType()返回一个 AnnotatedType对象,该对象表示使用类型来指定此可执行文件所表示的方法/构造函数的返回类型。
<T extends Annotation>TgetAnnotation(类<T> annotationClass)返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。
Annotation[]getDeclaredAnnotations()返回 直接出现在此元素上的注释。
类<T>getDeclaringClass()返回表示声明此对象表示的构造方法的类的 类对象。
Type[]getGenericExceptionTypes()返回 Type对象的数组, Type对象表示声明由此可执行对象引发的异常。
Type[]getGenericParameterTypes()返回 Type对象的数组, Type对象表示此对象表示的可执行文件的声明顺序的形式参数类型。
StringgetName()以字符串形式返回此构造函数的名称。
Annotation[][]getParameterAnnotations()返回 Annotation的数组数组,这些数组表示由此对象表示的 Executable声明顺序的形式参数的注释。
int getParameterCount()返回此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明,或两者都不)。
TypeVariable<构造器<T>>[]getTypeParameters()返回的数组 TypeVariable对象表示通过此表示的一般声明声明的类型变量 GenericDeclaration目的,在声明的顺序。
inthashCode()返回此 构造器的哈希 构造器 。
booleanisSynthetic()如果此可执行文件是合成构造,则返回true ; 否则返回false 。
booleanisVarArgs()如果声明此可执行文件采用可变数量的参数,则返回true ; 否则返回false 。
TnewInstance(Object... initargs)使用此 构造器对象表示的构造方法,使用指定的初始化参数创建和初始化构造函数声明类的新实例。
voidsetAccessible(boolean flag) 将此反射对象的 accessible标志设置为指示的布尔值。
StringtoGenericString()返回描述此 构造器的字符串,包括类型参数。
StringtoString()返回描述此 构造器的字符串。

  也可以使用该构造器创建对象

Student stu = (Student) dcon.newInstance("张三", 18);  
System.out.println(stu);

二、利用反射获取成员变量

System.out.println("--------getDeclaredFields--------");  
Field[] fields = clazz.getFields();  
for (Field field : fields) {  
    System.out.println(field);  
}  
System.out.println("--------getDeclaredFields--------");  
Field[] declaredFields = clazz.getDeclaredFields();  
for (Field field : declaredFields) {  
    System.out.println(field);  
}  
System.out.println("--------获取指定成员变量--------");  
Field gender = clazz.getField("gender");  
System.out.println(gender.getModifiers());  
System.out.println(gender.getName());

  成员变量的方法:

变量和类型方法描述
booleanequals(Object obj)将此 字段与指定的对象进行比较。
Objectget(Object obj)返回指定对象上此 字段表示的字段的值。
AnnotatedTypegetAnnotatedType()返回AnnotatedType对象,该对象表示使用类型来指定此Field表示的字段的声明类型。
<T extends Annotation>TgetAnnotation(类<T> annotationClass)返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。
<T extends Annotation>T[]getAnnotationsByType(类<T> annotationClass)返回与此元素 关联的注释。
booleangetBoolean(Object obj)获取静态或实例 boolean字段的值。
bytegetByte(Object obj)获取静态或实例 byte字段的值。
chargetChar(Object obj)获取类型为 char的静态或实例字段的值,或通过扩展转换获得可转换为类型 char的另一种基本类型的值。
类<?>getDeclaringClass()返回 类表示声明此表示的字段的类或接口对象 字段对象。
doublegetDouble(Object obj)获取类型为 double的静态或实例字段的值,或通过扩展转换获得可转换为类型 double的其他基本类型的值。
floatgetFloat(Object obj)获取类型为 float的静态或实例字段的值,或通过扩展转换获得可转换为类型 float的另一种基本类型的值。
TypegetGenericType()返回 Type对象,该对象表示此 字段对象表示的字段的声明类型。
intgetInt(Object obj)获取类型为 int的静态或实例字段的值,或通过扩展转换获得可转换为类型 int的另一种基本类型的值。
longgetLong(Object obj)获取类型为 long的静态或实例字段的值,或通过扩展转换获得可转换为类型 long的另一种基本类型的值。
intgetModifiers()以整数形式返回此 字段对象表示的字段的Java语言修饰符。
StringgetName()返回此 字段对象表示的字段的名称。
shortgetShort(Object obj)获取类型为 short的静态或实例字段的值,或通过扩展转换获得可转换为类型 short的另一种基本类型的值。
类<?>getType()返回 类对象,该对象标识此 字段对象表示的字段的声明类型。
inthashCode()返回此 字段的哈希 字段 。
booleanisEnumConstant()如果此字段表示枚举类型的元素,则返回true ; 否则返回false 。
booleanisSynthetic()如果此字段是合成字段,则返回true ; 否则返回false 。
voidset(Object obj, Object value)将指定对象参数上此 字段对象表示的字段设置为指定的新值。
voidsetAccessible(boolean flag)将此反射对象的 accessible标志设置为指示的布尔值。
voidsetBoolean(Object obj, boolean z)将字段的值设置为指定对象上的 boolean 。
voidsetByte(Object obj, byte b)将字段的值设置为指定对象上的 byte 。
voidsetChar(Object obj, char c)将字段的值设置为指定对象上的 char 。
voidsetDouble(Object obj, double d)将字段的值设置为指定对象上的 double 。
voidsetFloat(Object obj, float f)将字段的值设置为指定对象上的 float 。
voidsetInt(Object obj, int i)将字段的值设置为指定对象上的 int 。
voidsetLong(Object obj, long l)将字段的值设置为指定对象上的 long 。
voidsetShort(Object obj, short s)将字段的值设置为指定对象上的 short 。
StringtoGenericString()返回描述此 字段的字符串,包括其泛型类型。
StringtoString()返回描述此 字段的字符串。

三、利用反射获取成员方法

System.out.println("--------getMethods--------");  
Method[] methods = clazz.getMethods();  
for (Method method : methods) {  
    System.out.println(method);  
}  
System.out.println("--------getDeclaredMethods--------");  
Method[] declaredMethods = clazz.getDeclaredMethods();  
for (Method declaredMethod : declaredMethods) {  
    System.out.println(declaredMethod);  
}  
System.out.println("--------getMethod--------");  
Method setAge = clazz.getMethod("setAge",int.class);  
System.out.println(setAge.getModifiers());  
  
Method eat = clazz.getMethod("eat", String.class);  
Object invoke = eat.invoke(stu,"答辩");  
System.out.println(invoke.toString());

在获取方法的时候需要提供方法的形参,这是为了方法的重载

  成员方法的方法:

变量和类型方法描述
booleanequals(Object obj)将此 方法与指定的对象进行比较。
AnnotatedTypegetAnnotatedReturnType()返回一个 AnnotatedType对象,该对象表示使用类型来指定此可执行文件表示的方法/构造函数的返回类型。
<T extends Annotation>TgetAnnotation(类<T> annotationClass)返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。
Annotation[]getDeclaredAnnotations()返回 直接出现在此元素上的注释。
类<?>getDeclaringClass()返回表示声明此对象表示的方法的类或接口的 类对象。
ObjectgetDefaultValue()返回此 方法实例表示的注释成员的默认值。
Type[]getGenericExceptionTypes()返回 Type对象的数组, Type对象表示声明由此可执行对象引发的异常。
Type[]getGenericParameterTypes()返回一个 Type对象的数组, Type对象表示此对象表示的可执行文件的声明顺序的形式参数类型。
TypegetGenericReturnType()返回一个 Type对象,该对象表示此 方法对象表示的方法的正式返回类型。
StringgetName()返回此 方法对象表示的方法的名称,如 String 。
Annotation[][]getParameterAnnotations()返回 Annotation的数组数组,这些数组表示由此对象表示的 Executable声明顺序的形式参数的注释。
intgetParameterCount()返回此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明,或两者都不)。
类<?>getReturnType()返回一个 类对象,该对象表示此 方法对象表示的方法的正式返回类型。
TypeVariable<方法>[]getTypeParameters()返回的数组 TypeVariable对象表示通过此表示的一般声明声明的类型变量 GenericDeclaration目的,在声明的顺序。
inthashCode()返回此 方法的哈希 方法 。
Objectinvoke(Object obj, Object... args)在具有指定参数的指定对象上调用此 方法对象表示的基础方法。
booleanisBridge()如果此方法是桥接方法,则返回true ; 否则返回false 。
booleanisDefault()如果此方法是默认方法,则返回true ; 否则返回false 。
booleanisSynthetic()如果此可执行文件是合成构造,则返回true ; 否则返回false 。
booleanisVarArgs()如果声明此可执行文件采用可变数量的参数,则返回true ; 否则返回false 。
voidsetAccessible(boolean flag)将此反射对象的 accessible标志设置为指示的布尔值。
StringtoGenericString()返回描述此 方法的字符串,包括类型参数。
StringtoString()返回描述此 方法的字符串。

    可以使用invoke方法执行该成员方法



三、反射的作用

  ①获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
  ②结合配置文件,动态的创建对象并调用方法

四、练习

  一、保存信息

  
public class ReflectionDemo {  
    public static void main(String[] args) throws IOException, IllegalAccessException {  
        Student s = new Student("小A",23,"女",167.5,"睡觉");  
        Teacher t = new Teacher("波妞",10000);  
  
        saveObject(s);  
        saveObject(t);  
    }  
  
    private static void saveObject(Object obj) throws IllegalAccessException, IOException {  
        //利用反射获取类的所有信息  
        Class clazz = obj.getClass();  
  
        //创建io流  
        BufferedWriter bw = new BufferedWriter(new FileWriter("obj.txt",true));  
  
        //获取成员变量  
        Field[] fields = clazz.getDeclaredFields();  
        for (Field field : fields) {  
            field.setAccessible(true);  
            //获取成员变量的名字  
            String fieldName = field.getName();  
            //获取成员变量的值  
            Object o = field.get(obj);  
            //写出数据  
            bw.write(fieldName + " = " + o);  
            bw.newLine();  
        }  
        //关闭io流  
        bw.close();  
    }  
}

Student.java

  
public class Student {  
    private String name;  
    private int age;  
    private String gender;  
    private double height;  
    private String hobby;  
  
    public Student() {  
    }  
    public Student(String name, int age, String gender, double height, String hobby) {  
        this.name = name;  
        this.age = age;  
        this.gender = gender;  
        this.height = height;  
        this.hobby = hobby;  
    }  
  
    /**  
     * 获取     * @return name  
     */    public String getName() {  
        return name;  
    }  
  
    /**  
     * 设置     * @param name  
     */  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    /**  
     * 获取     * @return age  
     */    public int getAge() {  
        return age;  
    }  
  
    /**  
     * 设置     * @param age  
     */  
    public void setAge(int age) {  
        this.age = age;  
    }  
  
    /**  
     * 获取     * @return gender  
     */    public String getGender() {  
        return gender;  
    }  
  
    /**  
     * 设置     * @param gender  
     */  
    public void setGender(String gender) {  
        this.gender = gender;  
    }  
  
    /**  
     * 获取     * @return height  
     */    public double getHeight() {  
        return height;  
    }  
  
    /**  
     * 设置     * @param height  
     */  
    public void setHeight(double height) {  
        this.height = height;  
    }  
  
    /**  
     * 获取     * @return hobby  
     */    public String getHobby() {  
        return hobby;  
    }  
  
    /**  
     * 设置     * @param hobby  
     */  
    public void setHobby(String hobby) {  
        this.hobby = hobby;  
    }  
  
    public String toString() {  
        return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", height = " + height + ", hobby = " + hobby + "}";  
    }  
}

Teacher.java

  
public class Teacher {  
    private String name;  
    private int salary;  
  
    public Teacher() {  
    }  
    public Teacher(String name, int salary) {  
        this.name = name;  
        this.salary = salary;  
    }  
  
    /**  
     * 获取     * @return name  
     */    public String getName() {  
        return name;  
    }  
  
    /**  
     * 设置     * @param name  
     */  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    /**  
     * 获取     * @return salary  
     */    public int getSalary() {  
        return salary;  
    }  
  
    /**  
     * 设置     * @param salary  
     */  
    public void setSalary(int salary) {  
        this.salary = salary;  
    }  
  
    public String toString() {  
        return "Teacher{name = " + name + ", salary = " + salary + "}";  
    }  
}

  二、读取配置信息

  
public class ReflectionDemo {  
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {  
//        ./Day38/src/com/qcqc/javaStudy/Case2/prop.properties  
  
        //1.读取配置文件中的信息        Properties prop = new Properties();  
        prop.load(new FileInputStream("./Day38/src/com/qcqc/javaStudy/Case2/prop.properties"));  
  
        String className = (String) prop.get("class");  
        String methodName = (String) prop.get("method");  
  
        //获取class对象  
        Class clazz = Class.forName(className);  
        //创建对象  
        Object o = clazz.getConstructor().newInstance();  
        //调用方法  
        clazz.getMethod(methodName)  
        .invoke(o);  
  
  
    }  
}

配置文件

class=com.qcqc.javaStudy.Case2.Student  
method=study

五、小结