复习Java中的反射机制
Class类的使用
任何一个类都是Class的实例对象,这个实例对象有三种表达方式
/** * */ /** * @author jacky 2014年12月27日 */ class Foo { void print() { System.out.println("foo"); } } public class Reflect { public static void main(String[] args) { Foo foo1 = new Foo(); // 任何一个类都是Class的实例对象,这个实例对象有三种表达方式 // 第一种表达:实际告诉我们每个类都有个隐含的静态成员class Class c1 = Foo.class; // 第二种表达:已知该类的对象通过getClass方法得到 Class c2 = foo1.getClass(); /** * 万事万物皆对象 类也是对象,是Class类的实例对象 */ // 不管c1 or c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象 System.out.println(c1 == c2); // 第三种表达:已知该类的对象通过getClass方法得到 Class c3 = null; try { //com.jacky.reflect-->包名 c3 = Class.forName("com.jacky.reflect.Foo"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(c2 == c3); // 我们可以通过类的类类型创建该类的实例对象--->通过c1 ro c2 or c3创建Foo的实例对象 try { Foo foo = (Foo) c1.newInstance();// 需要有无参数的构造方法 foo.print(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出:
true true foo
动态加载类
先说静态加载:
new 创建对象是静态加载类,在编译时刻就需要加载所有的可能使用到的类
如下:Excel类并没有实现,如果是静态加载就要求所有类都要实现。我可以使用动态加载来解决这个问题,使程序依然可以运行。
class Office { public static void main(String[] args) { //new 创建对象是静态加载类,在编译时刻就需要加载所有的可能使用到的类 //通过动态加载可以解决该问题 if("Word".equals(args[0])){ Word w = new Word(); w.start(); } if("Excel".equals(args[0])){ Excel e = new Excel(); e.start(); } } }
动态加载:
class OfficeBetter { public static void main(String[] args) { try { //动态加载类,在运行时刻 Class c = Class.forName(args[0]); //通过类类型,创建该类对象 OfficeAble oa = (OfficeAble)c.newInstance(); oa.start(); } catch (Exception e) { e.printStackTrace(); } } }
参数args[0]是在运行时指定要加载的Class.如果我们只是实现了Excel,而为实现Word类,我们并可以指定加载Excel
如下:
OfficeAble.java:
class Word implements OfficeAble { public void start() { System.out.println("Word start"); } }
接口OfficeAble
interface OfficeAble { public void start(); }
执行命令参数为:Word
结果:
Word start
获取方法信息,构造等
ClassUtil.printClassMessage(Object obj)
基本的数据类型,void关键字都存在类类型
ClassDemo2.java:
public class ClassDemo2 { public static void main(String args[]) { Class c1 = int.class;//int 的类类型 Class c2 = String.class;//String 的类类型 Class c3 = double.class; Class c4 = Double.class; Class c5 = void.class; System.out.println(c1.getName()); System.out.println(c2.getName()); System.out.println(c2.getSimpleName()); System.out.println(c3.getName()); System.out.println(c4.getName()); System.out.println(c5.getName()); String hello = "xixi"; int i = 1; ClassUtil.printClassMethodMessage(i); ClassUtil.printClassConMessage("hello"); ClassUtil.printClassConMessage(new Integer(1)); } }
ClassUtil.java:
public class ClassUtil { /** * 打印类的信息,包括类的成员函数,成员变量(只获取成员函数) * * @author jacky 2014年12月27日 */ public static void printClassMethodMessage(Object obj) { // 要获取类的信息,首先获取类的类类型 Class c = obj.getClass(); // 传递的是哪个子类的对象,c就是该子类的类类型 System.out.println("类名称是:" + c.getName()); /** * getMethods()获取所有的public函数,包括父类继承而来的 * getDeclaredMethods()获取所有的该类申明的方法,不问访问权限 */ Method[] ms = c.getMethods(); for (int i = 0; i < ms.length; i++) { // 得到方法的返回值类型的类类型 Class returnType = ms[i].getReturnType(); System.out.println("返回值类型:" + returnType.getName()); System.out.print(ms[i].getName() + "("); // 获取参数列表,得到参数参数列表类型的类类型 Class[] paramTypes = ms[i].getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getSimpleName() + ","); } System.out.println(")"); } } /** * 获取成员变量 * * @author jacky 2014年12月27日 */ public static void printClassFieldMessage(Object obj) { /** * java.lang.reflect.Field Field类封装了关于成员变量的操作 * getFields()方法获取的是所有public的成员变量的信息 * getDeclaredFields()获取的是该类自己申明的成员变量的信息 */ } /** * 打印构造函数的信息 */ public static void printClassConMessage(Object obj) { Class c = obj.getClass(); /** * 构造函数也是对象 java.lang.Constructor中封装了构造函数的信息 * getConstructors获取所有public的构造函数 * getDeclaredConstructors()得到所有的构造函数 */ 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(")\n"); } } }
方法的反射 method.invoke(对象,参数列表)
/** * @author jacky 2014年12月27日 */ public class ClassDemo { public static void main(String args[]) { // 获取print(int,int)方法 A a1 = new A(); Class c = a1.getClass(); /** * 获取方法,名称和参数列表决定 getMethod获取的是public方法 getDeclaredMethod自己声明的方法 */ try { Method m = c.getMethod("print", int.class, int.class); // 方法的反射操作 // a1.print(10,20) 方法的反射使用m对象来进行方法调用 // 方法如果没有返回值返回,返回null,有返回值类型返回具体的返回值 m.invoke(a1, 10, 20); Method m1 = c.getMethod("print",new Class[]{}); m1.invoke(a1, null); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class A { public void print(){ System.out.println("hello world"); } 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()); } }
泛型的本质
反射的操作都是编译之后的操作
编译之后集合的泛型是去泛型化的
java中集合的泛型,只是防止错误输入的,只在编译阶段有效
绕过编译就无效了
/** * @author jacky 2014年12月27日 */ public class ClassDemo { public static void main(String args[]) { List list = new ArrayList(); List<String> list1 = new ArrayList<String>(); list1.add("xixi"); Class c1 = list.getClass(); Class c2 = list1.getClass(); System.out.println(c1 == c2); //true //反射的操作都是编译之后的操作 /** * 说明编译之后集合的泛型是去泛型化的 * java中集合的泛型,只是防止错误输入的,只在编译阶段有效 * 绕过编译就无效了 * 验证:方法的反射来操作,绕过编译 */ try { Method m = c2.getMethod("add", Object.class); m.invoke(list1,20); System.out.println(list1); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。