反射

80 阅读19分钟

1 反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性;

这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)

1.1 获取Class对象方式:

// 方式1 通过对象获取Class对象
Student stu = **new** Student();
Class  c1 = stu.getClass();
System.***out\***.println(c1);

// 方式2 直接根据类名获取
Class  c2 = Student.**class**;
Class  c4 = Student.**class**;

// 方式3 根据类的包名+类名的字符串获取 推荐
Class  c3 = Class.*forName*("com.qfedu.reflect.Studen");

// true 类的类对象是唯一的
System.***out\***.println(c1 ==  c2);
System.***out\***.println(c2 ==  c3);

1.2 常用方法

// 获取类中构造方法,公共的
getConstructors();
// 获取所有的构造方法,包括公开的私有的。。。
getDeclaredConstructors();
// 获取类中公开的方法,包括继承的父类的方法
getMethods();
c.getDeclaredMethods();

// 获取类中公开的属性
getFields();
getDeclaredFields();

public class ClassApp2 {

	public static void main(String[] args) throws ClassNotFoundException {
		// TODO Auto-generated method stub

		Class c = Class.forName("com.qfedu.reflect.Student");
		
		// 获取类中构造方法,公共的
		Constructor[] constructors = c.getConstructors();
		for(Constructor con : constructors) {
			System.out.println(con.getName());
		}
		System.out.println("----------------------");
		// 获取所有的构造方法,包括公开的私有的。。。
		Constructor[] declaredConstructors = c.getDeclaredConstructors();
		for(Constructor con : declaredConstructors) {
			System.out.println(con);
		}
		System.out.println("----------------------");
		// 获取类中公开的方法,包括继承的父类的方法
		Method[] methods = c.getMethods();
		for(Method m : methods) {
			System.out.println(m);
		}
		
		// c.getDeclaredMethods();
		
		System.out.println("----------------------");
		// 获取类中公开的属性
		Field[] fields = c.getFields();
		for(Field f : fields) {
			System.out.println(f);
		}
		
		Field[] fields2 = c.getDeclaredFields();
		for(Field f : fields2) {
			System.out.println(f);
		}		
	}
}

1.3 通过反射创建对象

public class ClassApp3 {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub

		Class c = Class.forName("com.qfedu.reflect.Student");
		
		// 通过Class对象 创建指定类的对象 ,相当于调用了默认的构造方法,创建了一个Student对象
		Object object = c.newInstance();
		
//		Student s = (Student)object;
//		s.setName("haha");
//		System.out.println(s.getName());
		
		// Method对象 是对方法信息的封装
		Method method = c.getMethod("setName", String.class);
		// 通过反射技术调用对象中的方法, 相当于  student.setName("zhangsan");
		// 第一个参数,类的对象(本例中object指的是Student的对象)
		// 第二个参数,给方法传的参数
		method.invoke(object, "zhangsan");
		
		Student s = (Student)object;
		System.out.println(s.getName());		
	}
}

2 Calendar类

常用方法:

获取日历对象:Calendar.getInstance()

获取年月日等信息: get()

设置年月日等信息:set()

日期的计算:add()

public class CalendarApp {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		// 获取日历类的对象
		Calendar calendar = Calendar.getInstance();
		System.out.println(calendar);
		// 年
		System.out.println(calendar.get(Calendar.YEAR));
		// 月  范围0-11   值+1,是真正的月份
		System.out.println(calendar.get(Calendar.MONTH) + 1);
		// 日
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
		// 时
		System.out.println(calendar.get(Calendar.HOUR));
		// 分
		System.out.println(calendar.get(Calendar.MINUTE));
		// 秒
		System.out.println(calendar.get(Calendar.SECOND));
		
		// 设置年月日时分秒
		calendar.set(2021, 4, 12, 13, 20, 20);
		System.out.println(calendar.get(Calendar.YEAR));
		// 具体设置某个属性
		calendar.set(Calendar.MONTH, Calendar.MARCH);
		
		System.out.println(calendar.get(Calendar.MONTH));
				
		System.out.println("---------------------------");
		
		// 日历类 -》 Date
		Date date = calendar.getTime();
		System.out.println(date);
		// Date -> Calendar
		Date date2 = new Date(1615969254000L);
		calendar.setTime(date2);
		System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
		
		System.out.println("-----------------");
		// 针对具体的属性 加减运算
		calendar.add(Calendar.MONTH, 1);
		System.out.println(calendar.get(Calendar.MONTH));
		
		calendar.add(Calendar.HOUR_OF_DAY, -1);
		System.out.println(calendar.get(Calendar.HOUR_OF_DAY));		
	}
}

反射方法

1.Constructor

1.1 获取公开的构造器

获取类信息对象中所有的public修饰的构造方法

getConstructor(Class<?>... parameterType) 根据参数列表获取到一个public修饰的构造器对象

getConstructors() 获取到所有的public修饰的构造器对象

package com.qfedu.test1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 	通过反射获取类对象
 * 
 * 	获取类信息对象中所有的public修饰的构造方法
 * 	getConstructor(Class<?>... parameterType) 根据参数列表获取到一个public修饰的构造器对象
 * 	getConstructors() 获取到所有的public修饰的构造器对象
 * @author WHD
 *
 */
public class Test1 {
	public static void main(String[] args) {
		// 包名 + 类名 称之为 全限定名 com.qfedu.test1.Student
		try {
			Class<?> stuClass = Class.forName("com.qfedu.test1.Student");
			
			Constructor<?>[] cons = stuClass.getConstructors();
			
			for (Constructor<?> con : cons) {
				System.out.println(con.getName() + "----" + con.getParameterCount());
			}
			
			Constructor<?> con1 = stuClass.getConstructor();
			
			Object obj1 = con1.newInstance();
			
			if(obj1 instanceof Student) {
				Student stu1 = (Student) obj1;
				stu1.setName("赵四");
				stu1.setAge(20);
				System.out.println(stu1);
			}
			
			Constructor<?> con2 = stuClass.getConstructor(String.class,int.class);
			
			Object obj2 = con2.newInstance("广坤",17);
			
			if(obj2 instanceof Student ) {
				Student stu2 = (Student) obj2;
				System.out.println(stu2);
			}
			
			Constructor<?> con3 = stuClass.getConstructor(int.class,String.class);
			
			Object obj3 = con3.newInstance(17,"大拿");
			
			if(obj3 instanceof Student) {
				Student stu3 = (Student) obj3;
				System.out.println(stu3);
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}

1.2 获取所有的构造器

getDeclaredConstructor(Class<?>... parameterType) 根据形参列表获取某一个任意修饰符修饰的构造器

getDeclaredConstructors() 获取所有已定义的任意修饰符修饰的构造器

package com.qfedu.test1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 	getDeclaredConstructor(Class<?>... parameterType) 根据形参列表获取某一个任意修饰符修饰的构造器
 * 	getDeclaredConstructors() 获取所有已定义的任意修饰符修饰的构造器
 * @author WHD
 *
 */
public class Test2 {
	public static void main(String[] args) {
		try {
			// 通过包名+类名 获取到类对象 
			Class<?> stuClass = Class.forName("com.qfedu.test1.Student");
			
			// 获取所有已定义构造器
			Constructor<?>[] cons = stuClass.getDeclaredConstructors();
		
			// 遍历数组
			for (Constructor<?> con : cons) {
				System.out.println(con.getName() + "---" + con.getParameterCount());
			}
			
			// 获取单个的已定义的<默认修饰符>修饰的构造器
			Constructor<?> con1 = stuClass.getDeclaredConstructor(String.class);
			
			// 根据获取到构造器对象 调用newInstance方法创建对象
			Object obj1 = con1.newInstance("赵四");
			
			// 进行类型判断
			if(obj1 instanceof Student) {
				Student stu = (Student) obj1;
				System.out.println(stu);
			}
			
			// 获取单个的已定义的<私有修饰符>修饰的构造器
			Constructor<?> con2 = stuClass.getDeclaredConstructor(int.class);
			
			// 设置con2构造器对象为可以访问 忽略调JVM的安全检查
			con2.setAccessible(true); // 设置为可访问 
			
			// 创建对象
			Object obj2 = con2.newInstance(17);
			
			//类型判断
			if(obj2 instanceof Student) {
				Student stu = (Student) obj2;
				System.out.println(stu);
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}

2. Field

2.1 获取公开的字段

使用反射获取public修饰的属性

getFiled(String filedName) 根据字段名称获取一个public修饰的属性

getFileds() 获取所有的public修饰的属性 返回值为Field数组

package com.qfedu.test2;

import java.lang.reflect.Field;

/**
 * 	使用反射获取public修饰的属性
 * 	getFiled(String filedName) 根据字段名称获取一个public修饰的属性
 * 	getFileds() 获取所有的public修饰的属性 返回值为Field数组
 * @author WHD
 *
 */
public class Test1 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		Class<?> stuClass = Class.forName("com.qfedu.test2.Student");
		
		Field[] fields = stuClass.getFields();
		
		for (Field f : fields) {
			System.out.println(f.getName() + "---" +  f.getType());
		}
		
		// 根据名字获取某一个public修饰的字段/属性/实例变量
		Field nameField = stuClass.getField("name");
		
		// 根据Class类提供的方法 来获取学生对象
		Object obj1 = stuClass.newInstance(); // Student stu = new Student();
		
		// 对字段对象赋值
		nameField.set(obj1, "赵四"); // stu.setName("赵四");
		
		// 取值
		System.out.println(nameField.get(obj1)); // stu.getName();
	}
}

2.2 获取所有的字段

获取已定义的字段

getDeclaredField(String name) 获取单个任意修饰符修饰的字段

getDeclaredFields() 获取所有任意修饰符修饰的字段

package com.qfedu.test2;

import java.lang.reflect.Field;

/**
 * 	获取已定义的字段
 * 	getDeclaredField(String name) 获取单个任意修饰符修饰的字段 
 * 	getDeclaredFields() 获取所有任意修饰符修饰的字段
 * @author WHD
 *
 */
public class Test2 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		Class<?> stuClass = Class.forName("com.qfedu.test2.Student");// shift + alt + L
		
		Field[] fields = stuClass.getDeclaredFields(); // shift + alt + L
		
		for (Field f : fields) {
			System.out.println(f.getName() + "---" + f.getType());
		}
		
		// 获取单个的非public修饰的属性
		Field field1 = stuClass.getDeclaredField("sex");
		
		// 使用Class类调用无参构造创对象
		Object obj1 = stuClass.newInstance();
		
		// 设置值
		// 第一个参数 表示要设置的字段属于哪个对象
		// 第二个参数 字段值
		field1.set(obj1, "男");
		
		// 获取值
		System.out.println(field1.get(obj1));
		
		
		// 获取private修饰的字段
		Field field2 = stuClass.getDeclaredField("weight");
		
		field2.setAccessible(true);
		
		field2.set(obj1, 75.5);
		
		System.out.println(field2.get(obj1));	
	}
}

3. Method

3.1 获取公开的以及继承的方法

获取public修饰的方法

getMethods() 获取所有的public修饰的,以及从父类继承的方法

getMethod(String name,Class<?>... paratemerType)根据方法名称和参数列表获取到一个public

修饰的方法

package com.qfedu.test3;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 	获取public修饰的方法
 * 	getMethods() 获取所有的public修饰的,以及从父类继承的方法
 * 	getMethod(String name,Class<?>... paratemerType)根据方法名称和参数列表获取到一个public
 * 	修饰的方法
 * @author WHD
 *
 */
public class Test1 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Class<?> stuClass = Class.forName("com.qfedu.test3.Student");
		
		Method[] methods = stuClass.getMethods();
		
		for (Method m : methods) {
			System.out.println(m.getName() + "---" + m.getParameterCount());
		}
		
		// 获取单个的方法
		Method method1 = stuClass.getMethod("m1");
		
		Object obj1 = stuClass.newInstance();
		
		method1.invoke(obj1);
		
		
		Method method2 = stuClass.getMethod("m1", String.class,int.class);
		
		method2.invoke(obj1, "hello",20);
	}
}
package com.qfedu.test3;

public class Student {
	public void m1() {
		System.out.println("public修饰的m1方法  无参的");
	}
	
	public void m1(String str,int num) {
		System.out.println("public修饰的m1方法  有参数的String,int" + str + num);
	}
	
	public void m2(){
		System.out.println("public修饰的m2方法");
	}
	
	void m3() {
		System.out.println("包级别访问权限的m3方法");
	}
	
	private void m4() {
		System.out.println("私有级别的m4方法");
	}
	
	private void m4(float num) {
		System.out.println("私有级别的m4方法  float参数" + num);
	}
}

3.2 获取所有的方法

获取已定义的方法(不包含继承的方法)

getDeclaredMethod(String name,Class<?>...parameterType) 获取单个已定义的方法

getDeclaredMethods() 获取所有已定义的方法

package com.qfedu.test3;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 	获取已定义的方法(不包含继承的方法)
 * 	getDeclaredMethod(String name,Class<?>...parameterType) 获取单个已定义的方法
 * 	getDeclaredMethods() 获取所有已定义的方法
 * @author WHD
 *
 */
public class Test2 {
	public static void main(String[] args) {
		try {
			Class<?> stuClass = Class.forName("com.qfedu.test3.Student");
			
			Method[] methods = stuClass.getDeclaredMethods();
			
			for (Method m : methods) {
				System.out.println(m.getName() + "----" + m.getParameterCount());
			}
			
			// 获取单个的方法
			Method m1 = stuClass.getDeclaredMethod("m3");
			
			Object obj1 = stuClass.newInstance();
			
			m1.invoke(obj1);
			
			
			Method m2 = stuClass.getDeclaredMethod("m4",float.class);
			
			m2.setAccessible(true); 
			
			m2.invoke(obj1, 3.14F);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}

3. 反射再识

3.1 Java类和Java文件的关系
Java中的类,一定会存在于Java文件中。
【重点】
	Java文件包含对应类的所有内容。
   
定义类的格式:
	class 类名 {
		成员变量;
		构造方法;
		成员方法;
	}

3.2 .class文件和Java文件的关系
Java文件 ==> Javac.exe 编译之后 ==> .class 字节码文件/二进制文件
【重点】
	.class文件中包含Java中的类所有内容
	.class字节码文件中会包含当前 类 所有参与代码编译和执行的内容,不包括注释

3.3 类文件加载做什么
在Java程序运行之前,将.class字节码文件,加载到内存的【方法区】
【重点】
	在内存方法区中,.class文件占用的空间,包含.class对应的所有内容。
	代码执行过程中,需要使用对应类的内容(成员变量,成员方法,构造方法,类型提供),都要使用内存【方法区】.class文件占用的空间。

3.4 .class字节码文件占用的内存空间和Java类有什么关系???
.class字节码文件在内存【方法区】占用空间,是Java类对应内容的完整映射。
	一个是程序员可以看懂,一个是计算机可以看懂。

成员变量看作一个类,你认为有什么属性?
	1. 数据类型 [核心] Type
	2. 变量名 【重点核心】 name
	3. 数据内容
	4. 权限修饰标记
	5. 静态标记
	6. final标记

成员方法看作是一个类,有什么属性?
	1. 权限修饰标记
	2. 静态标记
	3. 返回值类型 [核心]
	4. 方法名 【核心重点】
	5. 形式参数列表 [核心]
	6. 方法体

构造方法看做是一个类,有什么属性?
	1. 权限修饰标记
	2. 类名 [核心]
	3. 形式参数列表 【核心重点】
	4. 方法体
	
类也是一个类
	Field[] 成员变量数组
	Constructor[] 构造方法数组
	Method[] 成员方法数组
实操案例
	文件存储数据 
		className=com.qfedu.entity.Person
		[id:1,name:苟磊,age=16,gender=false]
		[id:2,name:狗鸽,age=16,gender=false]	
    1. 从文件中读取数据
    2. 字符串解析
    3. 通过反射获取指定名字的成员变量 Field对象
    4. 通过该Field对象数据类型,转换 String 数据 到对应数据类型从【字符串转任意类型的转换器】
    5. 生成一个 Person 类对象

4.1 复习

Java的类 ==> Java文件 ==> javac.exe ==> .class文件 ==> 加载 ==> 内存方法区有一块空间对应 .class文件
内存方法区 .class字节码文件占用的内存空间 ==> 对应 整个Java类,包含对应Java类的所有内容。

类也是一个类 Class类型 ==> 完整的类名 包名.类名
成员变量是一个类 Field类 ==> 变量名
成员方法是一个类 Method类 ==> 方法名 参数
构造方法是一个类 Constructor类 ==> 参数

1.2 万恶之源 -- Class类
Class类 是针对Java中所有类对应总结
	Class类对应的对象 ===> 每一个类在内存方法区.class文件占用的内存空间 就是Class对象。
	Person.java ===> Person.class ==> 加载到内存【方法区】 ==> Class<Person>对象

获取Class对象对应的方法:
	Class Class.forName(String packageAndClassName);
		根据提供的包名.类名获取对应类的Class对象
		【特殊功能】可以用于加载指定包名.类名对应的类
		【常用用途】指定类型获取,指定类型加载
		例如:
			Class cls = Class.forName("com.qfedu.entity.Student");
			Student.java ==> Student.class
	
	Class getClass();
		通过类对象调用,获取当前对象对应的Class对象
		【常用用途】用于获取类对象对应类型,参与判断
		例如:
			Student stu = new Student();
			Class cls = stu.getClass();
	
	Class 类名.class;
		通过类名,获取当前类Class对象,或者可以理解为获取当前类的Class属性
		【常用用途】用于约束方法参数类型。
		例如:
			Class cls = Student.class;
package com.qfedu.a_reflect;

/*
 * 获取Class对象方法演示
 * 
 * 异常说明:
 * 		ClassNotFoundException 指定类未找到异常
 */
public class GetClassObject {
	public static void main(String[] args) throws ClassNotFoundException {
		/*
		 * 根据指定包名.类名 获取对应类的Class对象
		 */
		Class<?> cls1 = Class.forName("com.qfedu.a_reflect.Person");
		
		/*
		 * 通过类对象,获取对应数据类型 Class对象
		 */
		Person person = new Person();
		Class<? extends Person> cls2 = person.getClass();
		
		/*
		 * 根据类名获取 Class对象。 或者说,根据类名获取Class属性
		 */
		Class<Person> cls3 = Person.class;
		
		/*
		 * 杰总 20遍 三个 true
		 * 
		 * 问题:
		 * 		一个类加载几次??? 
		 * 			一次
		 * 		类加载一次的情况下,占用的内存【方法区】空间是否也是一次???
		 * 			一次
		 * 		Class对象是对应当前.class字节码文件在内存方法区中的占用空间对象。
		 * 
		 * 不管通过哪一种方式获取的Class对象,类相同的情况下,都是同一个对象
		 */
		System.out.println("cls1 == cls2 : " + (cls1 == cls2));
		System.out.println("cls2 == cls3 : " + (cls2 == cls3));
		System.out.println("cls1 == cls3 : " + (cls1 == cls3));
	}
}

1.3 通过Class对象获取Constructor构造方法对象

1.3.1 获取Constructor分析
构造方法:
	具有唯一性的内容是什么???
		方法名??? No 可以存在多个构造方法,名称都一样,都是类名。
		参数类型,个数,顺序是不是唯一性???
			唯一!!!
	
	方法的重载!!!reload
	在一个类内,允许出现同名方法,但是要求方法对应的参数必须不一致!!!

获取构造方法,需要根据构造方法的数据类型,个数,顺序来获取!!!

Objects.hash(Object... value);

1.3.2 获取Constructor相关方法
Constructor[] getConstructors();
	获取当前Class对象中,所有非私有化构造方法 Constructor 对象数组

Constructor[] getDeclaredConstructors();
	【暴力反射】
	获取当前Class对象中,所有构造方法 Constructor 对象数组,包括私有化构造方法对象。

Constructor getConstructor(Class... parameterTypes);
	参数解释:
		Class... parameterTypes
		不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
	根据指定的参数类型,获取对应非私有化构造方法 Constructor 对象
	例如:
		Constructor con1 = cls.getConstructor();
		con1 ==> public Person() 无参数构造方法
		Constructor con2 = cls.getConstructor(int.class, String.class);
		con2 ==> public Person(int, String); 对应的构造方法参数为 int,String 类型
	
Constructor getDeclaredConstructor(Class... parameterTypes);
	【暴力反射】
	参数解释:
		Class... parameterTypes
		不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
	根据指定的参数类型,获取对应构造方法 Constructor 对象,包括私有化构造方法。
	例如:
		Constructor con1 = cls.getDeclaredConstructor(String.class);
		con1 ==> private Person(String); 私有化参数类型为String类型的构造方法。
package com.qfedu.a_reflect;

import java.lang.reflect.Constructor;

/*
NoSuchMethodException 指定方法不存在异常
SecurityException 安全异常
 */
public class GetConstructorObject {
	public static void main(String[] args) 
			throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		/*
		 * 有请万恶之源
		 */
		Class cls = Class.forName("com.qfedu.a_reflect.Person");
		
		/*
		Constructor[] getConstructors();
			获取当前Class对象中,所有非私有化构造方法 Constructor 对象数组
		 */
		Constructor[] constructors = cls.getConstructors();
		for (Constructor constructor : constructors) {
			System.out.println(constructor);
		}
		
		System.out.println();
		
		/*
		Constructor[] getDeclaredConstructors();
			【暴力反射】
			获取当前Class对象中,所有构造方法 Constructor 对象数组,包括私有化构造方法对象
		 */
		Constructor[] declaredConstructors = cls.getDeclaredConstructors();
		for (Constructor constructor : declaredConstructors) {
			System.out.println(constructor);
		}
		
		System.out.println();
		/*
		Constructor getConstructor(Class... parameterTypes);
			参数解释:
				Class... parameterTypes
				不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
			根据指定的参数类型,获取对应非私有化构造方法 Constructor 对象
		 */
		Constructor con1 = cls.getConstructor();
		Constructor con2 = cls.getConstructor(int.class);
		Constructor con3 = cls.getConstructor(int.class, String.class);
		System.out.println(con1);
		System.out.println(con2);
		System.out.println(con3);
		
		/*
		Constructor getDeclaredConstructor(Class... parameterTypes);
			【暴力反射】
			参数解释:
				Class... parameterTypes
				不定长参数,参数类型是Class类型,用于约束当前构造方法对应的数据类型是什么
			根据指定的参数类型,获取对应构造方法 Constructor 对象,包括私有化构造方法。
	
		 */
		Constructor con4 = cls.getDeclaredConstructor(String.class);
		System.out.println(con4);
	}
}

1.3.3 通过Constructor对象创建类对象
Object newInstance(Object... parameterValues);
	参数解释
		Object... parameterValues
		当前构造方法所需的实际参数,要求传入的参数和对应参数类型一致,【类型一致,顺序一致,个数一致】
		Object... 可以支持任意类型,同时支持任意个数
	通过该Constructor对象调用,创建Constructor对应类的对象
	例如:
		Constructor对象是 Person类,通过调用newInstance创建的对象,也就是Person对象。返回值Object类型
		只是为了数据统一操作,可以通过强制类型转换或者泛型约束,明确类型。

1.4 通过Class对象获取Method成员方法对象

1.4.1 获取Method对象分析
Method 成员方法在调用过程中
	1. 方法名字
	2. 对应当前方法的数据类型[参数个数,参数类型,参数顺序]
	明确一个方法所需的内容就是方法名+参数列表

1.4.2 获取Method相关方法
Method[] getMethods();
	获取类内所有非私有化方法,并且包含从父类继承而来子类可以使用的非私有化成员方法。
	
Method[] getDeclaredMethods();
	【暴力反射】
	获取类内所有的本类自有方法,包含私有化方法,但是不包括继承而来父类的非私有化方法。
	
Method getMethod(String methodName, Class... parameterTypes);
	参数解释:
		String methodName 指定方法的名字
		Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
	根据用户指定的方法名称,和对应的参数类型,获取类内指定非私有化成员方法。
	例如:
		Method method1 = cls.getMethod("game");
		method1 ==> public 待定 game();
		Method method2 = cls.getMethod("game", String.class);
		method2 ==> public 待定 game(java.lang.String);
		
Method getDeclaredMethod(String methodName, Class... parameterTypes);
	【暴力反射】
	参数解释:
		String methodName 指定方法的名字
		Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
	根据用户指定的方法名称,和对应的参数类型,获取类内指定成员方法。包括私有化方法。
	例如:
		Method method1 = cls.getMethod("testPrivate");
		method1 ==> private 待定 testPrivate();
		Method method2 = cls.getMethod("testPrivate", String.class);	
        method2 ==> private 待定 testPrivate(java.lang.String);
package com.qfedu.a_reflect;

import java.lang.reflect.Method;

/*
 * 通过Class对象获取对应类的 Method 成员方法对象演示
 */
@SuppressWarnings("all")
public class GetMethodObject {
	public static void main(String[] args) 
			throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		Class cls = Class.forName("com.qfedu.a_reflect.Person");
		
		/*
		Method[] getMethods();
				获取类内所有非私有化方法,并且包含从父类继承而来子类可以使用的非私有化成员方法。
		 */
		Method[] methods = cls.getMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
		
		System.out.println();
		
		/*
		Method[] getDeclaredMethods();
			【暴力反射】
			获取类内所有的本类自有方法,包含私有化方法,但是不包括继承而来父类的非私有化方法。
		 */
		Method[] declaredMethods = cls.getDeclaredMethods();
		for (Method method : declaredMethods) {
			System.out.println(method);
		}
		System.out.println();
		
		/*
		Method getMethod(String methodName, Class... parameterTypes);
			参数解释:
				String methodName 指定方法的名字
				Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
			根据用户指定的方法名称,和对应的参数类型,获取类内指定非私有化成员方法。
		 */
		Method method1 = cls.getMethod("game");
		Method method2 = cls.getMethod("game", String.class);
		System.out.println(method1);
		System.out.println(method2);
		System.out.println();
		
		/*
		Method getDeclaredMethod(String methodName, Class... parameterTypes);
			【暴力反射】
			参数解释:
				String methodName 指定方法的名字
				Class... parameterTypes 对应当前方法的参数类型,不定长参数,Class类型约束
			根据用户指定的方法名称,和对应的参数类型,获取类内指定成员方法。包括私有化方法。
		 */
		
		Method declaredMethod1 = cls.getDeclaredMethod("testPrivate");
		Method declaredMethod2 = cls.getDeclaredMethod("testPrivate", String.class);
		System.out.println(declaredMethod1);
		System.out.println(declaredMethod2);
	}
}

1.4.3 Method对象执行对应方法
方法调用格式:
	类对象.方法名(实际参数);
	类名.方法名(实际参数);

目前已经得到了 Method 对象 ==> 方法
运行/执行当前方法缺什么???
	1. 谁调用? 类对象/类名
	2. 实际参数

Method执行方法操作
	Object invoke(Object obj, Object... parameterValues);
    参数解释:
    	Object obj 执行当前方法使用的对应类对象
    	Object... parameterValues 当前方法执行所需的实际参数
    Method类对象调用执行 invoke 方法,执行当前Method对应方法内容
    
    【补充】
    	静态成员方法在使用Method方法执行过程中,推荐在调用者位置提供一个当前类对象,明确方法执行的参数问题,
    	明确方法执行的调用者问题。
Object obj = cls.getConstructor().newInstance();                            
method1.invoke(obj);                                                        
method2.invoke(obj, "World Of Tank");                                       
System.out.println();                                                       
                                                                            
declaredMethod1.setAccessible(true);                                        
declaredMethod1.invoke(obj);                                                
declaredMethod2.setAccessible(true);                                        
declaredMethod2.invoke(obj, "猕猴桃");                                         
                                                                            
cls.getMethod("test").invoke(obj); // 静态成员方法通过类对象调用,在语法层面没有任何错误             
cls.getMethod("test").invoke(null); // null 表示未提供任何的调用对象,有且只允许在static修饰方法中使用

1.5 通过Class对象获取Field成员变量对象

1.5.1 获取 Field 对象分析
使用成员变量过程中,操作成员变量
	1. 变量名
	2. 比较关注 变量对应的数据类型。

1.5.2 获取 Field 相关方法
Field[] getFields();
	 获取当前类内所有非私有化成员变量Field对象数组。
	 
Field[] getDeclaredFields();
	【暴力反射】
	获取当前类内所有成员变量,包括私有化成员变量。【常用】
	
Field getField(String fieldName);
	根据指定的成员变量名称,获取对应的非私有化成员变量Field对象
	
Field getDeclaredField(String fieldName);
	【暴力反射】
	根据指定的成员变量名称,获取对应成员变量Field对象,包括私有化成员变量对象
package com.qfedu.a_reflect;

import java.lang.reflect.Field;

/*
 * 通过Class对象获取对应类的Field成员变量对象演示
 */
public class GetFieldObject {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
		/*
		 * 万恶之源
		 */
		Class cls = Class.forName("com.qfedu.a_reflect.Person");
		
		Field[] fields = cls.getFields();
		
		for (Field field : fields) {
			System.out.println(field);
		}
		System.out.println();
		
		Field[] declaredFields = cls.getDeclaredFields();
		for (Field field : declaredFields) {
			System.out.println(field);
		}
		System.out.println();
		
		Field field1 = cls.getField("test");
		Field field2 = cls.getField("testStatic");
		System.out.println(field1);
		System.out.println(field2);
		System.out.println();
		
		Field declaredField1 = cls.getDeclaredField("id");
		Field declaredField2 = cls.getDeclaredField("name");
		System.out.println(declaredField1);
		System.out.println(declaredField2);
	}
}

1.5.3 Field 对象操作对应方法
操作成员变量的方式
	类对象.set成员变量名(对应成员变量数据类型参数);
		赋值操作:
			1. 明确是哪一个类对象的成员变量
			2. 对应当前成员变量数据类型的实际参数
	对应当前成员变量参数 类对象.get成员变量名();
    	取值操作:
    		明确是哪一个类对象的成员变量

void set(Object obj, Object value);
	【赋值操作】
	obj 是对应哪一个类对象,value 是对应当前成员变量赋值使用的数据
Object get(Object obj);
	【取值操作】
	obj 是对应哪一个类对象,返回值是当前成员变量存储的数据。

String getName();
	获取成员变量的名称
Class<?> getType();
	获取成员变量的数据类型,返回值是Class类型。

1.6 暴力反射授权
Constructor/Field/Method ==> setAccessible(boolean flag);
	给予一个反射对象进行权限赋值操作,可以用于【私有化】构造方法,成员方法和成员变量权限授予操作。
	主要的操作都是针对于 成员变量

class AccessibleObject
static void setAccessible(AccessibleObject[] arr, boolean flag);
	class Constructor extends AccessibleObject
	class Field extends AccessibleObject	
	class Method extends AccessibleObject	
	给予AccessibleObject数组所有元素,进行权限授予操作,AccessibleObject可以存储ConstructorFieldMethod,批量操作。
	主要的操作都是针对于 成员变量