Java反射原理
2016-02-23 14:05
369 查看
一、Class类的应用
1.类类型的对象该如何表示
public class Foo{ public void say(){ System.out.println("hello world"); } } public class ClassDemo1{ public static void main(String[] args){ //Foo的实例对象 Foo foo1 = new Foo(); //Foo这个类本身也是一个实例对象 //任何一个类都是Class类的实例对象 //这个实例对象有三种表示方式 //第一种方式,实际在告诉我们任何一个类都有一个隐含的静态成员变量 Class clazz1 = Foo.class; //第二种方式,已知该类的对象,通过getClass方法得到 Class clazz2 = foo1.getClass(); //第三种表达方式,通过Class类的静态方法forName()加全限定名 try{ Class clazz3 = Class.forName("com.destiny.reflect.Foo"); }catch(ClassNotFoundException e){ e.printStackTrace(); } //不管clazz1还是clazz2都代表了Foo类的类类型,一个类只可能是一个Class类的一个实例对象 System.out.println(clazz1 == clazz2); //官方文档:clazz表示了foo类的类类型 //万事万物皆对象,是Class类的对象,这个对象我们称之为该类的类类型 //我们完全可以通过类的类类型创建该类的实例对象,即通过clazz创建Foo的实例对象 Foo foo1 = clazz1.newInstance(); foo1.say(); } }
编译:编译时期加载类是静态加载类
运行:运行时期加载类是动态加载类
public class Word{ public static void start(){ System.out.println("word......start"); } } public class Office{ public static void main(){ //由于我们只有Word类而没有Excel类,因此本类在编译时无法通过 //new创建对象属于静态加载类,在编译时期就需要加载所有可能使用到的类 //通过动态加载类可以解决该问题 if("word".equals(args[0])){ Word w = new Word(); w.start(); } if("excel".equals(args[0])){ Excel e = new Excel(); e.start(); } } }
改进之后的例子:
public class OfficeBetter{ <span style="white-space:pre"> </span>public static void main(String[] args){ <span style="white-space:pre"> </span>try{ //动态加载类,在运行时刻加载 Class clazz = Class.forName(args[0]); //通过类类型创建对象 //使用Word与Excel的抽象接口OfficeAble OfficeAble oa = (OfficeAble)clazz.newInstance(); oa.start(); }catch(ClassNotFoundException e){ e.printStackTrace(); } } }
2.基本数据类型
类中存在的关键字都存在类类型
public class ClassDemo2{ public static void main(String[] args){ //int的类类型 Class clazz1 = int.class; //String的类类型,String类字节码 Class clazz2 = String.class; Class clazz3 = double.class; Class clazz4 = void.class; System.out.println(clazz2.getName()); //java.lang.String System.out.println(clazz2.getSimpleName()); //String } } public class ClassUtil{ //打印类的信息,包括类的成员变量、成员函数 public static void printClassMessage(Object obj){ //要获取类的信息,首先要获取类的类类型 //一直参数obj,是一个对象 Class clazz = obj.getClass(); System.out.println("类的名称是:"+clazz.getName()); //Method是方法的对象 //一个成员方法就是一个method对象 //getMethods()方法获取的是所有public方法,包括从父类继承而来的 //getDeclaredMethod()获取的是所有该类自己生命的方法,无视访问权限 Method[] methods = clazz.getMethods(); for(int i = 0; i < methods.length; ++i){ //得到方法的返回值类型的类类型 Class returnType = methods[i].getReturnType(); //通过返回值的类类型打印返回值类型 System.out.println(returnType.getName()+" "); //得到方法名称 System.out.println(methods[i].getName()+"("); //获取参数类型===>得到的是参数裂变的类型的类类型 Class[] paramTypes = methods[i].getParamTypes(); for(Class clazz : paramTypes){ System.out.println(class.getName()+","); } System.out.println(")"); } } }
3.成员变量的反射
成员变量也是对象
java.lang.reflect.Field Field类封装了关于成员变量的操作 Field[] fields = clazz.getFields(); //Field[] fields = clazz.getDeclaredFields(); for(Field field : fields){ //得到成员变量类型的类类型 Class fieldType = field.getType(); String typeName = fieldType.getName(); //得到成员变量的标识符 String fieldName = field.getName(); }
二、方法的反射操作
1.如何获取某个方法
一个方法的名称和其参数列表可以唯一决定一个方法
2.方法反射的操作
method.invoke(对象, 参数列表);
3.案例
public class A{ public void print(int a, int b){ System.out.println(a+b); } public String print(String a, String b){ System.out.println(a.toUpperCase() +","+ b.toLowerCase()); } } public class MethodDemo1{ public static void main(String[] args){ //获取print(int, int)方法 //1.获取类的类类型 A a = new A(); Class clazz = a.getClass(); //2.获取方法,名称和参数列表来决定 //getMethod()获取的是public Method method = clazz.getMethod("print", new Class[]{int.class, int.class}); Method method = clazz.getMethod("print", int.class, int.class); //方法的反射操作 //用方法对象来进行调用 //如果方法没有返回值,那么obj的值为null //如果方法有返回值,那么obj就是该方法的返回值,需要强制类型转换 Object obj = method.invoke(a, new Object[]{10, 20}); Object obj = method.invoke(a, 10, 20); } }
三、通过Class, Method了解泛型的本质
反射的操作都发生在运行期
public class MethodDemo4{ List list1 = new ArrayList(); List<String> list2 = new ArrayList<String>(); list2.add("hello"); //list2.add(10); Class clazz1 = list1.getClass(); Class clazz2 = list2.getClass(); System.out.println(clazz1 == clazz2); //输出结果为true,说明编译之后的结果是去泛型化 //即编译后,list2不再具有泛型 //java中集合的泛型是防止错误输入,只在编译阶段有效,绕过编译泛型就不再发生作用 //我们可以通过方法的反射绕过编译 Method method = clazz2.getMethod("add", Object.class); //绕过编译执行add方法 method.invoke(list2, 10); //添加成功,成功绕过泛型的限制 System.out.println(list2.size); }
相关文章推荐
- java代理(AOP) InvocationHandler
- eclipse快捷键
- spring中bean属性scope介绍
- 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O
- 一个简单音乐播放器的Java实现(二)
- java注解总结
- java学习笔记-理解封装的概念
- JAVA操作Excel文件
- 随堂笔记160223安装配置
- eclipse查看jdk源码,及反编译查看
- Java集合的基本使用
- Java中的集合
- java 反射 getDeclaredField和getField的区别
- java源码级注解处理+字节码级注解处理
- Java 生成唯一性标识解决方案与重复概率分析
- Java的BIO、NIO和AIO介绍
- JAVA基础(17) Java虚拟机工作原理详解
- java基础—java中使用final关键字的总结
- 解析scope为singleton的spring组件其数据完整性问题和jvm的内存关系
- 面向对象04-java基础