1 反射简介
反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果调整或修改应用所描述行为的状态和相关的语义。
核心:允许程序在运行时来进行自我检查并且对内部的成员进行操作
反射机制的作用:
在运行时判断任意一个对象所属的类
在运行时获取类的对象
在运行时访问java对象的属性,方法,构造方法等
反射类库(java.lang.reflect)主要的类:
Field:表示类中的成员变量
Method:表示类中的方法
Constructor:表示类的构造方法
Array:该类提供了动态创建数组和访问数组元素的静态方法
反射的主要用法:
如何获取类的构造方法并使用
如何获取类的成员变量并使用
如何获取类的成员方法并使用
2 Class对象
反射依赖于class对象:用来表示运行时类型信息的对应类
每个类都有唯一一个与之相对应的Class对象;Class类为类类型,而Class对象为类类型对象
每个类都有一个class对象,每当我们编写并且编译一个新创建的类,就会将相关的信息写到我们的.class文件中。当我们new一个新对象,或者引用静态成员变量时,JVM中的类加载器就会将对应的class对象加载到JVM中,JVM再根据类型信息相关的class对象,创建我们需要的实例对象或者提供静态变量的引用值。
特点:
Class类也是类的一种,class则是关键字
Class类只有一个私有的构造函数,只有JVM能够创建Class类的实例
JVM中只有唯一一个和类相对应的Class对象来描述其类型信息
获取Class对象的三种方式:
1.Object->getClass()
2.任何数据类型(包括基本数据类型)都有一个静态的class属性
3.通过Class类的静态方法:forName(String className) (常用)
public class ReflectTarget {
public static void main(String[] args) throws ClassNotFoundException {
//第一种方式获取class对象
ReflectTarget reflectTarget=new ReflectTarget();
Class class1 = reflectTarget.getClass();
System.out.println(class1.getName());
//第二种方式获取class对象
Class class2 = ReflectTarget.class;
System.out.println(class2.getName());
//第三种方式获取class对象
Class class3 = Class.forName("com.base.reflect.ReflectTarget");
System.out.println(class3.getName());
}
}
Class对象就像一面镜子,透过这面镜子可以看到类的结构,所以我们称这种方式为反射
3 获取构造方法
通过Class对象可以获取某个类中的构造方法
获取构造方法:
1)批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
2)获取单个的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有
调用构造方法: Constructor-->newInstance(Object... initargs)
1.定义类的多种类型的构造函数
public class ReflectTarget {
//---------构造函数-----------
//(默认的带参数构造函数)
ReflectTarget(String str) {
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造函数
public ReflectTarget() {
System.out.println("调用了公有的无参构造方法 。。。");
}
//有一个参数的构造函数
public ReflectTarget(char name) {
System.out.println("调用了带有一个参数的构造方法,参数值为 " + name);
}
//有多个参数的构造函数
public ReflectTarget(String name, int index) {
System.out.println("调用了带有多个参数的构造方法,参数值为【目标名】: " + name + " 【序号】" + index);
}
//受保护的构造函数
protected ReflectTarget(boolean n){
System.out.println("受保护的构造方法 n :" + n);
}
//私有的构造函数
private ReflectTarget(int index){
System.out.println("私有的构造方法 序号:" + index);
}
}
2.获取构造函数
import java.lang.reflect.Constructor;
//反射获取类的构造函数
public class ConstructorCollector {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class.forName("com.base.reflect.ReflectTarget");
//获取全部公有构造函数
System.out.println("获取全部公有构造函数");
Constructor[] constructors=clazz.getConstructors();
for(Constructor c:constructors)
{
System.out.println(c);
}
//获取全部构造方法,包括私有、受保护、默认、公有
System.out.println("获取全部构造方法,包括私有、受保护、默认、公有");
Constructor[] constructors1=clazz.getDeclaredConstructors();
for(Constructor c:constructors1)
{
System.out.println(c);
}
//获取单个公有构造方法
System.out.println("获取单个公有构造方法");
Constructor con = clazz.getConstructor(String.class,int.class);//构造方法的参数
System.out.println(con);
//获取私有构造方法
System.out.println("获取私有构造方法");
con=clazz.getDeclaredConstructor(int.class);
System.out.println(con);
}
}
3.调用公有构造函数创建实例对象
//获取单个公有构造方法
Constructor con = clazz.getConstructor(String.class,int.class);//构造方法的参数
System.out.println(con);
//调用公有构造函数创建实例
ReflectTarget reflectTarget= (ReflectTarget) con.newInstance("hello",1);
4.调用私有构造函数创建实例对象
如果直接向上面那样创建,因为是私有的构造函数,所以程序在运行时出错
应该设置con.setAccessible(true)
Constructor con=clazz.getDeclaredConstructor(int.class);
//调用私有构造函数创建实例
con.setAccessible(true);//暴力访问,忽略掉访问修饰符
ReflectTarget reflectTarget= (ReflectTarget) con.newInstance(1);
4 获取成员变量
通过Class对象可以获取某个类中的成员变量
获取成员变量的方法
1.批量的
Field[] getFields():获取所有的"公有字段"
Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有
2.获取单个的:
public Field getField(String fieldName):获取某个"公有的"字段;
public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
设置字段的值
Field --> public void set(Object obj,Object value)
obj:要设置的字段所在的对象;
value:要为字段设置的值
1.定义类的成员变量
public class ReflectTarget {
//**************字段*******************//
public String name;
protected int index;
char type;
private String targetInfo;
@Override
public String toString(){
return "ReflectTarget [name=" + name + ", index=" + index + ", type=" + type
+ ", targetInfo=" + targetInfo + "]";
}
}
2.通过反射获取类的成员变量
import java.lang.reflect.Field;
public class FieldCollector {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class clazz = Class.forName("com.base.reflect.ReflectTarget");
//1.获取所有公有字段
System.out.println("获取所有公有字段");
Field[] fields=clazz.getFields();
for(Field f:fields)
System.out.println(f);
//2.获取所有字段,包括私有,默认,受保护,公有
System.out.println("获取所有字段,包括私有,默认,受保护,公有");
Field[] fields2=clazz.getDeclaredFields();
for(Field f:fields2)
System.out.println(f);
//3.获取单个公有字段
System.out.println("获取单个公有字段");
Field f = clazz.getField("name");
System.out.println(f);
//4.获取单个私有字段
System.out.println("获取单个私有字段");
Field f2 = clazz.getDeclaredField("targetInfo");
System.out.println(f2);
}
}
3.设置公有字段值
Field f = clazz.getField("name");
//获取对象
ReflectTarget reflectTarget= (ReflectTarget) clazz.getConstructor().newInstance();
f.set(reflectTarget,"小美");//设置对象reflectTarget的name字段为小美
System.out.println(reflectTarget.name);
4.设置私有字段的值
跟构造函数相同,如果直接设置会报错,需要setAccessible(true)
Field f2 = clazz.getDeclaredField("targetInfo");
ReflectTarget reflectTarget2= (ReflectTarget) clazz.getConstructor().newInstance();
f2.setAccessible(true);
f2.set(reflectTarget2,"1345124512");//设置对象reflectTarget2的targetInfo字段
5 获取成员方法
通过Class对象可以获取某个类中的成员方法
获取成员方法的方法
1.批量的方法:
public Method[] getMethods() 获取所有"公有方法"(包含了父类的方法也包含Object类)
public Method[] getDeclaredMethods() 获取所有的成员方法,包括私有的(不包括继承的)
2.获取单个的:
public Method getMethod(String name,Class<?>... parameterTypes) name-方法名; Class -形参的Class类型对象
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
调用函数方法
Method --> public Object invoke(Object obj,Object... args)
参数说明: obj : 要调用方法的对象; args:调用方式时所传递的实参;
1.定义成员方法
public class ReflectTarget {
//***************成员方法***************//
public void show1(String s){
System.out.println("调用了公有的,String参数的show1(): s = " + s);
}
protected void show2(){
System.out.println("调用了受保护的,无参的show2()");
}
void show3(){
System.out.println("调用了默认的,无参的show3()");
}
private String show4(int index){
System.out.println("调用了私有的,并且有返回值的,int参数的show4(): index = " + index);
return "show4result";
}
}
2.通过反射获取类的成员方法
import com.sun.javafx.binding.StringFormatter;
import java.lang.reflect.Method;
public class MethodCollector {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class clazz=Class.forName("com.base.reflect.ReflectTarget");
//1.获取公有的成员方法(包括继承)
System.out.println("获取公有的成员方法");
Method[] methods=clazz.getMethods();
for(Method m:methods)
System.out.println(m);
//2.获取全部成员方法(不包括继承)
System.out.println("获取全部成员方法");
Method[] methods2=clazz.getDeclaredMethods();
for(Method m:methods2)
System.out.println(m);
//3.获取单个公有成员方法
System.out.println("获取单个公有成员方法");
Method m=clazz.getMethod("show1", String.class);
System.out.println(m);
//4.获取单个私有成员方法
System.out.println("获取单个私有成员方法");
Method m2=clazz.getDeclaredMethod("show4",int.class);
System.out.println(m);
}
}
3.调用公有成员方法
Method m=clazz.getMethod("show1", String.class);
System.out.println(m);
ReflectTarget reflectTarget= (ReflectTarget) clazz.getConstructor().newInstance();
m.invoke(reflectTarget,"反射方法");//执行对象的show1方法
4.调用私有成员方法
System.out.println("获取单个私有成员方法");
Method m2=clazz.getDeclaredMethod("show4",int.class);
System.out.println(m2);
ReflectTarget reflectTarget2= (ReflectTarget) clazz.getConstructor().newInstance();
m2.setAccessible(true);
m2.invoke(reflectTarget2,1);//执行对象的show4方法