反射
1、概述
1.1 定义
在运行程序的过程中,动态获取一个类中的基本信息
2、Class类型
2.1 定义
java.lang.Class是API中提供的一个类,可以表示java中所有的类型,包括基本类型和引用类型。
2.2 使用Class类对向表示不同类型
表示基本类型
//对象c表示int类型
CLass c = int.class;
//判断对象c是不是基本类型
System.out.println(c.isPrimitive());
//获取对象c所代表的类型的名字
System.out.println(c.getName());
表示类类型
假设有个Student类
//对象c代表Student类型
Class c = Student.class;
//获取Student类的全限定名
System.out.println(c.getName());
表示接口类型
//对象c表示List接口类型
Class c = List.class;
//判断对象c是不是接口类型
System.out.prinln(c.isInterface());
System.out.println(c.getName());
表示数组类型
Class c;
c = Student[].class;
//判断对象c是不是数组类型
System.out.println(c.isArray());
//获取数组的简单名
System.out.println(c.getSimpleName());
//获取该数组具体类型是什么
System.out.println(c.getComponentType().getSimpleName());
运行结果
true
Student[]
Student
3、获取Class对象的方式
总的来说有下面的三种方式,但不同类型对象使用的方式有些许区别
方式一:使用类型名称直接获取**(最常用)**
方式二:使用Class类中的静态方法forName获取
方式三:使用对象调用getClass方法获取
获取基本类型的Class对象:
只有一种方式:类型名称直接获取
Class c = int.class;
获取接口类型的Class对象:
两种方式:
方式1:类型名称直接获取
Class c = Action.class;
方式2:使用Class类中的静态方法forName获取
Class c = Class.forName("全限定名");
获取数组类型的Class对象:
两种方式:类型名称直接获取
方式1:
Class c = int[].class;
方式2:使用对象调用getClass方法获取
int[] arr = new int[4];
Class c = arr.getClass();
获取类类型的Class对象
三种方式
方式1:类型名称直接获取
Class c = Student.class;
方式2:使用Class类中的静态方法forName获取
Class c = Class.forName("全限定名");
方式3:使用对象调用getClass方法获取
Student stu = new Student();
Class c3 = stu.getClass();
3、获取类中信息的方法
3.1 获取类的基本信息
方法名 | 功能 | 补充 |
---|---|---|
getName() | 获取类的全限定名 | |
getSimpleName() | 获取类的简单名 | |
getPackage() | 获取所属的包 | 获取包名:getPackage().getName() |
getModifiers() | 返回此类或接口的修饰符的整数编码 | 常和Modifier类中的toString()方法搭配使用,可以获取修饰符名称 |
getSuperclass() | 获取父类型 | 搭配getName使用获取父类类名 |
getInterfaces() | 返回的是一个数组。返回由该对象表示的类或接口实现的接口 | 搭配Arrays工具类中的toString方法使用 |
isAssignableFrom() | 判断类对象表示的类或接口是否与由指定的Class 类表示的类或接口相同 |
例如:
以下均以Student类为例进行操作
package blog_1.reflect_0;
interface Action{
void run();
}
interface Mark{
void star();
}
public class Student implements Action,Mark{
private String name; //私有
int age; //普通
public static int num; //静态
public Student() {}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//定义普通方法
public String sayHello(String name) {
return "hello!" + name;
}
//重写接口中的方法
@Override
public void star() {
// TODO Auto-generated method stub
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
package blog_1.reflect_0;
import java.lang.reflect.Modifier;
import java.util.Arrays;
interface Action{
void run();
}
interface Mark{
void star();
}
public class Student implements Action,Mark{
private String name; //私有
int age; //普通
public static int num; //静态
public Student() {}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//定义普通方法
public String sayHello(String name) {
return "hello!" + name;
}
//重写接口中的方法
@Override
public void star() {
// TODO Auto-generated method stub
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
@SuppressWarnings("all")
class Demo01{
public static void main(String[] args) throws Exception{
//这里通过创建学生对象调用getClass()方法获取Class对象
Student stu = new Student();
Class c = stu.getClass();
//获取类的全限定名
System.out.println(c.getName());
//获取类的简单类名
System.out.println(c.getSimpleName());
//获取类所属包的名字
System.out.println(c.getPackage().getName());
//获取类的修饰符
System.out.println(c.getModifiers()); //这里获取的是编码
System.out.println(Modifier.toString(c.getModifiers())); //间接获取修饰符名
//获取类的父类型的名字
System.out.println(c.getSuperclass().getName());
//获取类实现的所有接口
System.out.println(Arrays.toString(c.getInterfaces()));
//判断对象所属类型是不是c的父类型
Class c1 = Object.class;
Class c2 = Action.class;
Class c3 = Mark.class;
Class c4 = String.class;
System.out.println(c1.isAssignableFrom(c)); //判断c1是不是c代表类型的父类型
System.out.println(c2.isAssignableFrom(c));
System.out.println(c3.isAssignableFrom(c));
System.out.println(c4.isAssignableFrom(c));
}
}
结果:
blog_1.reflect_0.Student
Student
blog_1.reflect_0
1
public
java.lang.Object
[interface blog_1.reflect_0.Action, interface blog_1.reflect_0.Mark]
true
true
true
false
3.2 获取类中声明的属性
java中将属性类型都打包到了java.lang.reflect.Field这个包中。
获取类中public修饰的属性,包括继承过来的public属性
方法 | 功能 |
---|---|
Field[] getFields() | 返回一个数组,获取所有权限为public的属性 |
Field getField(String name) | 返回一个Field对象,获取权限为public的指定对象 |
获取类中声明的属性(含私有的)但是不能获取从父类中继承的属性
方法 | 功能 |
---|---|
Filed[] getDeclaredFields() | 返回Class对表示的所有实体的成员变量,但不包括继承过来的属性 |
Field getDeclaredField(String name) | 返回Class对象所表示的类或接口的指定已声明成员变量 |
例如:
public static void main(String[] args) {
Class c = Student.class;
//获取类中所有声明的属性,不包括从父类继承过来的
Field[] fields = c.getDeclaredFields();
for(Field f : fields) {
System.out.println("属性的修饰符:" + Modifier.toString(c.getModifiers()));
System.out.println("属性的类型:" + f.getType().getName());
System.out.println("属性的名称:" + f.getName());
System.out.println("-----------------");
}
}
结果:
属性的修饰符:public
属性的类型:java.lang.String
属性的名称:name
--------------------
属性的修饰符:public
属性的类型:int
属性的名称:age
-----------------
属性的修饰符:public
属性的类型:int
属性的名称:num
-----------------
3.3 获取类中声明的方法
获取当前类中的public方法,包含从父类中继承的public方法
方法名 | 功能 |
---|---|
Method[] getMethods() | 返回一个数组,获取所有权限为public的方法 |
Method getMethod(String name,Class<?>…parameterTypes) | 返回method对象,获得权限为public的指定方法 |
获取当前类中声明的方法(包含私有的),但不能获取父类中继承过来的方法
方法名 | 功能 |
---|---|
method[] getDeclaredMethods() | 返回Method类型数组,返回所有方法,不包括从父类继承过来的 |
Method getDeclaredMethod(String name,Class<?>…parameterTypes) | 返会Method对象,返回指定公共成员方法,name是指定方法名称,parameterTypes是指定方法参数类型 |
其他一些相关方法
方法名 | 功能 |
---|---|
getReturnType() | 获取方法返回类型 |
getParameterTypeCount() | 获取方法中参数个数 |
getExceptionTypes() | 获取方法抛出异常类型 |
getParameterTypes() | 获取参数列表 |
例如:
public static void main(String[] args) {
Student stu = new Student();
Class c = stu.getClass();
Method[] methods = c.getDeclaredMethods();
for(Method m : methods) {
//获取方法的修饰符
System.out.println(Modifier.toString(m.getModifiers()));
//获取方法的返回类型
System.out.println(m.getReturnType().getSimpleName());
//获取方法的名字
System.out.println(m.getName());
System.out.println("方法参数个数:" + m.getParameterCount());
//获取方法的参数列表
Class<?>[] paramArr = m.getParameterTypes();
//输出方法的参数列表
System.out.println("\t" + Arrays.toString(paramArr));
//获取方法所抛出的异常类型
Class<?>[] exceptionArr = m.getExceptionTypes();
System.out.println("方法抛出异常个数" + exceptionArr.length);
//输出方法所抛出的异常列表
System.out.println("\t" + Arrays.toString(exceptionArr));
System.out.println("----------------------------");
}
}
public
void
run
方法参数个数:0
[]
方法抛出异常个数0
[]
----------------------------
public
String
getName
方法参数个数:0
[]
方法抛出异常个数0
[]
----------------------------
public
void
setName
方法参数个数:1
[class java.lang.String]
方法抛出异常个数0
[]
----------------------------
public
void
star
方法参数个数:0
[]
方法抛出异常个数0
[]
----------------------------
public
String
sayHello
方法参数个数:1
[class java.lang.String]
方法抛出异常个数0
[]
----------------------------
java.lang.reflect.Method表示类中的方法
3.4 获取类中声明的构造器
获取当前类中的public构造器
方法名 | 功能 |
---|---|
public Constructor<?>[] getConstructors() | 返回一个数组,数组中是Constructor对象 |
public Constructor getConstructor(Class<?>…parameterTypes) | 返回一个指定的构造器对象,class是类名,parameterTypes是参数类型 |
获取当前类汇总所有的构造器,包含私有的
方法名 | 功能 |
---|---|
public Constructor<?>[] getDeclaredConstructors() | 返回所有 构造器对象 |
public Constructor getDeclaredConstructors(Class<?> …parameterTypes) | 返回指定的构造器对象 |
public static void main(String[] args) {
Student stu = new Student();
Class c= stu.getClass();
//获取类中所有的public构造器
Constructor[] constructors = c.getConstructors();
for(Constructor constructor : constructors) {
//构造器的修饰符
System.out.println(Modifier.toString(constructor.getModifiers()));
//构造器的名字
System.out.println(constructor.getName());
//构造器的参数列表
Class[] paramList = constructor.getParameterTypes();
System.out.println(java.util.Arrays.toString(paramList));
//构造器的抛出异常
Class[] exceptionList = constructor.getExceptionTypes();
System.out.println(java.util.Arrays.toString(exceptionList));
System.out.println("------------------------");
}
}
结果:
public
blog_1.reflect_0.Student
[]
[]
------------------------
public
blog_1.reflect_0.Student
[class java.lang.String, int]
[]
------------------------
4、反射访问和赋值属性
访问类中属性
1、非私有非静态属性
set(对象,属性值 ) get(对象)
2、非静态私有属性
先使用setAccessible(true)方法获取访问权限 再使用set(对象,属性值)赋值,通过 get(对象)方法获取
3、静态属性 set(null,属性值) get(null);
public static void main(String[] args) throws Exception {
Student stu = new Student();
Class c = stu.getClass();
//获取类中名字叫name的私有属性
Field f1 = c.getDeclaredField("name");
//设置私有属性可以被访问,否则会报错
f1.setAccessible(true);
//使用反射的方式给指定对象的name属性赋值为tom
f1.set(stu, "tom");
//使用反射的方式获取这个属性的值
System.out.println(f1.get(stu));
System.out.println("-----------------");
//获取类中名字叫age的属性
Field f2 = c.getDeclaredField("age");
f2.set(stu, 20);
System.out.println(f2.get(stu));
System.out.println("-----------------");
Field f3 = c.getDeclaredField("num");
//用反射的方式,给静态属性num赋值,不需要对象
f3.set(null, 99);
System.out.println(f3.get(null));
}
结果:
tom
-----------------
20
-----------------
99
5、反射调用方法
反射调用方法的方法:
public Object invoke(Object obj,Object…args)
obj是指要调用方法的对象,静态方法就传null
args表示要调用的方法的参数列表
访问类中方法
1、非静态方法 invoke (obj,params.class)
2、静态方法 invoke(null,params.class)
3、静态无参 invoke(null,null)
public static void main(String[] args) throws Exception{
Student stu = new Student();
Class c = stu.getClass();
//获取类中的toString方法,没有参数,这是从父类中继承的方法
Method m1 = c.getMethod("toString", null); //toString是要获取的方法的名字,后面一个指定是参数
//利用反射的方式调用stu对象中的这个方法,没有参数,并接收执行结果
Object result = m1.invoke(stu, null); //括号内前一个参数是对象名,后一个是参数名
//输出执行结果
System.out.println(result);
System.out.println("-------------");
//获取类中的sayHello方法,需要一个String类型的参数
Method m2 = c.getMethod("sayHello", String.class);
//通过反射的方式调用stu对象中的而这个方法,参数是“tom”,并接收执行结果
result = m2.invoke(stu, "tom");
System.out.println(result);
}
6、反射创建对象
反射调用类中无参构造器创建对象
public static void main(String[] args) throws Exception{
Class c = Student.class;
//这里会默认调用无参构造器来创建对象
Object obj = c.newInstance();
System.out.println(obj);
}
反射调用类中有参构造器创建对象
public static void main(String[] args) throws Exception{
Class c = Student.class;
//获取类中的带参构造器
Constructor constructor = c.getConstructor(String.class, int.class);
//调用有参构造器来创建对象,传入对应的参数值
Object obj = constructor.newInstance("ton",20);
System.out.println(obj);
}