目录
一、介绍反射
1.反射概述
Java反射是Java语言的一种特性,它允许程序在运行时自我检查并对内部成员进行操作。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。具体来说,反射机制允许在运行状态中
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性,并且能改变它的属性。
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。其本质是JVM得到Class对象之后,再通过Class对象进行反编译,从而获取对象的各种信息。
2.反射主要应用场景
- 在运行时判断任意一个对象所属的类;
- 在运行时实例化任意一个类的对象;
- 在运行时获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等;
- 在运行时获取任意对象的属性,并且能改变对象的属性;
- 在运行时调用任意对象的方法。
3.Class类
在Java编程语言中,Class类是一个特殊的类,它用于表示JVM运行时的类或接口的信息。你可以把它看作是一个普通的类,但它描述的是所有的类的公共特性。
每个类在Java中都对应着一个Class对象,这个对象保存了该类的结构信息,如类名、字段、方法等。换句话说,Class类是一个反射工具,能提供很多方法用于获取类的各种信息,比如获取类名、判断该类是否是一个接口还是普通类等等。
二、使用反射
1.获取Class类
- Class.forName("类的全路径");
- 类名.Class
- 对象名.getClass();
- 包装类.TYPE
- Class类.getSuperClass();
下面附上示例代码:
package com.cqs.reflect_;
public class ReflectTest1 {
public static void main(String[] args) throws ClassNotFoundException {
//方法1:通过 Class.forName("类的全路径");获取Class
Class class1 = Class.forName("com.cqs.reflect_.Student");
//方法2:通过 类名.Class 获取Class
Class class2 = Student.class;
//方法3:通过 对象名.getClass(); 获取Class
Student student = new Student("小明", "10001", 18);
Class class3 = student.getClass();
//方法4:通过 包装类.TYPE 获取Class
Class class4 = Integer.TYPE;
//方法5:通过 Class类.getSuperClass(); 获取Class
Class class5 = class4.getSuperclass();
}
}
class Student{
private String name;
private String number;
public String sex;
public int age;
public Student(String name, String number, int age) {
this.name = name;
this.number = number;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
2.Class类常用方法
调用Class的方法一般会返回三个对象
- Field对象:存放获取对象的成员变量属性
- Method对象:存放获取对象的方法
- Constructor对象:存放获取对象的构造方法
下面是Class类的一些常用方法
- 获取成员变量
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)//获取指定公共属性的Field对象
getDeclaredField(变量名)//获取指定包括私有,不包括继承的Field对象
- 获取成员方法
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)//获取指定方法的Method对象
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)//获取指定包括私有,不包括继承的Method对象
- 获取构造方法
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)//获取指定包括私有,不包括继承的Constructor对象
- 总结:
getXXXs()//获取公开的包括继承的XXX对象
getDeclaredXXXs()//获取包括私有,不包括继承的XXX对象
getXXX(xx)//获取指定xx的XXX对象(公开的)
getDeclaredXXX(xx)//获取指定xx的XXX对象(包括私有,不包括继承)
其中XXX表示 Field/Method/Constructor 三者之一
方法名get后如果接Declared可以获取私有属性或者方法
方法名最后如果有s可以获取所有的XXX对象
- 其他方法
getInterfaces()//返回一个包含class对象的数组,存放该类或者接口实现的接口
newInstance()//使用无参构造创建一个类的实例
getName()//返回该类的完整名
3.示例代码
定义Students类
class Student{
private String name;
private String number;
public String sex;
public int age;
public Student(String name, String number, int age) {
this.name = name;
this.number = number;
this.age = age;
}
public Student(String name){
this.name = name;
}
private Student(String name, String number){
this.name = name;
this.number = number;
}
private void schooling(){
System.out.println("去上学");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", number='" + number + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
3.1 测试获取成员变量
package com.cqs.reflect_;
import java.lang.reflect.Field;
public class ReflectField {
public static void main(String[] args) throws NoSuchFieldException {
Class<Student> studentClass = Student.class;
//测试getFields()函数
Field []studentFields = studentClass.getFields();
System.out.println("通过getFields获取Student类所有公开属性");
for (Field field:studentFields) {
System.out.println("属性的类型为:"+field.getType()+"属性的名称为:"+field.getName());
}
System.out.println();//换行
//测试getDeclaredFields()函数
Field []studentDeclaredFields = studentClass.getDeclaredFields();
System.out.println("通过getDeclaredFields获取Student类所有属性(包括私有,不包括继承)");
for (Field field :studentDeclaredFields) {
System.out.println("属性的类型为:"+field.getType()+"\t属性的名称为:"+field.getName());
}
System.out.println();//换行
//getField(String)函数
Field field = studentClass.getField("age");
System.out.println("通过getField(\"age\")获取公开属性age");
System.out.println("属性的类型为:"+field.getType()+"\t属性的名称为:"+field.getName());
System.out.println();//换行
//测试getDeclaredField(String)函数
Field DeclaredFiled = studentClass.getDeclaredField("name");
System.out.println("通过getDeclaredField(\"name\")获取私有属性name");
System.out.println("属性的类型为:"+field.getType()+"\t属性的名称为:"+field.getName());
}
}
运行结果:
通过getFields获取Student类所有公开属性
属性的类型为:class java.lang.String属性的名称为:sex
属性的类型为:int属性的名称为:age通过getDeclaredFields获取Student类所有属性(包括私有,不包括继承)
属性的类型为:class java.lang.String 属性的名称为:name
属性的类型为:class java.lang.String 属性的名称为:number
属性的类型为:class java.lang.String 属性的名称为:sex
属性的类型为:int 属性的名称为:age通过getField("age")获取公开属性age
属性的类型为:int 属性的名称为:age通过getDeclaredField("name")获取私有属性name
属性的类型为:int 属性的名称为:age进程已结束,退出代码0
3.2 测试获取成员方法
package com.cqs.reflect_;
import java.lang.reflect.Method;
public class ReflectMethod {
public static void main(String[] args) throws NoSuchMethodException {
Class<Student> studentClass = Student.class;
//测试getMethods()函数
Method[] methods = studentClass.getMethods();
System.out.println("通过getMethods()获取所有公开方法");
for (Method method : methods) {
System.out.println(method.getName());
Class[] plts = method.getParameterTypes();
System.out.println("参数数量为:"+plts.length);
for (Class p : plts) {
System.out.println("参数类型为:"+p.getTypeName());
}
}
System.out.println();//换行
//测试getDeclaredMethods()函数
Method[] DeclaredMethods = studentClass.getDeclaredMethods();
System.out.println("通过getDeclaredMethods()获取所有方法(包括私有,不包括继承)");
for (Method method : DeclaredMethods) {
System.out.println(method.getName());
Class[] plts = method.getParameterTypes();
System.out.println("参数数量为:"+plts.length);
for (Class p : plts) {
System.out.println("参数类型为:"+p.getTypeName());
}
}
System.out.println();//换行
//测试getMethod(参数)函数
Method method = studentClass.getMethod("setName", String.class);
System.out.println("通过getMethod(\"getName\",String.class)获取getName方法");
System.out.println(method.getName());
Class[] plts = method.getParameterTypes();
System.out.println("参数数量为:"+plts.length);
for (Class p : plts) {
System.out.println("参数类型为:"+p.getTypeName());
}
System.out.println();//换行
//测试getDeclaredMethod(参数)函数
Method DeclaredMethod = studentClass.getDeclaredMethod("schooling");
System.out.println("通过getDeclaredMethod(\"schooling\")获取schooling方法");
System.out.println(DeclaredMethod.getName());
Class[] pls = DeclaredMethod.getParameterTypes();
System.out.println("参数数量为:"+pls.length);
for (Class p : pls) {
System.out.println("参数类型为:"+p.getTypeName());
}
}
}
运行结果:
通过getMethods()获取所有公开方法
getNumber
参数数量为:0
getName
参数数量为:0
setName
参数数量为:1
参数类型为:java.lang.String
setNumber
参数数量为:1
参数类型为:java.lang.String
wait
参数数量为:0
wait
参数数量为:2
参数类型为:long
参数类型为:int
wait
参数数量为:1
参数类型为:long
equals
参数数量为:1
参数类型为:java.lang.Object
toString
参数数量为:0
hashCode
参数数量为:0
getClass
参数数量为:0
notify
参数数量为:0
notifyAll
参数数量为:0通过getDeclaredMethods()获取所有方法(包括私有,不包括继承)
getNumber
参数数量为:0
getName
参数数量为:0
setName
参数数量为:1
参数类型为:java.lang.String
schooling
参数数量为:0
setNumber
参数数量为:1
参数类型为:java.lang.String通过getMethod("getName",String.class)获取getName方法
setName
参数数量为:1
参数类型为:java.lang.String通过getDeclaredMethod("schooling")获取schooling方法
schooling
参数数量为:0
3.3 测试获取构造函数
示例代码
package com.cqs.reflect_;
import java.lang.reflect.Constructor;
public class ReflectConstructor {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
//测试getConstructors()函数
Constructor[] constructors = studentClass.getConstructors();
System.out.println("通过getConstructors()获取所有公开构造方法");
for (Constructor con: constructors) {
System.out.println("构造方法名称为:"+con.getName());
Class plts[] = con.getParameterTypes();
System.out.println("参数数量为:"+plts.length);
System.out.println("形参类型为:");
for (Class p: plts) {
System.out.println(p);
}
}
System.out.println();//换行
//测试getDeclaredConstructors()函数
Constructor[] DeclaredConstructors = studentClass.getDeclaredConstructors();
System.out.println("通过getDeclaredConstructors()获取所有构造方法(包括私有,包括继承)");
for (Constructor con : DeclaredConstructors) {
System.out.println("构造方法名称为:"+con.getName());
Class[] plts = con.getParameterTypes();
System.out.println("参数数量为:"+plts.length);
System.out.println("形参类型为:");
for (Class p: plts) {
System.out.println(p);
}
}
}
}
运行结果
通过getConstructors()获取所有公开构造方法
构造方法名称为:com.cqs.reflect_.Student
参数数量为:3
形参类型为:
class java.lang.String
class java.lang.String
int
构造方法名称为:com.cqs.reflect_.Student
参数数量为:1
形参类型为:
class java.lang.String通过getDeclaredConstructors()获取所有构造方法(包括私有,包括继承)
构造方法名称为:com.cqs.reflect_.Student
参数数量为:3
形参类型为:
class java.lang.String
class java.lang.String
int
构造方法名称为:com.cqs.reflect_.Student
参数数量为:1
形参类型为:
class java.lang.String
构造方法名称为:com.cqs.reflect_.Student
参数数量为:2
形参类型为:
class java.lang.String
class java.lang.String
3.4 通过反射创建对象
package com.cqs.reflect_;
import java.lang.reflect.Constructor;
public class Reflect_newInstance {
public static void main(String[] args) throws Exception{
Class studentClass = Student.class;
Constructor c = studentClass.getConstructor(String.class, String.class, int.class);
Object obj = c.newInstance("小明","1001",18);
System.out.println(obj);
//等价于
Student s = new Student("小明", "1001", 10);
System.out.println(s);
}
}
运行结果
Student{name='小明', number='1001', sex='null', age=18}
Student{name='小明', number='1001', sex='null', age=10}
3.5 通过反射修改属性
package com.cqs.reflect_;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Reflect_modifyAttribute {
public static void main(String[] args) throws Exception{
//通过反射创建对象
Class studentClass = Student.class;
Constructor c = studentClass.getConstructor(String.class, String.class, int.class);
Object obj = c.newInstance("小明","1001",18);
//通过属性名获取field对象
Field f = studentClass.getDeclaredField("name");
//取消属性访问权限控制
f.setAccessible(true);
//获取更改前name的值
System.out.println("更改前:"+f.get(obj));
System.out.println(obj);
f.set(obj,"小刚");
System.out.println("更改后:"+f.get(obj));
System.out.println(obj);
}
}
运行结果
更改前:小明
Student{name='小明', number='1001', sex='null', age=18}
更改后:小刚
Student{name='小刚', number='1001', sex='null', age=18}
3.6 通过反射调用方法
package com.cqs.reflect_;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Reflection_callMethod {
public static void main(String[] args) throws Exception{
//通过反射创建对象
Class<Student> studentClass = Student.class;
Constructor c = studentClass.getConstructor(String.class, String.class, int.class);
Object obj = c.newInstance("小明","1001",18);
//获取setName方法并调用
Method m1 = studentClass.getDeclaredMethod("setName", String.class);
m1.invoke(obj,"小飞");
System.out.println(obj);
//获取schooling方法
Method m2 = studentClass.getDeclaredMethod("schooling");
//因为schooling为私有方法,所以得取消权限访问控制
m2.setAccessible(true);
m2.invoke(obj);
}
}
运行结果
去上学
Student{name='小飞', number='1001', sex='null', age=18}