package com.app.d2_reflect_class;
public class Student {
}
package com.app.d2_reflect_class;
/**
目标:学习反射第一步:获取Class类的对象的方式
*/
public class Test {
public static void main(String[] args) throws Exception {
// 1、Class类中的一个静态方法:forName(全限名:包名 + 类名)
Class c1 = Class.forName("com.app.d2_reflect_class.Student");
System.out.println("c1 = " + c1);
// 2、类名.class
Class c2 = Student.class;
System.out.println("c2 = " + c2);
// 3、对象.getClass():获取对象对应类的Class对象
Student stu = new Student();
Class c3 = stu.getClass();
System.out.println("c3 = " + c3);
}
}
c1 = class com.app.d2_reflect_class.Student
c2 = class com.app.d2_reflect_class.Student
c3 = class com.app.d2_reflect_class.Student
Process finished with exit code 0
方法名称 | 说明 |
---|---|
Constructor< ? >[] getConstructors() | 返回所有构造器对象的数组(只能拿public的) |
Constructor< ? >[] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
Constructor< T > getConstructor(Class< ? >… parameterTypes) | 返回单个构造器对象(只能拿public的) |
Constructor< T > getDeclaredConstructor(Class< ? >… parameterTypes) | 返回单个构造器对象,存在就能拿到 |
package com.app.d3_reflect_constructor;
/**
学生类
*/
public class Student {
private String name;
private int age;
public Student() {
System.out.println("无参构造器执行");
}
public Student(String name, int age) {
System.out.println("有参数构造器执行");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.app.d3_reflect_constructor;
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
目标:学习使用反射技术获取构造器对象并使用
*/
public class TestStudent01 {
// 第一步:获取类对象
public static Class c = Student.class;
/**
getConstructors:
获取所有public修饰的构造器对象(只能拿有public修饰的)
*/
@Test
public void getConstructors() {
System.out.println("1. 获取所有public修饰的构造器对象:");
// 第二步:返回所有public修饰的构造器对象的数组
Constructor[] constructors = c.getConstructors();
// 第三步:遍历所有public修饰的构造器对象的数组
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());
}
System.out.println();
}
/**
getDeclaredConstructors:
获取所有构造器对象
*/
@Test
public void getDeclaredConstructors() {
System.out.println("2. 获取所有构造器对象:");
// 第二步:返回所有构造器对象的数组
Constructor[] declaredConstructors = c.getDeclaredConstructors();
// 第三步:遍历所有构造器对象的数组
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor.getName() + " ---> " + declaredConstructor.getParameterCount());
}
System.out.println();
}
/**
getConstructor:
获取某个有public修饰的构造器对象(只能拿public修饰的)
*/
@Test
public void getConstructor() throws Exception {
System.out.println("3. 获取某个有public修饰的构造器对象:");
// 第二步:获取某个有public修饰的无参数构造器对象
System.out.println("获取有public修饰的无参数构造器对象:");
Constructor constructor = c.getConstructor();
System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());
// 第三步:获取某个有public修饰的有参数构造器对象
System.out.println("获取有public修饰的有参数构造器对象:");
Constructor constructor1 = c.getConstructor(String.class, int.class);
System.out.println(constructor1.getName() + " ---> " + constructor1.getParameterCount());
System.out.println();
}
/**
getDeclaredConstructor:
获取某个构造器对象
*/
@Test
public void getDeclaredConstructor() throws Exception {
System.out.println("4. 获取某个构造器对象:");
// 第二步:获取无参数构造器对象
System.out.println("获取无参数构造器对象:");
Constructor declaredConstructor = c.getDeclaredConstructor();
System.out.println(declaredConstructor.getName() + " ---> " + declaredConstructor.getParameterCount());
// 第三步:获取有参数构造器对象
System.out.println("获取有参数构造器对象:");
Constructor declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(declaredConstructor1.getName() + " ---> " + declaredConstructor1.getParameterCount());
System.out.println();
}
}
方法名称 | 说明 |
---|---|
T newInstance(Object… initargs) | 根据指定的构造器创建对象 |
public void setAccessible(boolean flag) | 设置为true,表示取消访问检查,进行暴力反射 |
package com.app.d3_reflect_constructor;
/**
老师类
*/
public class Teacher {
private String name;
private int age;
private Teacher() {
System.out.println("无参构造器被执行");
}
public Teacher(String name, int age) {
System.out.println("有参构造器被执行");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.app.d3_reflect_constructor;
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
目标:学习使用反射技术获取构造器对象并使用
*/
public class TestTeacher02 {
@Test
public void getDeclaredConstructor() throws Exception {
// a. 获取类对象
Class c = Teacher.class;
// b. 获取无参数构造器对象
Constructor constructor = c.getDeclaredConstructor();
System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());
// c. 根据指定的构造器创建对象
constructor.setAccessible(true); // 权限被打开
Teacher t = (Teacher) constructor.newInstance(); // 如果指定的构造器是private修饰的,请使用上一行代码进行暴力反射(暴力拆箱)
System.out.println(t);
System.out.println("-----------------------------");
// d. 获取有参数构造器对象
Constructor constructor1 = c.getDeclaredConstructor(String.class, int.class);
// e. 根据指定的构造器创建对象
Teacher t1 = (Teacher) constructor1.newInstance("薰悟空", 2000);
System.out.println(t1);
}
}
方法名称 | 说明 |
---|---|
Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
方法名称 | 说明 |
---|---|
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 取值 |
package com.app.d4_reflect_field;
public class Student {
private String name;
private int age;
public static String schoolName;
public static final String COUNTRY = "中国";
public Student() {
System.out.println("无参构造器被执行");
}
public Student(String name, int age) {
System.out.println("有参构造器被执行");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static String getSchoolName() {
return schoolName;
}
public static void setSchoolName(String schoolName) {
Student.schoolName = schoolName;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.app.d4_reflect_field;
import org.junit.Test;
import java.lang.reflect.Field;
/**
目标:使用反射技术获取成员变量:取值和赋值
Field的方法:给成员变量赋值和取值
void set(Object obj, Object value): 给对象注入某个成员变量的值
Object get(Object obj): 获取对象的成员变量的值
void setAccessible(true): 暴力反射,设置为可以直接访问私有类型的属性
Class getType(): 获取属性的类型,返回class对象
String getName(): 获取属性的名称。
*/
public class TestStudent01 {
@Test
public void setField() throws Exception {
// 1、先获取类对象
Class c = Student.class;
// 2、提取所有成员变量对象的数组
Field[] fields = c.getDeclaredFields();
// 3、遍历一下
for (Field field : fields) {
System.out.println(field.getName() + " ===> " + field.getType());
}
System.out.println("-------------------------");
// 4、提取某个成员变量
Field country = c.getDeclaredField("COUNTRY");
// 5、获取对象的成员变量的值
String coun = (String) country.get(c);
System.out.println(coun);
Field nameF = c.getDeclaredField("name");
// 暴力反射,设置为可以直接访问私有类型的属性
nameF.setAccessible(true);
System.out.println("-------------------------");
// 6、给对象注入某个成员变量的值: 赋值
Student s = new Student(); // 创建对象
nameF.set(s, "薰悟空");
System.out.println(s);
System.out.println("-------------------------");
// 7、获取对象的成员变量的值: 取值
String name = (String) nameF.get(s);
System.out.println(name);
}
}
方法名称 | 说明 |
---|---|
Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class< ? >… parameterTypes) | 返回单个成员方法对象(只能拿到public的) |
Method getDeclaredMethod(String name, Class< ? >… parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
方法名称 | 说明 |
---|---|
Object invoke(Object obj, Object… args) | 运行方法 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
package com.app.d5_reflect_method;
public class Cat {
private String name;
public Cat() {
}
public void run() {
System.out.println("猫跑得飞快~~");
}
// 私有方法
private void eat() {
System.out.println("猫喜欢吃鱼!");
}
private String eat(String food) {
System.out.println("猫吃" + food);
return "吃得非常开心~~";
}
public static void inAdd() {
System.out.println("我们正在学习Java!");
}
public Cat(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
package com.app.d5_reflect_method;
import org.junit.Test;
import java.lang.reflect.Method;
/**
目标:使用反射技术获取方法对象并触发执行
*/
public class TestCat01 {
// a.先获取对象类
public static Class c = Cat.class;
/**
* 1、获取所有方法对象的数组
*/
@Test
public void getDeclaredMethods() {
System.out.println("1、获取所有方法对象的数组:");
// b.获取所有方法对象的数组
Method[] methods = c.getDeclaredMethods();
// c.遍历一下
for (Method method : methods) {
System.out.println("方法名称:" + method.getName() +
",返回值类型:" + method.getReturnType() +
",参数个数:" + method.getParameterCount());
}
System.out.println();
}
/**
* 2、获取某个方法对象
*/
@Test
public void getDeclaredMethod() throws Exception {
System.out.println("2、获取某个方法对象:");
// b.获取某个方法对象
Method method = c.getDeclaredMethod("eat");
Method method1 = c.getDeclaredMethod("eat", String.class);
Method method2 = c.getDeclaredMethod("inAdd");
// 如果方法是private修饰的,就暴力打开权限
method.setAccessible(true);
method1.setAccessible(true);
// c.触发方法的执行
Cat cat = new Cat();
// 注意:方法如果是无返回值的,那么返回的是null
Object result = method.invoke(cat);
System.out.println(result);
System.out.println("-----------------");
Object result1 = method1.invoke(cat, "猫粮");
System.out.println(result1);
System.out.println("-----------------");
method2.invoke(cat);
System.out.println();
}
}
反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以 为集合存入其他任意类型的元素的。
之前在创建集合时会声明泛型,比如以下程序中声明的泛型是Integer类型,那么此集合只能添加Int类型的数据,一旦添加其他类型的数据就会在编译时报错,但是如果用反射技术,就可以强行往声明了泛型的集合添加其他类型的数据:
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
// list.add("中国"); // 报错
list.add(99);
原因:
package com.app.d6_reflect_genericity;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
目标:反射实现泛型擦除后,加入其他类型的元素
*/
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
// 1、创建两个不同泛型的集合
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
// 2、得到两个集合的class文件
System.out.println(list1.getClass());
System.out.println(list2.getClass());
// 3、判断两个集合的class文件是否相同
System.out.println(list1.getClass() == list2.getClass()); // true
System.out.println("--------------------------");
// 4、创建一个泛型的集合,用于实现泛型擦除后,加入不同类型的数据
ArrayList<Integer> list3 = new ArrayList<>();
list3.add(123);
list3.add(24);
// list3.add("我爱中国!"); // 报错
// list3.add(123.33); // 报错
// 5、得到泛型集合list3的Class对象
Class c = list3.getClass();
// 6、得到c类中的add方法
Method add = c.getDeclaredMethod("add", Object.class);
// 7、添加任意类型的数据到list3集合中
boolean rs1 = (boolean) add.invoke(list3, "我爱中国!");
boolean rs2 = (boolean) add.invoke(list3, 123.33);
System.out.println(rs1);
System.out.println(rs2);
System.out.println(list3);
System.out.println("--------------------------");
// 另一种方式实现泛型擦除后,加入其他类型的元素
// a.将泛型集合list3赋值给没有约定泛型的集合list4
ArrayList list4 = list3;
// b.添加其他类型的元素
list4.add("敖德彪");
list4.add(false);
list4.add(66.6);
System.out.println(list3);
}
}
class java.util.ArrayList
class java.util.ArrayList
true
--------------------------
true
true
[123, 24, 我爱中国!, 123.33]
--------------------------
[123, 24, 我爱中国!, 123.33, 敖德彪, false, 66.6]
Process finished with exit code 0
案例:反射做通用框架
package com.app.d7_reflect_framework;
/**
1、创建对象:学生类
*/
public class Student {
/**
学生的属性:姓名、性别、年龄、班级、爱好
*/
private String name;
private char sex;
private int age;
private String className;
private String hobby;
/**
无参数构造器
*/
public Student() {
}
/**
* 有参数构造器
* @param name 姓名
* @param sex 性别
* @param age 年龄
* @param className 班级
* @param hobby 爱好
*/
public Student(String name, char sex, int age, String className, String hobby) {
this.name = name;
this.sex = sex;
this.age = age;
this.className = className;
this.hobby = hobby;
}
/**
* 提供全套get、set方法:暴露其取值和赋值
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
/**
* 重写toString方法
*/
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
", className='" + className + '\'' +
", hobby='" + hobby + '\'' +
'}';
}
}
package com.app.d7_reflect_framework;
/**
1、创建对象:老师类
*/
public class Teacher {
/**
老师的属性:姓名、性别、薪水
*/
private String name;
private char sex;
private double salary;
/**
无参数构造器
*/
public Teacher() {
}
/**
有参数构造器
* @param name 姓名
* @param sex 性别
* @param salary 薪水
*/
public Teacher(String name, char sex, double salary) {
this.name = name;
this.sex = sex;
this.salary = salary;
}
/**
提供get、set方法:暴露其取值和赋值
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
/**
重写toString方法
*/
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", sex=" + sex +
", salary=" + salary +
'}';
}
}
package com.app.d7_reflect_framework;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
/**
2、创建框架类
*/
public class MyBatisUtil {
/**
* 3、定义保存所有类型对象的方法
* @param obj 传入的对象
*/
public static void saveAllObject(Object obj) {
try (
// d. 创建打印流,包装一个文件字节输出流:参数一是输出目标文件相对路径;参数二是每次输出都会在文件末尾追加数据。
PrintStream ps = new PrintStream(new FileOutputStream("day14-junit-reflect-annotation-proxy-app/src/data.txt", true));
) {
// a. 得到该对象的Class类对象
Class c = obj.getClass();
// e. 输出当前类名到文件中
// c.getSimpleName(): 获取当前类名;c.getName(): 获取类的全限名(包名+类名)
ps.println("===========" + c.getSimpleName() + "===========");
// b. 提取该对象的全部成员变量
Field[] fields = c.getDeclaredFields();
// c. 遍历全部成员变量,得到信息
for (Field field : fields) {
// (c-1) 获取成员变量的名称
String name = field.getName();
// (c-2) 由于对象的成员变量都是私有的,所以需要暴力反射
field.setAccessible(true);
// (c-3) 获取该成员变量在obj对象中的具体值(取值)
String value = field.get(obj) + ""; // 得到值后拼接一个空字符串:意思就是把任何值都转成字符串存入到文件中
// f. 将成员变量名称和具体值输出到目标文件中
ps.println(name + "=" + value);
}
System.out.println("保存成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.app.d7_reflect_framework;
/**
目标:通过使用反射做通用框架支持保存任意对象的具体信息,可以理解到反射的作用
需求:
给你任意一个对象,在不清楚对象字段的情况,可以把对象的字段名称和对应值存储到文件中。
*/
public class ReflectDemo {
public static void main(String[] args) {
// 4、创建学生对象
Student stu1 = new Student();
stu1.setName("孙悟空");
stu1.setSex('男');
stu1.setAge(2000);
stu1.setClassName("天宫舔狗99班");
stu1.setHobby("大闹天宫");
// a. 将此学生对象的信息保存到目标文件中
MyBatisUtil.saveAllObject(stu1);
// 5、创建老师对象
Teacher tea1 = new Teacher();
tea1.setName("玉皇大帝");
tea1.setSex('男');
tea1.setSalary(10000);
// a. 将此老师对象的信息保存到目标文件中
MyBatisUtil.saveAllObject(tea1);
}
}