Java反射机制
一、什么是反射,为什么被推崇
JAVA反射机制:在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
作用:正常是知道类才能去创建对象,而现在 既可以用类来获取对象,又可以通过对象获取类的信息。简单来说就是不用new了。
实现方式:获取某类对应的Class对象,并通过Class对象使用该类中的构造器、属性、方法、内部类。
这里提供一个类,下面所有例子都是由此类推衍
package test;
public class MyTest{
//成员变量
private int x;
private String y;
//构造器
public MyTest(int i){
System.out.println(i);
}
public MyTest(int i,String str){
System.out.println(i+str);
}
//成员方法
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
}
二、反射的三种实现方法
反射就是获取某类对应的Class对象。Class对象能做什么在三中进行说明。
1.Object类中的方法 obj.getClass()
直接举例
//创建了一个类的对象
Mytest m = new Mytest();
//获取对象的Class对象
Class c = m.getClass();
//控制台打印c对象获取的类名,目的是证明取到此类的Class对象了
System.out.println(c.getName());
其中c是对象m通过getClass()方法获取的Class对象。
2.通过 类名.class 直接获取Class对象
//创建了一个类的对象
Class c = Mytest.class;
System.out.println(c.getName());
3.通过Class类的forName(String className)方法获取
//获取test包下Mytest类的Class对象
Class c = Class.forName("test.Mytest");
System.out.println(c.getName());
注:这里的参数字符串应该是带包名的类名。因为 包名.类名 才是一个类的全名。
三、获取类中的构造器及构造器的属性
1. getDeclaredConstructors()获取全部构造器
其中c为Class类型的对象,返回值是Constructor[]类型,也就是全部构造器的数组。
//获取Mytest的Class对象
Class c = Mytest.class;
//获取Mytest的全部构造器数组
Constructor[] constructors = c.getDeclaredConstructors();
//再遍历一下,得到每一个数组
for(int i = 0; i<constructors .length;i++){
Constructor constructor = constructors[i];
//获取类中的构造器名称与构造器参数个数
System.out.println(constructor.getName()+" "+constructor.getParameterCount());
//获取全部参数的数组
Class[] paramTypes = constructor.getParameterTypes();
//遍历每一个参数的类型
for(int j = 0 ;j<paramTypes.length;j++){
System.out.println(paramTypes[j]);
}
}
2. getDeclaredConstructor(Class<?>…parameterTypes)获取指定构造器
先说下参数部分。这是个泛型,如果不想了解泛型我就直接给你说在这的意思。
如果有一个int型的参数,就应该写成:c.getDeclaredConstructor(int.class)
如果第一个参数是int型,第二个是String型 就写成:c.getDeclaredConstructor(int.class,String.class)
Class c = Mytest.class;
//我在这就只获取带有两个参数的方法来举例了
Constructor constructor = c.getDeclaredConstructor(int.class,String.class);
//打印下名称和参数数量证明我们获取对了
System.out.println(constructor.getName()+" "+constructor.getParameterCount());
3.Constructor对象的方法!*(我认为是精髓)
getName():返回的是constructor的名字
getParameterCount():返回此构造函数参数的个数
getParameterTypes():获取参数的类型
getDeclaringClass():获取constructor所属的类
newInstance(Class<?>…parameterTypes):通过构造器去创建对象*
其他的都好理解,我直接说最后一个newInstance(Class<?>…parameterTypes)
Class<?>…parameterTypes不理解去上边三、2找,跟这是一样的。
public static void main(String[] args){
//获取Class对象
Class c = Mytest.class;
Constructor constructor;
Mytest m;
try {
//获取了构造器因为参数类型可能会写的不对,所以要处理异常
constructor = c.getDeclaredConstructor(int.class, String.class);
//通过带两个参数构造器生成Mytest型的对象,也是怕参数类型不对,所以要处理异常
m= (Mytest)constructor.newInstance(12345,"上山打老虎");
//我这图方便,就用Exception抓异常,但并不推荐。
} catch (Exception e) {
e.printStackTrace();
}
}
四、获取类中的方法及方法的属性
1. getDecaredMethods() 方法获取全部方法的方法,返回值是Method型的的数组
Class c = Mytest.class;
//获取类的全部方法的数组
Method[] methods = c.getDeclaredMethods();
//遍历
for(Method method:methods ){
//打印描述此 Method 的字符串
System.out.println(method.toString() );
}
控制台输出(这里是Mytest,我实际写的时候是TestReflect类):
2. getDeclaredMethod(String name, Class<?>… parameterTypes)方法可获取指定的方法 。参数name是方法名的字符转,parameterTypes…是方法的参数的类型。返回值是Method型对象
Class c = Mytest.class;
//获取名为setX,参数为int型的方法
Method method = c.getDeclaredMethod("",int.class);
System.out.println(method.toString());
控制台输出为
3.Method对象的方法
getReturnType();获得返回值类型 Class
getModifiers();获得访问修饰符的组合(int)
getarameterTypes:获得参数类型的数组 Class[]
getName();获得方法名
setAccessible();设置方法是否为可访问
invoke(Object obj, Object… args) 调用指定方法*
这里说一下最后一个方法,第一个参数为目标对象(方法不能脱离对象而运行哦~),第二个参数args为当前方法的参数列表。看例子就容易明白
public static void main(String[] args) {
//获取Class对象
Class c = MyTest.class;
try {
//获取参数为int型的构造器
Constructor constructor = c.getDeclaredConstructor(int.class);
//利用构造器实例化出MyTest 对象
MyTest m = (MyTest)constructor.newInstance(1);
//获取set(int i)方法
Method method0 = c.getDeclaredMethod("setX",int.class);
//执行set方法
method0.invoke(m,123);
//获取get()方法
Method method1 = c.getDeclaredMethod("getX");
//执行get方法,并获得int型的返回值
int i = (int)method1.invoke(m);
//打印取到的返回值
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
}
}
五、获取类中的成员变量
1. getDeclaredFields() 方法获取全部成员变量的方法,返回值是Field型的数组
public static void main(String[] args) {
Class c = Mytest.class;
//获取类的全部方法的数组
Field[] fields= c.getDeclaredFields();
//遍历
for(Field field:fields ){
//打印描述此 Field 的字符串
System.out.println(field.getName());
}
}
控制台输出为:
2. getDeclaredField(String name) 方法获取指定成员变量的方法。参数是变量名称,返回值是Field型变量
public static void main(String[] args) {
Class c = Mytest.class;
//获取类的全部方法的数组
Field field= c.getDeclaredField("x");
3. Field类的一些常用方法
下面是Field类的一些方法:
public static void main(String[] args) throws Exception{
Class c = Mytest.class;
Constructor constructor = c.getConstructor(int.class);
Mytest tf = (Mytest) constructor.newInstance(1);
//获取名称为x的变量
Field field= c.getDeclaredField("x");
//获取属性的类型
Class c1 = field.getType();
System.out.println("类型是:"+c1.getName());
//获取属性的修饰符,并利用Modifier的toString解析为String
String modifier = Modifier.toString(field.getModifiers());
System.out.println("修饰符是:"+modifier);
//setAccessible(true)的作用是可以强行访问private的类型
field.setAccessible(true);
//获取属性值get(obj)
int i = (int)field.get(tf);
System.out.println("属性值是:"+i);
//设置属性值
field.set(tf, 123456);
}
控制台输出为:
六、获取类中的内部类
楼主只会这一种(通过Class.forName()获取),还没失手过。
Class c = Class.forName(“test.MyTest$InnerClass”);
来源:CSDN
作者:秒怂_z
链接:https://blog.csdn.net/weixin_43584835/article/details/104058443