反 射
一、简介
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
自己理解:
想知道一个类有哪些方法属性,java里针对方法、属性、类的描述,获取一个类有哪些方法、属性、接口就是反射机制。(不用看到源代码,比如jar包)
二、相关类
(1)Class类
1.介绍:
既然万事万物皆对象,那么我们的类是不是对象呢?是的,我们写的每一个类都是对象,是 java.lang.Class 类的对象。也就是说,每一个类既有自己的对象,同时也是 Class 类的对象。
2.复习一下泛型:
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。 Java语言引入泛型的好处是安全简单。
对于数据结构来说,泛型用于指定当前数据结构存储的元素类型,例如:ArrayList<String>表示当前的数组线性表只能存储String类型的数据。
也可以在List中存储自定义类型,例如:LinkedList<Student>表示当前的双向链表中只能存储Student的对象。
3.API的定义:
java.lang
类 Class<T>
java.lang.Object
|__java.lang.Class<T>
类型参数:
T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是 Class<String>。如果将被建模的类未知,则使用 Class<?>。
4.生成对象:
返回值 static Class<?>
类名 forName(String className)
返回与带有给定字符串名的类或接口相关联的 Class 对象。
代码:Class cls =Class.forName("com.zzxtit.mvc.ref.UserInfo");
5.常用方法:
(以下获取的Method都是成员方法,不是类方法)
获得当前类的public Method 以及当前类继承的超类的public Method
Method[] arrMethods = classType. getMethods();
获得当前类声明的所有Method:(即本类重写的父类的Method和自己独立声明的Method)
Method[] arrMethods = classType. getDeclaredMethods();
获得当前类指定的public Method 以及当前类继承的超类指定的public Method
Method method = classType. getMethod(String name,Class<?>... parameterTypes); 没有就写null
获得当前类声明的指定的Method:
Method method = classType. getDeclaredMethod(String name,Class<?>... parameterTypes); 没有就写null
(前面是方法名,后面是参数列。因为成员方法可以重名。但参数列不能一样。)
parameterTypes 参数是 Class 对象的一个数组,它按声明顺序标识该方法的形参类型。为什么前面写泛型,因为一个方法参数类型都是不一样的。
(String name写字符串,即方法名。后面参数)
没有方法能够获得当前类超类的private方法和属性。
(2)Method类
1.API的定义:
public final class Method
extendsAccessibleObject
implementsGenericDeclaration, Member
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
2.生成对象:
常规生成。见上面Class类的代码代码
3.常用方法:
//这里先不深究
通过反射动态运行指定Method:
Object obj = method. invoke(Object obj, Object... args);
invoke(Object obj, Object... args) |
其余方法Class类已讲了。
(3)Field类
1.API的定义:
public final class Field
extendsAccessibleObject
implementsMember
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
2.生成对象:
“常规生成”
★这里可以重点理解一下
Field field = classType. getField(String name); (字段)
field是个Field对象。假如说get到的是Stu类中的属性stuNo,这个属性是个Field对象。它们共用hash地址只不过是临时(动态)的
3.常用方法:
获得当前类以及超类的public Field:
Field[] arrFields = classType. getFields();
获得当前类声明的所有Field:
Field[] arrFields = classType. getDeclaredFields();
获得当前类以及超类指定的public Field:
Field field = classType. getField(String name);
获得当前类声明的指定的Field:
Field field = classType. getDeclaredField(String name);
通过反射动态设定Field的值:
(将指定对象变量上此 Field
对象表示的字段设置为指定的新值。)
fieldType.set(Object obj, Object value);
通过反射动态获取Field的值:
(返回指定对象上此 Field 表示的字段的值。)
Object obj = fieldType. get(Object obj);
( )用于要来一波代码了:
StuInfo.java
package com.zzxtit.mvc.ref;
public class StuInfo {
public String stuNo;
String stuName;
private String passwd;
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
@Override
public String toString() {
return "StuInfo [stuNo=" + stuNo + ", stuName=" + stuName + ", passwd=" + passwd + "]";
}
}
Refmf.java
package com.zzxtit.mvc.ref;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Refmf {
public static void main(String[] args) {
try {
Class cls = Class.forName("com.zzxtit.mvc.ref.StuInfo");
//Method method0 = cls.getMethod("setStuNo", String.class);
/*StuInfo中错误演示代码
* private void setStuNo(String stuNo) {
this.stuNo = stuNo;
}*/
//System.out.println("-----证明打不出非public的------>"+method0);
/*java.lang.NoSuchMethodException: com.zzxtit.mvc.ref.StuInfo.setStuNo(java.lang.String)
at java.lang.Class.getMethod(Class.java:1786)
at com.zzxtit.mvc.ref.Refmf.main(Refmf.java:10)*/
Method[] methods=cls.getDeclaredMethods();
for(Method method : methods){
System.out.println("---methodName--->"+method.getName());
System.out.println("---ReturnType--->"+method.getReturnType());
System.out.println("方法返回值");
for(Class pt:method.getParameterTypes()){
System.out.println("---methodName--->"+pt.getName());
}
System.out.println("==================分界线===========");
}
System.out.println("~~~~~~~~~~~~~~刘循子墨大波浪分界线~~~~~~~~~~~~~~~~~~");
//生成这个类(StuInfo)的实例
Object obj = cls.newInstance();
System.out.println("--------发现这个getClass得到StuInfo----------->" + obj.getClass());
for(Field field : cls.getDeclaredFields()){
System.out.println("--------------------------->" + field);
if("passwd".equals(field.getName())){
//用暴力的方法让private的字段可以用
field.setAccessible(true);
field.set(obj, "123456");
}
}
Method method = cls.getMethod("toString", null);
Method method0 = cls.getMethod("setStuName", String.class);
/*博客上这样写↓:对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。*/
method0.invoke(obj, "王大锤");//对带有“王大锤”(String)类型的参数 的 obj 对象 、
//调用method0表示的底层方法。 即对obj这个实例执行 setStuName("王大锤");
System.out.println("=======================>" + method.invoke(obj, null) );
//对obj这个实例执行toString();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果:
---methodName--->toString
---ReturnType--->class java.lang.String
方法返回值
==================分界线===========
---methodName--->setStuName
---ReturnType--->void
方法返回值
---methodName--->java.lang.String
==================分界线===========
---methodName--->getPasswd
---ReturnType--->class java.lang.String
方法返回值
==================分界线===========
---methodName--->setStuNo
---ReturnType--->void
方法返回值
---methodName--->java.lang.String
==================分界线===========
---methodName--->getStuNo
---ReturnType--->class java.lang.String
方法返回值
==================分界线===========
---methodName--->getStuName
---ReturnType--->class java.lang.String
方法返回值
==================分界线===========
---methodName--->setPasswd
---ReturnType--->void
方法返回值
---methodName--->java.lang.String
==================分界线===========
~~~~~~~~~~~~~~刘循子墨大波浪分界线~~~~~~~~~~~~~~~~~~
--------发现这个getClass得到StuInfo----------->classcom.zzxtit.mvc.ref.StuInfo
--------------------------->public java.lang.Stringcom.zzxtit.mvc.ref.StuInfo.stuNo
--------------------------->java.lang.String com.zzxtit.mvc.ref.StuInfo.stuName
--------------------------->private java.lang.Stringcom.zzxtit.mvc.ref.StuInfo.passwd
=======================>StuInfo [stuNo=null, stuName=王大锤, passwd=123456]