阅读目录
一、Class类的使用
二、动态加载类
三、获取方法信息
四、获取成员变量、构造函数信息
五、方法的反射
六、通过反射了解集合泛型的本质
一、Class类的使用
1)在面向对象(oop)的世界里,万事万物皆对象。
在Java中,包括基本的数据类型,都是对象。
Class c = int.class;//int 的类类型
那就是说:
类是对象,类是java.lang.Class类的实例对象。这个对象我们称之为类类型。
换言之,每一个类都有一个类类型,这个类类型就是java.lang.Class的实例对象
2)如何获取一个类的类类型(三种方法)
类名.class;
类的对象.getClass();
Class.forName(“类的全称包含包名”);
class Foo{}
Foo foo1=new Foo();
1. Class c1 = Foo.Class;//任何一个类都有一个隐含的静态成员变量class
2. Class c2 = foo1.getClass()//已经知道该类的对象通过getClassF方法
3. Class c3 = null;
c3 = Class.forName("com.immoc.reflect.Foo");
//of course, c1 == c2 == c3 is true
3)利用类类型来创造实例对象(需要有无参数的构造方法)(需要有强制类型转化,且有异常抛出)
Foo foo2 = (Foo)(c1.newInstance());
Foo foo3 = (Foo)(c2.newInstance());
Foo foo4 = (Foo)(c3.newInstance());
1 packagecom.study.reflect;
2
3 /**
4 * @description 6 * @date 2016-3-28 下午4:06:29
7 */
8 public classClassDemo1 {
9
10 public static voidmain(String[] args){
11 //Foo的实例对象如何表示?
12 Foo foo1=new Foo();//foo1就表示Foo的实例对象
13 //Foo这个类也是一个实例对象,它是Class类的对象,那Class类的实例对象,如何表示呢?
14 //任何一个类都是Class的实例对象,但是不能通过new关键字来创建。这个实例对象有三种表示方式:
15
16 //第一种表示方式---->实际是在告诉我们任何一个类都有一个隐含的静态成员变量class
17 Class c1=Foo.class;//如果Foo已经存在,可以用这种方法来创建Foo的类类型(class type),即Foo类的类类型就是Class类的一个实例对象。
18
19 //第二种方式-->已知该类的对象,通过getClass方法
20 Class c2=foo1.getClass();//如果Foo类的对象foo1已经存在,可以通过这种方法来创建Foo类的类类型。
21
22 /**
23 * 上面官网说c1,c2 是表示了Foo类的类类型(class type)---->指的就是Class的对象
24 * 类类型,即万事万物皆对象,
25 * 类也是一个对象,是Class类的实例对象
26 * 这个对象我们把它称为该类的类类型
27 */
28
29 //不管c1 or c2,他们都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象
30 System.out.println(c1==c2);//true
31
32 //第三种表示:
33 Class c3=null;
34 try{
35 c3=Class.forName("com.study.reflect.Foo");//通过Foo的全称来创建
36 } catch(ClassNotFoundException e) {
37 e.printStackTrace();
38 }
39 System.out.println(c2==c3);//true
40
41 //我们完全可以通过类的类类型创建该类的对象实例-->通过c1 or c2 or c3 创建Foo的实例
42 try{
43 //如果c1是A类的类类型,创建的就是A类的实例对象,所以需要做强制类型转换,也会有异常
44 Foo foo = (Foo) c1.newInstance();//这个前提要求是需要有无参数的构造方法
45 foo.print();
46 } catch(InstantiationException e) {
47 e.printStackTrace();
48 } catch(IllegalAccessException e) {
49 e.printStackTrace();
50 }
51 }
52
53 }
54 classFoo{
55 voidprint(){
56 }
57 }
二、动态加载类
首先区分什么是动态加载和静态加载。
也就是区分编译和运行。
new 创建对象,是静态加载类,在编译时刻就需要加载所有可能使用到的类
通过动态加载类可以解决该问题。通过类类型创建该类的对象
1、静态加载类,是编译时刻加载;动态加载类,是运行时刻加载
2、new创建对象:是静态加载类,在编译时刻就需要加载所有的【可能使用到的类】。有一个类有问题(如不存在),都不能通过编译,会报错。
3、Class.forName()通过动态加载类,可以用到一个类时,才进行加载。
【功能性的类尽量使用动态加载,并对新添的类实现功能性接口(标准),这样就不用重新编译】
比如:
//new 创建对象是静态加载类,在编译时刻就需要加载所有的可能使用到的类。eg:word excel
//通过动态加载类可以解决该问题
//动态加载类,在运行时刻加载
Class c=Class.forName(args[0]);
//通过类类型,创建该类对象
OfficeAble oa=(OfficeAble)c.newInstance();//word 和excel都想加载就用一个标准oa
oa.start();
—————————————————————————————————
//编写一个标准接口
interfaceOfficeAble
{
public voidstart();
}
—————————————————————————————————
//让word 和excel继承oa
class Excel implementsOfficeAble
{
public voidstart(){
}
}
动态加载的好处(设计思想):
扩展性,主程序不需要修改,不需要重新编译,只要新功能实现了相同的接口,启动的时候换个新的参数就可以。
三、获取方法信息
public classClassDemo2 {
public static voidmain(String[] args) {
/*** 基本数据类型、void关键字都存在类类型
*/Class c1=int.class;//基本数据类型int的类类型
Class c2=String.class;//String类的类类型(可以理解为String类的字节码,如:编译生成的xx.class文件即xx的字节码文件)
Class c3=double.class;//double这个数据类型的类类型
Class c4=Double.class;//Double这个类的类类型
Class c5=void.class;//在类里面声明的,比如void,也是有类类型
//获取类的全称getName()
System.out.println(c1.getName());//输出:int
System.out.println(c2.getName());//输出:java.lang.String
//获取不包含包名的类的全称
System.out.println(c2.getSimpleName());//输出:String
}
}
Class类的基本API操作
获取类的全部信息,包括类的成员函数、成员变量
1 public classClassUtil {
2
3 /**
4 *
5 * @description 打印类的信息,包括类的成员函数、成员变量
6 * @date 2016-3-28 下午5:12:42
7 * @param @paramobj 该对象所属类的信息
8 * @returnvoid
9 */
10 public static voidprintClassMessage(Object obj){
11 //要获取类的信息,首先要获取类的类类型
12 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
13 //获取类的名称
14 System.out.println("类的名称是:"+c.getName());
15 //在Java中,方法是Method类的对象
16 /**
17 * Method类,是方法的对象
18 * 一个成员方法就是一个Method的对象
19 * Method类中封装了对方法的操作
20 * getMethods()方法获取的是所有public的函数,包括父类继承而来的
21 * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
22 */
23 Method[] methods =c.getMethods();
24 Method[] declaredMethods =c.getDeclaredMethods();
25 for(int i=0;i
26 //得到方法的名称
27 System.out.print(methods[i].getName()+"(");
28 //获得参数类型--->得到的参数列表的类型的类类型
29 Class[] parameterTypes =methods[i].getParameterTypes();
30 for(Class class1 : parameterTypes){
31 System.out.print(class1.getName()+",");
32 }
33 System.out.print(")");
34 //得到方法的返回值类型的类类型
35 Class returnType = methods[i].getReturnType();//如果方法返回得到的是int,那结果就是int.class
36 System.out.println("方法的返回值类型名称:"+returnType.getName());//这个得到的就是名称int
37 }
38 }
39 }
测试类:
1 public classClassDemo3 {
2 public static voidmain(String[] args) {
3 String s="Hello";
4 ClassUtil.printClassMessage(s);
5
6 System.out.println("=================================");
7 Integer i=1;
8 ClassUtil.printClassMessage(i);
9 }
10 }
运行结果:
View Code
四、获取成员变量、构造函数信息
1 public classClassUtil {
2
3 /**
4 *
5 * @description 打印类的成员函数的信息
6 * @date 2016-3-28 下午5:12:42
7 * @param @paramobj 该对象所属类的信息
8 * @returnvoid
9 */
10 public static voidprintClassMethodMessage(Object obj){
11 //要获取类的信息,首先要获取类的类类型
12 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
13 //获取类的名称
14 System.out.println("类的名称是:"+c.getName());
15 //在Java中,方法是Method类的对象
16 /**
17 * Method类,是方法的对象
18 * 一个成员方法就是一个Method的对象
19 * Method类中封装了对方法的操作
20 * getMethods()方法获取的是所有public的函数,包括父类继承而来的
21 * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
22 */
23 Method[] methods =c.getMethods();
24 Method[] declaredMethods =c.getDeclaredMethods();
25 for(int i=0;i
26 //得到方法的名称
27 System.out.print(methods[i].getName()+"(");
28 //获得参数类型--->得到的参数列表的类型的类类型
29 Class[] parameterTypes =methods[i].getParameterTypes();
30 for(Class class1 : parameterTypes){
31 System.out.print(class1.getName()+",");
32 }
33 System.out.print(")");
34 //得到方法的返回值类型的类类型
35 Class returnType = methods[i].getReturnType();//如果方法返回得到的是int,那结果就是int.class
36 System.out.println("方法的返回值类型名称:"+returnType.getName());//这个得到的就是名称int
37 }
38 }
39
40 /**
41 * @description 打印类的成员变量的信息
42 * @date 2016-3-29 上午9:32:58
43 * @param @paramobj 该对象所属类的信息
44 * @returnvoid
45 */
46 public static voidprintClassFieldMessage(Object obj) {
47 //要获取类的信息,首先要获取类的类类型
48 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
49 /**
50 * 成员变量也是对象
51 * 它是java.lang.reflect.Field的对象
52 * Field类封装了关于成员变量的操作
53 * getFields()方法获取的是所有的public的成员变量的信息
54 * getDeclaredFields()方法获取的是该类自己声明的成员变量信息,不问访问权限
55 */
56 Field[] fields = c.getFields();//public的成员变量用的比较少
57 Field[] declaredFields =c.getDeclaredFields();
58 for(Field field:declaredFields){
59 //得到成员变量的类型的类类型
60 Class fieldType =field.getType();
61 String typeName =field.getName();
62 //得到成员变量的名称
63 String fieldName =field.getName();
64 System.out.println(typeName+" "+fieldName);
65 }
66 }
67
68 /**
69 *
70 * @description 打印对象的构造函数信息
71 * @date 2016-3-29 上午9:39:50
72 * @param @paramobj 该对象所属类的信息
73 * @returnvoid
74 */
75 public static voidprintClassConstructorMessage(Object obj){
76 //要获取类的信息,首先要获取类的类类型
77 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
78 /**
79 * 构造函数也是对象
80 * 它是java.lang.reflect.Constructor的对象
81 * Constructor类中封装了构造函数的信息
82 * getConstructors()获取所有public的构造函数
83 * getDeclaredConstructors()获取的是该类自己声明的所有的构造函数
84 * 构造方法是没有返回值类型的
85 */
86 Constructor[] constructors = c.getConstructors();
87 Constructor[] declaredConstructors = c.getDeclaredConstructors();
88 for (Constructor constructor : declaredConstructors) {
89 System.out.print(constructor.getName()+"(");
90 //获取构造函数的参数列表--->得到的是参数列表的类类型
91 Class[] parameterTypes = constructor.getParameterTypes();
92 for (Class class1 : parameterTypes) {
93 System.out.print(class1.getName()+",");
94 }
95 System.out.println(")");
96 }
97 }
98 }
测试类:
1 /**
2 * @description 测试ClassUtil类的操作
3 * @date 2016-3-28 下午5:34:47
4 */
5 public classClassDemo3 {
6 public static voidmain(String[] args) {
7 System.out.println("=========获取类的成员函数的信息========================");
8 //测试获取类的成员方法的信息
9 String s="Hello";
10 ClassUtil.printClassMethodMessage(s);
11
12 Integer i=1;
13 ClassUtil.printClassMethodMessage(i);
14
15 System.out.println("=========获取类的成员变量的信息========================");
16 //测试获取类的成员变量的信息
17 Integer i1=1;
18 ClassUtil.printClassFieldMessage(i);
19
20 System.out.println("=========获取类的构造函数的信息========================");
21 ClassUtil.printClassConstructorMessage("Hello");
22 ClassUtil.printClassConstructorMessage(new Integer(1));
23 }
24 }
注意:要获取类的信息,首先要获取类的类类型。obj.getClass()
五、方法的反射
1、如何获取某个方法
方法的名称和方法的参数列表才能唯一决定某个方法
2、方法反射的操作
method.invoke(对象,参数列表)
1 public classMethodDemo1 {
2 public static voidmain(String[] args) {
3 /**思考:如何获得方法对象,然后用方法对象进行反射操作
4 * 1、要获取一个方法首先要获取类的信息,获取类的信息首先要获取类的类类型
5 * 2、获取方法必须要有名称和参数列表来决定
6 */
7 //1、首先要获取类的信息,获取类的信息首先要获取类的类类型
8 A a1=newA();
9 Class c =a1.getClass();
10
11 /*2、获取方法 名称和参数列表来决定
12 * getMethod获取的是public的方法
13 * getDeclaredMethod()获取自己声明的方法
14 */
15 try{
16 //获取print(int,int)方法.
17 System.out.println("=================获取print(int,int)===============");
18 //这个一定会抛出异常,我们这里简单的处理一下异常,原因:万一这个方法(带两个整型参数的方法)不存在呢
19 Method method = c.getMethod("print", new Class[]{int.class,int.class});//这个方法中“...”代表可变参数,当有几个参数的时候,可以new Class数组
20 //也可以这样写:有几个参数就传几个参数
21 Method method2 = c.getMethod("print", int.class,int.class);
22 a1.print(10, 20);//普通调用(可以理解为a1这个对象操作方法对象print)
23 /*方法的反射操作是用method/method2对象来进行方法调用 和a1.print()调用的效果完全相同
24 *方法如果没有返回值,返回null。有返回值就返回具体的返回值如下面的Object o
25 */
26 Object o = method.invoke(a1, new Object[]{10,20});//方法的反射(可以理解为print这个方法对象,即method/method2来操作a1,即上面普通调用反过来操作,通过invoke来进行操作)
27 //也可以这样:
28 Object o1 = method.invoke(a1, 10,20);
29
30
31
32 System.out.println("=================获取print(String,String)===============");
33 //获取方法print(String,String)
34 Method method3 = c.getMethod("print", String.class,String.class);
35 a1.print("hello", "world");//普通调用
36 //对方法进行反射操作
37 Object o2 = method3.invoke(a1, "hello","world");
38
39
40
41
42 System.out.println("=================获取print()无参方法===============");
43 //Method method4 = c.getMethod("print", new Class[]{});
44 Method method5 = c.getMethod("print");//没有参数就不传
45 //method5.invoke(a1, new Object[]{});
46 method5.invoke(a1);
47 }catch(Exception e) {
48 e.printStackTrace();
49 }
50 }
51 }
52
53 classA{
54 public voidprint(){
55 System.out.println("hello world");
56 }
57 public void print(int a,intb){
58 System.out.println(a+b);
59 }
60 public voidprint(String a,String b){
61 System.out.println(a.toUpperCase()+","+b.toUpperCase());
62 }
63 }
六、通过反射了解集合泛型的本质
通过Class、Method来认识集合泛型的本质
1 public classMethodDemo2 {
2 public static voidmain(String[] args) {
3 ArrayList list=newArrayList();
4
5 ArrayList list1 = new ArrayList();
6 list1.add("hello");
7 //list1.add(20);//传个整型,就是错误的
8
9 Class c1 =list.getClass();
10 Class c2 =list1.getClass();
11 System.out.println(c1==c2);//true
12 /**
13 * 分析:
14 * Class,我们可以认为是类类型或字节码,因为文件编译之后就生成*.class文件
15 * 也就是说:反射的操作(Class、Method、field的操作)都是编译之后的操作(就是变成字节码之后的操作)就是在运行时刻执行的
16 *
17 * c1==c2结果返回true说明编译之后集合的泛型是去泛型化的
18 * Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了
19 * 验证:我们可以通过方法的反射来操作,绕过编译
20 */
21 try{
22 Method method = c2.getMethod("add", Object.class);//参数是Object类型,没有任何的泛型类型
23 method.invoke(list1,20);//绕过了编译就绕过了泛型
24 System.out.println(list1.size());//输出size为2,说明整型20加进去list1集合里面了
25 System.out.println(list1);//输出[hello, 20]
26 //不能再用foreach进行遍历了,这时他认为都是String类型,会报异常:java.lang.ClassCastException,会提示说int类型不能转换成String类型
27 /*for (String string : list1) {
28 System.out.println(string);
29 }*/
30 } catch(Exception e) {
31 e.printStackTrace();
32 }
33 }
34 }
转自:http://www.cnblogs.com/Qian123/p/5329363.html