一:java反射的基础概念
一般当使用一个类的时候,是通过new来创建得到对象。而反射是在运行时刻通过对象来得到这个类。
二:实现
1、需要得到Class,获取Class对象三种方法:
①实例变量 eg:A a=new A();Class
clazz=A.getClass();
②通过类名 eg:Clas clazz=A.class;(只会加载类,不会触发类构造器初始化)
③Class.forName(String className);
Class clazz=Class.forName("类路径.类名");
Class clazz=Class.forName("类路径.类名",false,类名.class.getClassLoader());
初始化参数代表是否对加载的类进行初始化,false代表不进行初始化类,反之则进行。
2、根据需求参照jdk文档中Class的使用
以下实现2个案例
第一个获取类的public方法信息
/**
* 打印类信息
* @author YKW
* @description TODO
*/
public class ClassUtil {
public static void printMethodMessage(Object obj){
//获取类类型
Class c=obj.getClass();//传递的是哪个子类的对象,就是获取哪个子类 类类型
System.err.println("类名:"+c.getName());
//方法对象
Method[] ms=c.getMethods();//c.getDeclaredMethods()第一个获取public方法第二个获取所有方法
for(int i=0;i<ms.length;i++){
//返回值类型的类类型
Class returnType=ms[i].getReturnType();
System.err.print("返回值类型的类类型"+returnType);
System.err.println(returnType.getName());
System.err.println("方法名称:"+ms[i].getName()+"(");
//获取参数类型:得到的参数列表的类型的类类型
Class[] parmTypes=ms[i].getParameterTypes();
for (Class class1:parmTypes) {
System.err.print("参数:"+class1.getName()+",");
}
System.err.println(")");
}
}
}
写个main方法调用
public static void main(String[] args) {
String s="hello";
ClassUtil.printMethodMessage(s);
}
运行结果:
第二个方法反射
/**
* 方法的反射
* @author YKW
* @description TODO
*/
public class MethodDemo1 {
public static void main (String arg[]) {
//获取print(int,int)方法
// 1、获取类的信息,得到类的类类型,
A a1=new A();
Class c=a1.getClass();
//2、获取方法,名称和参数列表决定,
//getMethod获取的是public方法
try {
Method m= c.getMethod("print", new Class[]{int.class,int.class});
//c.getMethod("print", int.class,int.class);
//方法的反射:用m对象来进行方法调用和a1.print效果相同,没有返回值返回null有返回值返回具体的返回值
Object o= m.invoke(a1,new Object[]{10,20});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class A{
public void print(int a,int b){
System.err.println(a+b);
}
public void print(String a,String b){
System.err.println(a+b);
}
}
运行结果:
还有一个小tip:反射操作是编译后操作的(可以通过集合泛型来证明)
该部分引用https://blog.csdn.net/dyl2530/article/details/52191236。
先new 两个List:
-
ArrayList list = new ArrayList();
-
ArrayList<String> list1 = new ArrayList<String>();
list1.add("hello");这是没有问题的,而list1.add(20);错误的,因为泛型限制了数据类型,再来看:
-
Class c1 = list.getClass();
-
Class c2 = list1.getClass();
-
System.out.println(c1 == c2);
可以得到结果为true,即c1=c2,我们知道,反射的操作是编译之后的操作,这说明编译之后集合的泛型是去泛型化的,由此,我们可以下一个结论:Java中集合的泛型,是为了防止错误输入的,只在编译阶段有效,绕过编译就无效了,我可以通过方法的反射来操作,绕过编译:
-
Method m = c1.getMethod("add", Object.class);
-
m.invoke(list1, 100);
-
System.out.println(list1.size());
这时候我们看输出结果,size加了1,说明数据已经加进去了,由此证明了我们的结论是正确的。