Java类的反射机制
2016-05-06 15:57
465 查看
在慕课网上看到了Cedar老师讲的Java类的反射机制,感觉讲得很好,所以整理一下,以便于更深入的学习。http://www.imooc.com/learn/199
Java语言中,静态的成员,普通的数据类型类是不是对象?
类是谁的对象?
类也是对象,类是java.lang.Class类的实例对象
2、这个对象应该怎样表示呢?
任何一个类都是Class的实例对象,这个实例对象有三种表示方式
Class.forName(“类的全名”)不仅表示了类的类型性,还表示这是动态加载类。
new 出来的对象都是静态加载类,在编译时刻就需要加载所有可能使用到的类,假如有100个类,99个存在,1个不存在,依旧用不了。
想要解决此类问题,就需要使用动态加载类。
但此时又出现一个问题,想要创建类的实例对象,必须要将c.newInstance()强转。应该向哪个方向强转,是向Word强转还是向Excel强转,故需要一个接口,统一标准。
Word类需要实现这个接口
若是想增加其他类,也不需要更改和重新编译OfficeBetter类,只需要在用到之前书写相应的类并实现OfficeAble接口即可。
一般来说,只要是类中的关键字,都有类类型。package没有类类型,因为它不是在类中的。
测试类:
输出结果为
Field类封装了关于成员变量的操作
getFields方法获取的是所有public成员变量的信息
getDeclaredFields获取的是该类自己声明的成员变量的信息
测试:
输出结果为:
java.lang.Constructor中封装了构造函数的信息
getConstructor获取public的所有构造方法
getDeclaredCOnstructor获取所有构造函数的信息
测试:
输出结果为:
方法的名称和方法的参数列表才能唯一决定某个方法
2.方法的反射操作
method.invoke(对象,参数列表);
Class类介绍
1、在面向对象的世界里,万事万物皆对象。Java语言中,静态的成员,普通的数据类型类是不是对象?
类是谁的对象?
类也是对象,类是java.lang.Class类的实例对象
2、这个对象应该怎样表示呢?
任何一个类都是Class的实例对象,这个实例对象有三种表示方式
package cn.reflect; public class Demo { public static void main(String[] args) { Foo f1 = new Foo(); //(1)任何一个类都有一个隐藏的静态成员变量class Class c1 = Foo.class; //(2)已知该类的对象,通过getClass方法来表示 Class c2 = f1.getClass(); /** * c1和c2都代表了Foo类的类类型(class Type) * 一个类只可能是Class类的一个实例对象 */ System.out.println(c1 == c2);//True //(3)Class.forName("类全名") Class c3 = null; try { c3 = Class.forName("cn.reflect.Foo"); System.out.println(c2 == c3); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } /** * 通过类的类类型创建该类的实例对象--> * 通过c1、c2、c3都可创建 */ try { //这种方式需要强转,也需要Foo有一个无参的构造函数 Foo foo = (Foo) c1.newInstance(); foo.print(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class Foo { public void print() { // TODO Auto-generated method stub System.out.println("Foo"); } }
动态加载类和静态加载类
编译时刻加载类是静态加载类,运行时刻加载类是动态加载类。Class.forName(“类的全名”)不仅表示了类的类型性,还表示这是动态加载类。
package cn.reflect; public class Office { public static void main(String[] args) { if("Word".equals(args[0])){ Word w = new Word(); w.print(); }else if("Excel".equals(args[0])){ Excel e = new Excel(); e.print(); } } }
package cn.reflect; public class Word { public void print() { System.out.println("word is starting"); } }
new 出来的对象都是静态加载类,在编译时刻就需要加载所有可能使用到的类,假如有100个类,99个存在,1个不存在,依旧用不了。
想要解决此类问题,就需要使用动态加载类。
Class c = Class.forName(args[0]);
但此时又出现一个问题,想要创建类的实例对象,必须要将c.newInstance()强转。应该向哪个方向强转,是向Word强转还是向Excel强转,故需要一个接口,统一标准。
package cn.reflect; public interface OfficeAble { public void print(); }
Word类需要实现这个接口
public class Word implements OfficeAble
package cn.reflect; public class OfficeBetter { public static void main(String[] args) { try { Class c = Class.forName(args[0]); OfficeAble oa = (OfficeAble) c.newInstance(); oa.print(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
若是想增加其他类,也不需要更改和重新编译OfficeBetter类,只需要在用到之前书写相应的类并实现OfficeAble接口即可。
获取方法信息
类中的关键字都存在类类型
package cn.reflect; public class ClassDemo { public static void main(String[] args) { Class c1 = int.class;//int 的类类型 Class c2 = String.class; Class c3 = double.class; Class c4 = Double.class; Class c5 = void.class; System.out.println(c1.getName());//int System.out.println(c2.getName());//java.lang.String System.out.println(c2.getSimpleName());//String System.out.println(c5.getName());//void } }
一般来说,只要是类中的关键字,都有类类型。package没有类类型,因为它不是在类中的。
Class类的基本API操作
获取类的成员函数的信息
package cn.reflect; import java.lang.reflect.Method; public class ClassUtil { /** * 打印类的信息,包括类的成员函数 */ public static void printClassMessage(Object obj){ //要获取类的信息,首先要获取类的类类型 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型 //获取类的名称 System.out.println("类的名称是"+c.getName()); /* * Method类,方法对象 * 一个成员方法就是一个Method对象 * getMethods()方法获取的是所有的public的函数,包括父类继承来的。 * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限 */ Method[] ms = c.getMethods(); for(int i = 0; i< ms.length;i++){ //得到方法的返回值的类类型 Class returnType = ms[i].getReturnType(); System.out.print(returnType.getName()+" "); //得到方法的名称 System.out.print(ms[i].getName()+"("); //获取参数类型 Class[] paramTypes = ms[i].getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getName()+","); } System.out.println(")"); } } }
测试类:
package cn.reflect; public class ClassDemo3 { public static void main(String[] args) { String s = "hello"; ClassUtil.printClassMessage(s); } }
输出结果为
类的名称是java.lang.String boolean equals(java.lang.Object,) java.lang.String toString() int hashCode() int compareTo(java.lang.String,) int compareTo(java.lang.Object,) int indexOf(java.lang.String,int,) ……
获取类的成员变量的信息
成员变量也是对象,java.lang.reflect.Field类的对象Field类封装了关于成员变量的操作
getFields方法获取的是所有public成员变量的信息
getDeclaredFields获取的是该类自己声明的成员变量的信息
/** * 打印类的信息,包括类的成员变量 */ public static void printFieldMessage(Object obj) { Class c = obj.getClass(); Field[] fs = c.getDeclaredFields(); for (Field field : fs) { // 得到成员变量的类型的类类型 Class fieldType = field.getType(); String typeName = fieldType.getName(); // 得到成员变量的名称 String fieldName = field.getName(); System.out.println(typeName + " " + fieldName); } }
测试:
ClassUtil.printFieldMessage("hello");
输出结果为:
long serialVersionUID [Ljava.io.ObjectStreamField; serialPersistentFields java.util.Comparator CASE_INSENSITIVE_ORDER
获取类的构造函数的信息
构造函数也是对象,是java.lang.Constructor的对象java.lang.Constructor中封装了构造函数的信息
getConstructor获取public的所有构造方法
getDeclaredCOnstructor获取所有构造函数的信息
/** * 打印对象的构造函数的信息 * @param obj */ public static void printConMessage(Object obj){ Class c = obj.getClass(); //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(")"); } }
测试:
ClassUtil.printConMessage("hello");
输出结果为:
java.lang.String([C,int,int,) java.lang.String([B,int,) java.lang.String([B,int,int,int,)
方法的反射
1.如何获取某个方法方法的名称和方法的参数列表才能唯一决定某个方法
2.方法的反射操作
method.invoke(对象,参数列表);
package cn.reflect; import java.lang.reflect.Method; public class MethodDemo1 { public static void main(String[] args) { // 要获取 print(int a, int b)方法,1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型 A a1 = new A(); Class c = a1.getClass(); /* * 2.获取方法 名称和参数列表来决定 getMethod获取的是public的方法 getDecaredMethod获取自己声明的方法 */ try { // Method m = c.getMethod("print", new // Class[]{int.class,int.class}); Method m = c.getMethod("print", int.class, int.class); // 方法的反射操作 // 用m对象进行方法的操作,和a1.print调用的效果相同 // 方法如果没有返回值,返回null,如果有返回值,返回具体的返回值 // Object o = m.invoke(a1, new Object[]{10,20}); Object o = m.invoke(a1, 10, 20); System.out.println("================"); Method m1 = c.getMethod("print", String.class, String.class); Object o1 = m1.invoke(a1, "hello", "world"); /* * 如果没有参数可以直接写m1.invoke(a1); */ } catch (Exception e) { // TODO Auto-generated catch block 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.toUpperCase()); } }
通过反射了解集合泛型的本质
package cn.reflect; import java.lang.reflect.Method; import java.util.ArrayList; public class MethodDemo02 { public static void main(String[] args) { ArrayList list = new ArrayList(); ArrayList<String> list1 = new ArrayList<String>(); Class c1 = list.getClass(); Class c2 = list1.getClass(); System.out.println(c1==c2);//true //反射的操作的都是编译之后的操作 /* * c1==c2说明编译之后的集合的泛型是去泛型化的 * Java中的集合的泛型,是防止错误输入的,只在编译阶段有效 * 绕过编译就无效了 * 验证:通过方法的反射才操作,绕过编译 */ try { Method m = c2.getMethod("add", Object.class); m.invoke(list1, 20);//绕过编译操作就绕过了泛型 m.invoke(list1, "hello"); System.out.println(list.size()); /*for (String string : list1) { System.out.println(string); }*///不能这样输出,会抛异常 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
相关文章推荐
- Java 注解 拦截器
- Java多线程同步机制(synchronized)
- java html生成图片后保存
- java面向对象_抽象类和接口
- 负载均衡的几种算法Java实现代码
- RxJava入门[转载一篇很棒的文]
- Java基础-第四天作业
- 别人用Myeclipse没问题,到我的eclipse中跑不起来
- Java集合06--Vector源码详解
- Java实现的二分查找算法
- spring bean创建细节
- 20个非常有用的Java程序片段
- JAVA序列化操作详解
- java动态代理(JDK和cglib)
- eclipse安装ndk时,常出现的问题及错误
- java 排序算法
- volatile详解
- 深入理解Java:注解(Annotation)自定义注解入门
- java中compareTo比较两个日期大小
- Spring整合Hibernate--声明式事务管理