前言:
下面是个student类,我想获得此类中信息,除了用正常的new对象的方法,我们还可以用反射的方式获取。(本文下面讲解都以Student类为示例)
public class Student {
private String name;
private Integer age;
private String gender;
private String mobile;
private String address;
public Student(){}
public Student(String name, Integer age, String gender, String mobile, String address) {
this.name = name;
setAge(age);
setGender(gender);
this.gender = gender;
this.mobile = mobile;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age<=18?18:age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = (!gender.equals("男")&&!gender.equals("女"))?"男":gender;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", mobile='" + mobile + '\'' +
", address='" + address + '\'' +
'}';
}
}
一.什么是反射
反射就是:在程序运行时动态解析类的内部信息(注解,属性,方法)。
所以反射的前提就是:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
二.怎么用反射
1.获取目标类型的Class对象
方法有三种
第一种:Class c1 = Student.class;
第二种:Student stu = new Student();
Class c2 = stu.getClass();
第三种:Class c3 = Class.forName(“refection.Student”);
此方法要处理ClassNotFoundException异常,防止路径下没有此类
//方式一
Class c1 = Student.class;
System.out.println("方式一:"+c1);
//方式二
Student stu = new Student();
Class c2 = stu.getClass();
System.out.println("方式二:"+c2);
//方式三(此方法要处理异常)
Class c3 = Class.forName("refection.Student");
System.out.println("方式三:"+c3);
输出结果为:
方式一:class refection.Student
方式二:class refection.Student
方式三:class refection.Student
2.获取类名
法一:String fullPathName = c1.getName();//获取类的全路径名称
法二:String simpleName = c1.getSimpleName();//获取类的简名称,也就是类名
String name = c1.getName();//获取类的全路径
String simpleName = c1.getSimpleName();//获取类的简名称
System.out.println("name为:"+name);
System.out.println("simpleName为:"+simpleName);
代码执行结果
name为:refection.Student
simpleName为:Student
3.获取目标类型的Class对象中的构造方法
第一种:获取无参构造
Constructor noCons = c1.getConstructor();
第二种:获取有参构造方法
Constructor hasCons = c1.getConstructor(String.class, Integer.class,String.class,String.class,String.class)
注意:看我Student类中成员变量的类型都不是基本类型。
//获取类的构造方法
Constructor noCons = c1.getConstructor();//获取无参构造
Constructor hasCons = c1.getConstructor(String.class, Integer.class,String.class,String.class,String.class);
System.out.println(noCons);
System.out.println(hasCons);
结果为:
public refection.Student()
public refection.Student(java.lang.String,java.lang.Integer,java.lang.String,java.lang.String,java.lang.String)
4.获取目标类型的Class对象中的自定义属性(成员变量Field)
Field[] fs = c1.getDeclaredFields();//获取类中所有的自定义的属性(返回的是个数组)
int modeifiedNum = f.getModifiers();//获取属性访问修饰整数(返回是个整数,0代表default,1代表public,2代表private,4代表protected )
String typeName = c.getName();//获取属性的类型名称
String fieldName = f.getName();//获取属性的名称
代码如下
//获取类中自定义属性
int modeifiedNum ;//属性访问修饰整数
Class c ;//属性的类型信息
String typeName ;//属性的类型名称
String fieldName ;//属性的名称
Field[] fs = c1.getDeclaredFields();//获取类中所有的自定义的属性
for (Field f : fs) {
modeifiedNum = f.getModifiers();//获取属性访问修饰整数
c = f.getType();//获取属性的类型信息
typeName = c.getName();//获取属性的类型名称
fieldName = f.getName();//获取属性的名称
System.out.println("访问修饰符:"+modeifiedNum);
System.out.println("属性的类型信息:"+c);
System.out.println("属性的类型名称:"+typeName);
System.out.println("属性的名称:"+fieldName);
System.out.println("==========================");
}
运行结果如下
访问修饰符:2
属性的类型信息:class java.lang.String
属性的类型名称:java.lang.String
属性的名称:name
==========================
访问修饰符:1
属性的类型信息:class java.lang.Integer
属性的类型名称:java.lang.Integer
属性的名称:age
==========================
访问修饰符:0
属性的类型信息:class java.lang.String
属性的类型名称:java.lang.String
属性的名称:gender
==========================
访问修饰符:4
属性的类型信息:class java.lang.String
属性的类型名称:java.lang.String
属性的名称:mobile
==========================
访问修饰符:2
属性的类型信息:class java.lang.String
属性的类型名称:java.lang.String
属性的名称:address
5.获取目标类型的Class对象中的相关的方法
Method[] ms = c1.getDeclaredMethods();//获取类中所有的方法
String methodName = m.getName();//获取方法的名称
Class cm = m.getReturnType();//获取方法的返回类型
String returnType = cm.getName();//获取方法返回类型的名称
Class<?>[] parameterTypes = m.getParameterTypes();//获取方法所有参数类型(数组)
//获取类中的自定义方法
String methodName ;
Class cm;//方法的返回类型
String returnType;//方法返回类型的名称
Class<?>[] parameterTypes;//方法所有参数类型
Method[] ms = c1.getDeclaredMethods();
for (Method m : ms) {
methodName = m.getName();//获取方法的名称
System.out.println("方法名称为:"+methodName);
cm = m.getReturnType();//获取方法的返回类型
System.out.println("返回类型:"+cm);
returnType = cm.getName();//获取方法返回类型的名称
System.out.println("返回类型的名称:"+returnType);
parameterTypes = m.getParameterTypes();//获取方法所有参数类型
for (Class<?> t : parameterTypes) {
System.out.println("方法中的參數为:"+t);
}
System.out.println("=============================");
}
运行结果
方法名称为:toString
返回类型:class java.lang.String
返回类型的名称:java.lang.String
=============================
方法名称为:getAddress
返回类型:class java.lang.String
返回类型的名称:java.lang.String
=============================
方法名称为:getName
返回类型:class java.lang.String
返回类型的名称:java.lang.String
=============================
方法名称为:setName
返回类型:void
返回类型的名称:void
方法中的參數為:class java.lang.String
=============================
方法名称为:getAge
返回类型:class java.lang.Integer
返回类型的名称:java.lang.Integer
=============================
方法名称为:setAge
返回类型:void
返回类型的名称:void
方法中的參數為:class java.lang.Integer
=============================
方法名称为:getMobile
返回类型:class java.lang.String
返回类型的名称:java.lang.String
=============================
方法名称为:setMobile
返回类型:void
返回类型的名称:void
方法中的參數為:class java.lang.String
=============================
方法名称为:getGender
返回类型:class java.lang.String
返回类型的名称:java.lang.String
=============================
方法名称为:setGender
返回类型:void
返回类型的名称:void
方法中的參數為:class java.lang.String
=============================
方法名称为:setAddress
返回类型:void
返回类型的名称:void
方法中的參數為:class java.lang.String
=============================
三.运用反射给类中的属性赋值
从上面我们知道了
类名 | 用途 |
---|---|
Class | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Fields | 代表类的成员变量(类属性) |
Method | 代表类的方法 |
Constructor | 代表类的构造方法 |
下面我们就来运用一下,调用类中的方法,给类属性赋值
1.创建对象
利用无参构造创建对象
T t = (T)c.newInstance();
利用无参构造创建函数
Constructor cons = c.getConstructor(Class<?> …parameter Types); T t = (T)cons.newInstance(Object…parameters);
Student t = (Student)c3.newInstance();//利用无参构造创建对象,处理异常
Constructor cons = c3.getConstructor(String.class, Integer.class, String.class, String.class, String.class);//获取构造器
Student t1 = (Student)cons.newInstance("hello",17,"1","2","3");//利用有参构造,处理异常
2.给姓名赋值
Method m = c3.getDeclaredMethod("setName",String.class);//获取setName方法
m.setAccessible(true);//防止方法时私有的,如果方法是私有的设置为true
m.invoke(t,"你猜");//给调用方法,赋值
System.out.println(t);
m = c3.getMethod("getName");//获取查值的方法
String name = (String) m.invoke(t);
System.out.println("姓名为:"+name);
其中:m.invoke()方法作用是传递object对象及参数调用该对象对应的方法;
m.setAccessible(true);//设置方法的可见性