文章目录
文章目录
前言
提示:反射机制在基础知识的学习中属于比较重要的部分,学好反射有助于后期第三阶段的学习。这也是我一直想要学好的一个阶段,无论如何需要抓紧它。
提示:以下是本篇文章正文内容,下面案例可供参考
一、反射是什么?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
二、获取字节码文件的三个方式
本次需要用到一个学生类作为实验对象(Student.java)
创建学生类
public class Student {
public String name;
private char sex;
private int age;
private String classId;
private String id;
public Student() {
}
public Student(String classId, String id) {
this.classId = classId;
this.id = id;
}
public Student(String name, char sex, int age, String classId, String id) {
this.name = name;
this.sex = sex;
this.age = age;
this.classId = classId;
this.id = id;
}
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 getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void eat() {
System.out.println(this.name + "吃饭饭");
sleep();
}
private void sleep() {
System.out.println(this.name + "睡觉觉");
}
@Override
public String toString() {
return name + "\t" + sex + "\t" + age + "\t" + classId + "\t" + id;
}
}
创建一个properties文件【classpath.properties】
创建Test01类 ,通过三种方式来获取字节码文件,此处推荐第三种方式,理由是它的可变性要好很多
import java.util.Properties;
public class Test01 {
public static void main(String[] args) throws Exception{
/**
* 知识点:反射
* 需求:获取类的字节码文件对象
*/
//第一种获取方式
Class<?> c1=Student.class;
//第二种获取方式
Student stu=new Student();
Class<?> c2 = stu.getClass();
//第三种方式创建
Properties p=new Properties();
p.load(Test01.class.getClassLoader().getResourceAsStream("classpath.properties"));
String classPath = p.getProperty("classPath");
Class<?> c3 = Class.forName(classPath);
}
}
三、通过反射来操作类
(1)通过反射来获取类的构造方法
这一个案例中 我们仍然以Student来作为实验对象
Student 类代码
package com.yzy.Reflex.TestReflex01;
public class Student {
public String name;
private char sex;
private int age;
private String classId;
private String id;
public Student() {
}
public Student(String classId, String id) {
this.classId = classId;
this.id = id;
}
public Student(String name, char sex, int age, String classId, String id) {
this.name = name;
this.sex = sex;
this.age = age;
this.classId = classId;
this.id = id;
}
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 getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void eat() {
System.out.println(this.name + "吃饭饭");
sleep();
}
private void sleep() {
System.out.println(this.name + "睡觉觉");
}
@Override
public String toString() {
return name + "\t" + sex + "\t" + age + "\t" + classId + "\t" + id;
}
}
创建一个测试类Test02
import java.lang.reflect.Constructor;
import java.util.Properties;
public class Test02 {
public static void main(String[] args) throws Exception {
/**
* 知识点:反射
* 需求:利用反射机制操作构造方法
*/
//获取Student类的字节码文件对象
Properties p = new Properties();
p.load(Test02.class.getClassLoader().getResourceAsStream("classpath.properties"));
String classPath = p.getProperty("classPath");
Class<?> c = Class.forName(classPath);
//1、通过字节码文件来获取构造方法的个数(我已经事先在Student中设置了三个构造方法)
//获取该类中的public的构造方法
/*Constructor<?> [] constructor = c.getConstructors();//记住 getConstructors() 是获取所有的构造方法故此使用集合来获取
//getConstructor()少了一个“s”,是获取一个构造方法
for ( Constructor<?> constructors:constructor) {
System.out.println(constructors);
}*/
//获取该类的所有的构造方法的对象,不管是共有还是私有都能获取 强大的declaredConstructor不管是否处于继承状态下
// Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
//
// for (Constructor<?> decons: declaredConstructors) {
// System.out.println(decons);
// }
//利用无参创建Student对象,关键字newInstance
/*
Constructor<?> constructor = c.getConstructor();
Student student= (Student) c.newInstance();
System.out.println(student);*/
//利用有参构造方法创建对象
Constructor<?> constructor=c.getDeclaredConstructor(String.class,char.class,int.class,String.class,String.class);
//设置修改权限
constructor.setAccessible(true);
Student student= (Student)constructor.newInstance("雍仲杨",'男',21,"2107","001");
System.out.println(student);
}
}
(2)通过反射机制来操作属性
仍然使用之前的Student作为实验对象
Student对象
public class Student {
public String name;
private char sex;
private int age;
private String classId;
private String id;
public Student() {
}
public Student(String classId, String id) {
this.classId = classId;
this.id = id;
}
public Student(String name, char sex, int age, String classId, String id) {
this.name = name;
this.sex = sex;
this.age = age;
this.classId = classId;
this.id = id;
}
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 getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void eat() {
System.out.println(this.name + "吃饭饭");
sleep();
}
private void sleep() {
System.out.println(this.name + "睡觉觉");
}
@Override
public String toString() {
return name + "\t" + sex + "\t" + age + "\t" + classId + "\t" + id;
}
}
import java.lang.reflect.Field;
import java.util.Properties;
public class Test03 {
public static void main(String[] args) throws Exception {
/**
* 知识点:反射
* 需求:通过反射来操作类的属性
*/
//1、获取类的字节码文件对象
Properties p=new Properties();
p.load(Test03.class.getClassLoader().getResourceAsStream("classpath.properties"));
String classPath = p.getProperty("classPath");
Class<?> c = Class.forName(classPath);
//获取到本类中共有属性的对象
/* Field[] fields = c.getFields();
for (Field field:fields) {
System.out.println(field);
}*/
//获取本类的所有属性的对象
/*
Field[] deFields = c.getDeclaredFields();
for (Field deField:deFields) {
System.out.println(deField);
}*/
Student student=new Student("唐坤梅",'女',21,"2107","002");
//设置非私有化属性
Field nameField = c.getField("name");
nameField.set(student,"廖薇");
//设置私有化属性
Field age = c.getDeclaredField("age");
age.setAccessible(true);//设置修改权限
age.set(student,22);
System.out.println(student);
}
}
(3)利用反射机制来操作方法
老规矩使用Student作为实验对象
public class Student {
public String name;
private char sex;
private int age;
private String classId;
private String id;
public Student() {
}
public Student(String classId, String id) {
this.classId = classId;
this.id = id;
}
public Student(String name, char sex, int age, String classId, String id) {
this.name = name;
this.sex = sex;
this.age = age;
this.classId = classId;
this.id = id;
}
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 getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void eat() {
System.out.println(this.name + "吃饭饭");
sleep();
}
private void sleep() {
System.out.println(this.name + "睡觉觉");
}
@Override
public String toString() {
return name + "\t" + sex + "\t" + age + "\t" + classId + "\t" + id;
}
}
import java.lang.reflect.Method;
import java.util.Properties;
public class Test04 {
public static void main(String[] args) throws Exception {
/**
* 知识点:反射
*
* 需求:利用反射机制操作方法
*/
Properties p=new Properties();
p.load(Test04.class.getClassLoader().getResourceAsStream("classpath.properties"));
String classPath = p.getProperty("classPath");
Class<?> c = Class.forName(classPath);
//获取该类的公有方法的对象(public)
/*Method[] methods = c.getMethods();
for (Method method:methods) {
System.out.println(method);
}*/
//获取该类所有的方法的对象
/*Method[] declaredMethods = c.getDeclaredMethods();
for (Method decMethod:declaredMethods) {
System.out.println(declaredMethods);
}*/
Student student=new Student("雍仲杨",'男',22,"2107","003");
//调用公有的方法
Method setAge = c.getMethod("setAge", int.class);
setAge.invoke(student,22);
//调用私有方法
Method sleep = c.getDeclaredMethod("sleep");
sleep.setAccessible(true);//设置权限
sleep.invoke(student);
System.out.println(student);
}
}
(4)利用反射操作数组
import java.lang.reflect.Array;
public class Test05 {
public static void main(String[] args) throws Exception {
/**
* 知识点:反射
*
* 需求:利用反射机制操作数组
*/
String [] ss = (String[]) Array.newInstance(String.class, 5);
System.out.println("利用反射获取数组的长度:"+Array.getLength(ss));
//利用反射设置数组元素
Array.set(ss, 0, "盖伦");
Array.set(ss, 1, "赵信");
Array.set(ss, 2, "嘉文");
Array.set(ss, 3, "泰隆");
Array.set(ss, 4, "李青");
for (int i=0;i<Array.getLength(ss);i++){
System.out.println(Array.get(ss,i));//根据下标 i 获取元素 ss
}
}
}
难点:使用反射操纵泛型
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
public class Test06 {
public static void main(String[] args) throws Exception{
/**
* 知识点:反射
*
* 需求:利用反射机制操作泛型
*/
//获取Tesy06的字节码文件对象
Class<?> c=Class.forName("com.yzy.Reflex.TestReflex01.Test06");
//获取method01方法的对象
Method method01 = c.getDeclaredMethod("method01", ArrayList.class, HashMap.class);
method01.setAccessible(true);//设置修改权限
Type[] genericParameterTypes = method01.getGenericParameterTypes();//获取参数类型
for (Type type:genericParameterTypes) {
//此处由于之前的Type是一个接口 所以这里必须进行强转,将接口转成一个类
ParameterizedType parameterizedType=(ParameterizedType)type;
//获取参数的泛型类型
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type acTypeArguments:actualTypeArguments) {
System.out.println(acTypeArguments);
}
}
System.out.println("----------------------------------------------------------");
//获取method02方法对象
Method method02 = c.getDeclaredMethod("method02");
method02.setAccessible(true);//设置修改权限
Type genericReturnType = method02.getGenericReturnType();//获取返回值类型
ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
//获取返回值的泛型类型
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type type:actualTypeArguments) {
System.out.println(type);
}
}
//方法一
public static void method01(ArrayList<String> list, HashMap<String,Integer> map){
}
//方法二
public static HashMap<String,Integer>method02(){
return null;
}
}