个人简介
- 大家好,我是韩慧腾。一名正在努力学JAVA的大一小白,本文章为初学的笔记,希望各位多多指教。💙
- 欢迎点赞+收藏+留言💜
- 发光不是太阳的权力,你也可以🧡
一、反射概述
- 反射是指对于任何一个Class类,在运行的时候都可以直接得到这个类的全部成分
- 在运行时,可以直接得到这个类的构造器对象:Constructor
- 在运行时,可以直接得到这个类的成员变量对象:Field
- 在运行时,可以直接得到这个类的成员方法对象:Method
- 这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制
反射的关键:反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。
反射的作用:反射是在运行时获取类的字节码文件对象,然后可以解析类中的全部成分
二、反射操作
1)获取Class类的对象
package com.itheima_01;
/**
* @author hanhan
* date 2022/5/1 17:09
* 努力已经来不及了,你得拼命
*/
public class Reflect_01 {
public static void main(String[] args) throws Exception {
//获取Class类对象,调用Class类中静态方法:forName(包名+类名)
//方式一:
Class c=Class.forName("com.itheima_01.Cat");
System.out.println(c);//实际上就是得到.class文件
//方式二:类名.class
Class c1=Cat.class;
//方式三:对象.getClass(),获取对象对应类的Class对象
Cat cat = new Cat();
Class c2=cat.getClass();
}
}
class Cat{
String name;
int age;
public Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(name+"爱吃鱼");
}
}
2)从类对象中获取类的成分对象
- Class类中用于获取构造器的方法:
package com.itheima_01;
import java.lang.reflect.Constructor;
/**
* @author hanhan
* date 2022/5/1 18:44
* 努力已经来不及了,你得拼命
*/
public class Reflect_02 {
public static void main(String[] args) throws NoSuchMethodException {
//获取Student类对象
Class c = Student.class;
//提取类中的全部构造器对象
Constructor[] constructors = c.getConstructors();//该方法只能获取public修饰的构造器
//遍历Constructor数组
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"->"+constructor.getParameterCount());//输出构造器的名字和参数的个数
}
System.out.println("~~~~~~~~~~~~~~~~");
Constructor[] declaredConstructors = c.getDeclaredConstructors();//可以获取全部构造器(包括private修饰的)
//遍历declaredConstructors数组
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor.getName()+"->"+declaredConstructor.getParameterCount());//获取构造器名字和参数个数
}
System.out.println("~~~~~~~~~~~~~~~~");
//获取某个构造器(只能是public修饰的)
Constructor constructor = c.getConstructor();//定位单个构造器(根据参数定位),无参的
System.out.println(constructor.getName()+"->"+constructor.getParameterCount());
System.out.println("~~~~~~~~~~~~~~~~");
//获取单个构造器(包括私密的)
Constructor declaredConstructor = c.getDeclaredConstructor(String.class,String.class);
System.out.println(declaredConstructor.getName()+"->"+declaredConstructor.getParameterCount());//根据参数定位私密的构造器
}
}
class Student{
private String name;
private String sex;
private int age;
public Student() {
}
private Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
public Student(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
获取构造器的作用:初始化一个对象并返回
反射得到的对象作用依旧是创建对象(newInstance),可以打开private构造方法的权限。
反射可以破环封装性,私有的也可以执行了
package com.itheima_01;
import java.lang.reflect.Constructor;
/**
* @author hanhan
* date 2022/5/2 8:15
* 努力已经来不及了,你得拼命
*/
public class Reject_02 {
public static void main(String[] args) throws Exception {
Class dogClass = Dog.class;
Constructor declaredConstructor = dogClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);//构造器权限被打开,暴力反射
Dog o = (Dog)declaredConstructor.newInstance("毛毛",10);
o.eat();
System.out.println(o);
}
}
class Dog{
private String name;
private int age;
private String sex;
public Dog() {
}
private Dog(String name, int age) {
this.name = name;
this.age = age;
}
public Dog(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void eat(){
System.out.println(name+"爱吃骨头");
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
- Class类中用于获取成员变量的方法:
package com.itheima_01;
import java.lang.reflect.Field;
/**
* @author hanhan
* date 2022/5/2 14:40
* 努力已经来不及了,你得拼命
*/
public class FieldDemo_00 {
public static void main(String[] args) throws Exception {
//定位class类对象
Class teacherClass = Teacher.class;
//定位全部成员变量
Field[] declaredField = teacherClass.getDeclaredFields();
//遍历成员变量数组
for (Field field : declaredField) {
System.out.println(field.getName()+"->"+field.getType());//成员变量的名字和类型
}
System.out.println("~~~~~~~~~~~~~");
//定位某一个成员变量
Field field = teacherClass.getDeclaredField("age");//根据参数定位
field.setAccessible(true);//暴力打开权限
System.out.println(field.getName()+"->"+field.getType());
//创建一个Teacher对象,并为其赋值
Teacher teacher = new Teacher();
field.set(teacher,18);
System.out.println(field.get(teacher));
}
}
class Teacher{
private String name;
private String sex;
private int age;
public Teacher() {
}
private Teacher(String name, String sex) {
this.name = name;
this.sex = sex;
}
public Teacher(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
- Class类中用于获取成员方法的方法:
package com.itheima_01;
import java.lang.reflect.Method;
/**
* @author hanhan
* date 2022/5/2 15:16
* 努力已经来不及了,你得拼命
*/
public class MethodDemo_00 {
public static void main(String[] args) throws Exception {
Class pigClass = Pig.class;
Method[] declaredMethods = pigClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName()+"->"+declaredMethod.getReturnType()+"->"+declaredMethod.getParameterCount());//输出方法名字和返回值类型\参数个数
}
System.out.println("~~~~~~~~~~~~~~~");
//提取单个方法
Method eat = pigClass.getDeclaredMethod("eat");//第一个参数:方法名
Method eat1=pigClass.getDeclaredMethod("eat",String.class);//第一个参数:方法名 第二个参数:参数类型
eat.setAccessible(true);//同样可以打开权限
//触发方法的执行
Pig pig = new Pig();
eat.invoke(pig);
Object o=eat1.invoke(pig,"zzz");//执行方法的时候,第一个参数是对象名,第二个参数是方法的参数,若方法没有参数,则只有一个参数
System.out.println(o);
}
}
class Pig{
private String name;
private String sex;
private int age;
public Pig() {
}
public Pig(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("猪从早吃到晚,永远管不住嘴");
}
public String eat(String name){
System.out.println(name+"猪不仅爱吃,还喜欢乱叫");
return name+"猪";
}
@Override
public String toString() {
return "Pig{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
三、反射作用
- 绕过编译阶段为集合添加数据
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译Class文件进入运行阶段的时候,泛型会被擦除;而反射是作用在运行时的技术,此时集合的泛型将不能产生约束,即可以为集合添加任意类型的元素。
package com.itheima_01;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* @author hanhan
* date 2022/5/2 21:19
* 努力已经来不及了,你得拼命
* 用反射实现泛型擦除后,加入其他类型的元素
*/
public class ReflectDemo_0 {
public static void main(String[] args) throws Exception {
ArrayList<String> list = new ArrayList<>();
ArrayList<Integer> list1 = new ArrayList<>();
System.out.println(list.getClass()==list1.getClass());//true 证明集合对应的Class文件是同一个
//以上的集合List只能添加字符串,而不能添加其他类型,使用反射可以解决,擦掉泛型
Class c = list.getClass();//相当于是ArrayList.class
//定位c中的add方法
Method add = c.getDeclaredMethod("add", Object.class);//此时的集合可以加任何类型
add.invoke(list,100);//List可以加整型
add.invoke(list1,"d");//List1可以加字符串
System.out.println(list);
System.out.println(list1);
}
}
package com.itheima_01;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* @author hanhan
* date 2022/5/3 8:28
* 努力已经来不及了,你得拼命
*/
public class ReflectDemo_01 {
public static void main(String[] args) throws NoSuchMethodException {
ArrayList<String> list = new ArrayList<>();
Class c = list.getClass();
Method add = c.getDeclaredMethod("add", Object.class);
ArrayList list1=list;//此时的list和list1指向同一个地址对象,所以list1可以添加任何元素
list1.add(19);
list1.add("明天");
list1.add(12.34);
list1.add(true);
System.out.println(list1);
}
}
2.通用框架的底层原理
需求:给你任意一个对象,在不清楚对象字段的情况可以把对象的字段名称和对应值存储到文件中去。
package com.itheima_01.Reflect;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
/**
* @author hanhan
* date 2022/5/3 8:39
* 努力已经来不及了,你得拼命
*/
public class ReflectDemo_00 {
public static void main(String[] args) {
Student student = new Student("菜菜","女",18);
Frame.save(student);
Teacher teacher = new Teacher("hhh", "nan", 18, 10000);
Frame.save(teacher);
}
}
//提供一个通用框架,支持保存所有对象的具体信息
class Frame{
public static void save(Object o){
try (PrintStream printStream = new PrintStream(new FileOutputStream("java-01/src/d.txt",true))){
Class c = o.getClass();
printStream.println("======="+c.getSimpleName()+"=======");//打印其类名 getName:获取全名(包名和类名)
Field[] declaredFields = c.getDeclaredFields();
for (Field declaredField : declaredFields) {
String s=declaredField.getName();//成员变量名
declaredField.setAccessible(true);
String s1=declaredField.get(o)+"";//获取其内容
printStream.println(s+"="+s1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Student{
private String name;
private String sex;
private int age;
public Student() {
}
public Student(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Teacher{
private String name;
private String sex;
private int age;
private double salary;
public Teacher() {
}
public Teacher(String name, String sex, int age, double salary) {
this.name = name;
this.sex = sex;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}