一、什么是反射

  反射允许对封装类的字段,方法和构造函数的信息进行编程访问
  
  
  
  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

五、小结