纸上谈反射
Updated:
Class类的使用
- 传送万物皆对象,那么类是谁的对象呢?
- 时java.lang.Class这个类的!没想到吧!
- 所以说任何一个类都是Class类的实例对象
这个实例对象有三种表达方式 :
就不多说了直接上代码好啦
1
2
3
4
5
6
7
8
9
10
11
12
13
14//首先假装我们已经有一个Demo类了,实例化它
Demo demo = new Demo();
//然后我们能怎么得到这个类呢?
//第一种方式 :直接由 类名.class 得到
Class c1 = Demo.class;
//第二种方式 :已知该类的对象,通过 对象.getClass() 得到
Class c2 = demo.getClass();
//第三种方式 :直接通过 Class.forName() 得到
Class c3 = null;
try {
c3 = Class.forName("com.demo.reflect.Demo");
} catch (ClassNotFoundException e) {
e.printStackTrack();
}还有一点要注意的就是
- c1、c2、c3 被称为类的类类型
- 且 c1 是 == c2 == c3 的
通过类的类类型直接创建该类的实例对象
比如像这样 :
1
2
3
4
5
6
7//注意要做一个强制类型转换,还有要处理一下异常
try {
Demo demoFromC1 = (Demo)c1.newInstance();
demoFromC1.print();
} catch (Exception e) {
e.printStackTrack();
}注意能直接创建的的前提是这个类要有无参构造方法
Java动态加载类
- 静态加载类 :
- 即在编译时刻就要加载所有可能用到的类
- 也就是说一个类不存在 整个就编译不通过
- 比如说用new创建对象的话 就属于静态加载
动态加载类 :
- 即在使用时才去加载这个要用到的类
- 也就是说就算这个类不存在
- 只要还没开始使用它 就是可以通过编译的
就比如说 这样 :
1
2
3
4
5
6
7
8
9
10
11
12public static void main(String[] args){
try {
//动态加载类,在运行时加载
Class c = Class.forName(args[0]);
//将这个类转换为交通工具类
Vehicle vehicle = (vehicle)c.newInstance();
//假装有一个run()方法
Vehicle.run();
} catch (Exception e) {
e.printStackTrack();
}
}然后其他类就可以通过实现 Vehicle 这个接口来直接被调用啦,完全不用改动main方法里的代码
Java获取方法信息
“编写一个获取类信息的方法” :
抄写一个获取方法信息的方法 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public void printClassMessage(Object obj) {
//首先获取类类型
Class c = obj.getClass();
//获取类的名称
System.out.println("类的名称为 :" + c.getName());
//getMethods():取得所有public函数
//包括继承父类而来的
Method[] methods = c.getMethods();
//getDeclaredMethods():获取所有该类自己声明的方法
//不论访问权限,不包括父类函数
//c.getDeclaredMethods();
for(int i = 0; i < methods.length; i++) {
//得到方法的返回值类型的类类型
Class returnType = methods.getReturnType();
//打印方法的返回类型
System.out.print(returnType.getName + " ");
//得到方法的名称
System.out.print(methods[i].getName() + "(" );
//获取参数类型(得到的是参数列表的类型的类类型)
Class[] paramTypes = methods[i].getParameterType();
for(Class class : paramTypes) {
//其实这个逗号有点bug但是算了
System.out.print(class.getName() + ",");
}
System.out.println( ")" );
}
}然后要怎么调用呢?这样子 :
1
2
3String s = "hello";
printClassMessage(s);
然后就会打印出String的类信息啦
获取成员变量与构造函数的信息
继续编写一个获取类信息的方法 :
抄写一个获取成员变量的方法 :
1
2
3
4
5
6
7
8
9
10
11
12//getFields()方法获取的是所有public的成员变量信息
//Filed[] fields = c.getFileds();
//getDeclaredFields()获取的是该类自己声明的成员变量
Field[] fidlds = c.getDeclaredFields();
for(Field field : fields) {
Class fieldType = field.getType();
//得到成员变量的类类型
String typeName = fieldType.getName();
//得到成员变量的名称
String filedName = field.getName();
System.out.println(typeName + " " + fieldName);
}抄写一个获取构造函数信息的方法 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14Class c = obj.getClass();
//getConstructors() :获取所有public的构造函数
//Constructor[] cs = c.getConstructors();
//getDeclaredConstructors :获取所有自己定义的构造函数
Constructor[] cs = c.getDeclaredConstructors();
for(Constructor constructor : cs) {
//获取构造函数的参数列表(得到参数列表的类类型)
System.out.print(constructor.getParameterTypes());
for(Class class : paramTypes) {
//同样,这里的逗号也有点bug啦
System.out.print(class.getName() + ",");
}
System.out.println( ")" );
}所以说其实只要得到了这个类的类类型,一切都好说;只需要要c.一下,什么都出来了啦
Java方法反射的基本操作
简单一点来说就是用方法对象来调用方法
不用反射的话是这样的 :
- (假设有一个Demo类,里面有一个tell()方法)
1
2Demo demo = new Demo();
demo.tell();
- (假设有一个Demo类,里面有一个tell()方法)
用反射的话是这样的 :
- (假设tell的参数列表为为 String, int)
1
2
3
4
5
6
7
8
9
10Class c = demo.getClass();
try {
//首先获取到这个方法
Method method = c.getMethod("tell",String.class,int.class);
//然后进行方法的反射操作
//即使用method这个对象来调用方法
method.invoke("你好",2018);
} catch (Exception e) {
e.printStackTrack();
}
- (假设tell的参数列表为为 String, int)
最后的最后
- 为什么要使用反射呢?
- 个人感觉最大的优势可能还是在于易扩展吧
- 就比如说你写的那个Excel导入导出
- 总有一种加上反射就可以随传随导的感觉啊!!!
- 求你了赶紧好好学习一下反射看看能不能改一下好嘛!
- 现有代码的入侵太多了啦 !!!