一、反射的引出
通常的正向处理:先有类,再根据类创建对象(根据包名.类名找到类)
范例:

import java.util.Date;
public class ReflectTest {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date);//输出系统当前时间
    }
}

而反射是根据现有对象倒推类的组成
反射的最核心:Class类(专门描述其他类的组成)
任何一个类在JVM中只有唯一的一个class对象,此对象记录该类的组成结构。当类加载时由JVM产生,用户只能取得此对象无法创建。

二、应用反射

  • 要想在java中应用反射,首先取得该类的class对象

1.取得任意类class对象方法:

1)调用Object提供的getClass方法
即调用对象.getClass()取得Class对象
2).类名称.class取得Class对象
3).调用Class类提供的静态方法Class.forName(类的全名称)取得Class对象;
范例:

public class reflectStartTest {
    public static void main(String[] args) throws Exception{
        Date date=new Date();
        System.out.println(date);//----->Sun Mar 31 10:03:24 CST 2019
        //1.调用对象.getClass()
        System.out.println(date.getClass());
        //2.类名称.class
        System.out.println(Date.class);
        //3.调用Class.forName()
        System.out.println(Class.forName("java.util.Date"));
        //---->class java.util.Date

        System.out.println(int.class);//----> int
        System.out.println(Integer.class);//---->class java.lang.Integer
    }
}

2.拿到一个类的class对象后,就可以对该类进行以下操作
1).创建该类的新对象
public T newInstance():通过反射实例化对象,使用类中的无参构造进行对象的创建

Class<Date> cls = Date.class;
//用过反射产生Date类的对象
//等同于 Date date = new Date();正向产生对象
Date date = cls.newInstance();
System.out.println(date);

2).取得包名、父类、父接口
a. Package:描述一个类的包信息
Class类提供的getPackage()方法

Class<Test> cls = Test.class;
System.out.println(cls.getPackage().getName());

b. 取得一个类的父类信息:Class
Class类提供的getSuperclass()方法

Class<Test> cls = Test.class;
System.out.println(cls.getSuperclass().getName());

c. 取得一个类的所有父接口
Class类提供的getInterface()方法,返回值是一个Class数组

interface  IMessage{}
interface  INews{}
class MyClass implements  IMessage,INews{}
public class Test {    
   public static void main(String[] args) throws Exception { 
          Class<Test> cls = Test.class;
          Class[] classes = MyClass.class.getInterfaces();   
           for(Class cls1:classes){
                    System.out.println(cls1);
            }
        }
  }

3.取得构造方法、普通方法、普通属性
constructor.setAccessible(true);//动态破坏封装,仅在一次JVM进程中
3.1 Constructor:描述一个类的构造方法
1)取得本类中指定参数的构造方法
Class类中提供的getConstructor(参数):只能取得权限为public的构造方法
Class类中提供的getDeclaredConstructor(参数):可以取得类中所有的构造方法,与权限无关

Class<Person> cls = Person.class;
Constructor constructor = cls.getDeclaredConstructor(Integer.class,String.class);  
  System.out.println(constructor);

2)取得本类中所有构造方法
Class类中提供的getConstructors():只能取得权限为public的构造方法
Class类中提供的getDeclaredConstructors():可以取得类中所有的构造方法,与权限无关

Class<Person> cls = Person.class;
Constructor[] constructors = cls.getDeclaredConstructors();
for(Constructor constructor:constructors){
    System.out.println(constructor);
}

3)作用:创建对象:
Class类的newInstance()实际上调用的是类中的无参构造,如果类中没有无参构造或者权限不是public,此方法无法使用!建议:以后在定义简单java类时,一定要保留一个无参构造.
当类中没有无参构造时,就调用Constructor类提供的newInstance方法使用有参构造来实例化对象 。public T newInstance(Object… initargs)

class Person{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class ReflectConstructorTest {
    public static void main(String[] args) throws Exception {
        Class<?> cls=Person.class;//取得class对象
        Constructor<?> constructors=cls.getConstructor(String.class,int.class);
    //调用Constructor类提供的newInstance方法使用有参构造来实例化对象
        System.out.println(constructors.newInstance("zhangsan",18));

    }

3.2 Method:描述一个类的普通方法
1)取得类中所有方法
a.取得本类以及父类中的所有权限为public的普通方法(包含静态方法)

public Method[] getMethods() throws SecurityException

b. 只能取得本类中所有方法(包含private方法)

public Method[] getDeclaredMethods() throws SecurityException

2)取得类中指定名称与参数的普通方法

public Method getMethod(String name,Class<?>...parameterTypes)

public Method getDeclaredMethod(String name,Class<?>...parameterTypes)

3)作用:Method类提供的反射调用普通方法

/**
  *反射调用普通方法
  *obj类的实例化对象
  *args 普通方法的参数
  */
public Object invoke(Object obj,Object...args)


class Person {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}
public class Test {
    public static void main(String[] args) throws Exception {
        //正向处理,调用getter和setter
//        Person per = new Person();
//        per.setName("张三");
//        System.out.println(per.getName());
        //-------------利用反射调用方法-----------------------------
        //1.先取得class对象
        Class<Person> cls = Person.class;
        //2.组装方法名称
        String setMethodName = "set"+initCap(args[0]);
        String getMethodName = "get"+initCap(args[0]);
        //3.取得Method对象
        Method setMethod = cls.getMethod(setMethodName,String.class);
        Method getMethod = cls.getMethod(getMethodName);
        //4.取得Person类实例化对象而后调用方法
        Person per = cls.newInstance();
        setMethod.invoke(per,"张三");
        System.out.println(getMethod.invoke(per));
    }
    //首字母大写方法
    private static String initCap(String str){
        return str.substring(0,1).toUpperCase()+str.substring(1);
    }
}

3.3 Field:描述一个类的普通属性
1)取得类中指定名称属性

public Field getField(String name)

public Field getDeclaredField(String name)

2)取得类中所有属性(同Method)

public Field[] getFields() throws SecurityException   ---->取得本类以及父类中的所有权限为public的普通方法(包含静态方法)

public Field[] getDeclaredFields() throws SecurityException   ----->只能取得本类中所有方法(包含private方法)

3)Field类提供的设置与取得属性值
a.设置值

/**
* 设置属性值
* @param obj 类的实例化对象
* @param value 要设置的值
*/
public void set(Object obj,Object value)

b.取得值

/**
* 取得属性值
* @param obj 类的实例化对象
*/
public Object get(Object obj)

c.取得属性类型

/**
  * 取得属性类型
  * @return
  */
public Class<?> getType()

eg:

class Person {
    public int age ;
}
public class Test {
    public static void main(String[] args) throws Exception {
        Class<Person> cls = Person.class;
        Field field = cls.getField("age");
        Person per = cls.newInstance();
        field.set(per,20);
        System.out.println(field.get(per));
        System.out.println(field.getType());
    }
}  ----->20  int

3.4动态破坏封装(反射的特性)-只在一次JVM进程中,不是永久破坏,只能通过反射调用
Constuctor、Method、Field类都继承AccessibleObject类
此类中有一个破坏封装的方法:

public void setAccessible(boolean flag) throws SecurityException

nameField.setAccessible(true);//取消封装