本文共 7784 字,大约阅读时间需要 25 分钟。
初解
java.lang.Class
对象,通过该Class
对象就可以访问到JVM中的这个类.Class类的使用
在面向对象的世界里,所有看到的事物都是对象,包括class也是对象(java.lang.Class的对象)
任何一个类都是Class类的实例对象,那么,他们是如何表示的呢?
Foo foo=new Foo();
第一种 Class c1=Foo.Class;
任何一个类都有一个隐含的静态成员变量;
第二种 Class c2=foo.getClass();
通过该对象的getClass()方法,获取类;
此时c1/c2表示的是Foo类的类类型 (class type)
c1==c2,因为他们表示的是同一个类的类类型,一个类只有一种类类型
第三种 Class c3=null;
c3=Class.forName(“reflect.Foo”);
此时,需要的参数是类的全限定名;这种方法不仅表示了类的类类型,还表示了动态加载类;
c2==c3;
last:
Foo foo=(Foo)c1.newInstance;
需要通过无参的构造函数;
静态加载类:编译时刻加载类; new一个对象,编译时候需要加载所有需要的类;很多执行的功能同时执行,但是只要有一个有问题,那么,所有的都会停滞,全部无用;
动态加载类:运行时刻加载类; 通过类类型创建类对象;
Class.forName(“类的全称”)Class c=Class.forName(arg[0]); //加载类型未知,不要强制类型转换,但是不知道怎么转换OfficeAble oa=( OfficeAble) c.newInstance();//用一种规则(接口)来强制转换,因为此时不知道转换到哪一种类;oa.start();
此时,可编译上述代码;
编写OfficeAble接口下面的各种类;
编译哪个类,就可以动态加载哪个类;
用途:利用动态加载,尽量提高功能型的类的可扩展性,尽量使用动态加载,更加方便;
常见的现象,某个运行的界面,运行到某个地方的时候提示出错,此时是个别的类出错,使用动态加载类,避免了整个界面不能启动、功能全部瘫痪。
void关键字、基本数据类型等都有自己的类类型;
获取类的信息,类成员变量,类方法,类构造函数等
package hdu.terence.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class ClassUtil { @SuppressWarnings("unchecked") public static void printClassMessage(Object obj) { //获取类的信息:类类型; Class c = obj.getClass(); System.out.println("类名称:" + c.getName()); /* * Method类,方法对象 * 一个成员方法就是一个Method对象 * * getMethods()方法,获取所有public函数,包括继承过来的 * * getDeclaredMethods()获取该类自己声明的方法(一般在自定义类中) * */ Method[] ms = c.getMethods(); for (inti = 0; i < ms.length; i++) { ClassreturnType = ms[i].getReturnType(); System.out.print(" " + returnType.getName() + " "); System.out.print(ms[i].getName() + "("); Class[] paramTypes = ms[i].getParameterTypes(); for (intj = 0; j < paramTypes.length; j++) { System.out.print(paramTypes[j].getName()); if (j != paramTypes.length - 1) { System.out.print(","); } } System.out.println(")"); } } /** * 获取成员变量的信息 */ @SuppressWarnings("unchecked") public static void printFieldMessage(Object obj) { Classc = obj.getClass(); /**成员变量也是对象 * java.lang.reflect.Field * Field类封装了关于成员变量的操作 * getFields()方法获取的是所有的public的成员变量的信息 * getDeclaredFields获取的是该类自己声明的成员变量的信息 * */ //Field[]fs = c.getFields(); Field[] fs = c.getDeclaredFields(); for (Field field : fs) { //得到成员变量的类型的类类型 ClassfieldType = field.getType(); tringtypeName = fieldType.getName(); //得到成员变量的名称 StringfieldName = field.getName(); System.out.println(" " + typeName + " " + fieldName); } } /** * 打印对象的构造函数的信息 */ @SuppressWarnings("unchecked") public static void printConMessage(Object obj) { Classc = obj.getClass(); /**构造函数也是对象 * * java.lang. Constructor中封装了构造函数的信息 * * getConstructors获取所有的public的构造函数 * getDeclaredConstructors得到所有的构造函数 * */ //Constructor[]cs = c.getConstructors(); Constructor[] cs = c.getDeclaredConstructors(); for (Constructor constructor : cs) { System.out.print(" " + constructor.getName() + "("); //获取构造函数的参数列表--->得到的是参数列表的类类型 Class[] paramTypes = constructor.getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getName() + ","); } System.out.println(")"); } } public static void main(String[] args) { Strings = "Hello,Terence!"; System.out.println("获取类信息"); ClassUtil.printClassMessage(s); System.out.println("获取类成员变量信息"); ClassUtil.printFieldMessage(s); System.out.println("获取类构造函数信息"); ClassUtil.printConMessage(s); //Integeri=1; // ClassUtil.printClassMessage(i); }}
方法反射
如何获取某个方法
方法的名称和方法的参数列表可以唯一决定某个方法
方法的反射操作
Method.invoke(对象,参数列表)
package hdu.terence.reflect;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class MethodDemo1 { @SuppressWarnings("unchecked") public static void main(String[] args) { /** *要获取方法 *1.首先要获取该方法所在的类,即获取类的信息 *要获取类的信息,首先要获取类的类类型; */ A a1 = new A(); Class c = a1.getClass(); /** *2.获取方法名称和参数列表来表决 *getMethod获取的是public方法 *getDeclaredMethod自己声明的方法 * / /* Methodm=c.getDeclaredMethod("print",new Class[]{int.class,int.class}); */ try { Method m = c.getDeclaredMethod("print", int.class, int.class); /**方法的反射;正常调用:a1.print(10,20); *方法的反射操作时通过m对象来进行方法调用,效果和正常调用是一样的; *反射操作有返回值,返回值类型是Object类型,如果返回值类型是void则obj=null; */ Object obj1 = m.invoke(a1, new Object[]{10, 20}); /* 反射传参1 */ Objectobj2 = m.invoke(a1, 10, 20); /* 反射传参2 */ System.out.println(obj1 + "\t" + obj2); Methodm1 = c.getDeclaredMethod("print", String.class, String.class); Object obj3 = m1.invoke(a1, "Hello", "Terence"); Object obj4 = m1.invoke(a1, new Object[]{"Hello", "Terence"}); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }}class A { public void print(int a, int b) { System.out.println(a + b); } public void print(String a, String b) { System.out.println(a.toUpperCase() + "," + b.toLowerCase()); }}
通过反射来理解泛型的本质
package hdu.terence.reflect;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;public class MethodDemo2 { public static void main(String[] args) { ArrayListlist = new ArrayList(); ArrayListlist1 = new ArrayList (); list.add("hello"); list.add(10); list1.add("tttttt"); /* list1.add(10);提示错误; */ Classc1 = list.getClass(); Classc2 = list1.getClass(); System.out.println("listand list1 是否类型相同:" + (c1 == c2)); /* *上述结果提示:true;表明编译之后的集合ArrayList是去除泛型化的 *只是泛型的限制不同,所以,泛型是用来提示输入错误的,只有在编译阶段才有效,绕过编译就无效了; *反射的操作都是在编译之后的操作,此处可以用方法反射来证明上述观点; */ try { Methodm = c2.getMethod("add", Object.class); m.invoke(list1, 20); /* 此时转化为对象传参,绕过了编译,避免了泛型的判断;不提示错误 */ System.out.println("list1的长度:" + list1.size()); System.out.println("list1:" + list1); System.out.println("使用泛型 遍历集合(出错)"); /* 此时不能用泛型再遍历了,应该使用对象Object遍历 *//*for(Stringstr:list1) {System.out.println(str+" "); *此时遍历到整形的时候会出错 } */ System.out.println("使用Object类型 遍历集合:"); for (Object obj : list1) { System.out.print(obj + "\t"); } } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }}
(2016-10-17)
(注:如果看到的人发现了里面有错误,请帮忙指正一下,我修改一下自己的理解,共同学习,只求让我这只菜鸟快快成长。提到反射我就晕晕乎不知其所以然)