写的不是很详细,可能会有看不懂的地方,建议去慕课网的视频:https://www.imooc.com/video/3735java
之前就学习过java的反射,可是后来一直没有用过,如今回过头来看了一下,并把知识点作了整理程序员
1)在面向对象的世界里,万事万物皆对象。 类也是对象,类是java.lang.Class类的实例对象。 官方文档是这么解释的There is a class named Class 2)Foo的实例对象 Foo foo1=new Foo(); //Foo类是java.lang.Class类的实例对象,也有构造方法(本地方法),可是不能使用new //三种表示方式 //第一种表示方式--->说明任何一个类都有一个隐含的静态成员变量class Class c1=Foo.class; //第二种表达方式--->已经有该类的对象经过getClass()方法 Class c2=foo1.getClass(); //第三种表达方式 Class c3=Class.forName("com.Foo"); //经过c1 or c2 or c3(类类型)建立Foo的实例对象(须要用try catch包住) Foo foo=(Foo)c1.newInstance();//须要有无参数的构造方法
在这里能够看到Class的构造方法,是本地方法,只能由虚拟机建立,而且由c语言实现数组
c1,c2,c3表示了Foo类的类类型(class type)
一个类是Class类的一个实例对象(c1==c2==c3)返回true
建立实例对象:c1.newInstance();框架
这一部分使用ide工具是看不出来的,最好使用Sublime相似的工具,首先添加.java文件,后使用javac对文件进行编译,使用java运行编译后的文件看是否出错 定义office类,静态加载类 public class office(){ public static void main(String[] args){ if("word".equals(args[0])){ Word word=new Word(); } if("excel".equals(args[0])){ Excel excel=new Excel(); } } } javac office.java就会直接报错,由于Word和Excel类没有实现 new建立对象:静态加载类,在编译时刻就加载全部的【可能用到的类】。任何一个使用的类有问题,都不能经过编译,都会报错。 在上面的例子中用到了:new Word();new Excel();须要静态加载Word、Excel类,编译时刻就会对类Word和Excel进行加载,若是(任一)类文件中有错误就会编译不经过。 定义office2类,动态加载类 public class office2(){ public static void main(String[] args){ if("Word".equals(args[0])){ Class class=Class.forName(args[0]); Word word=(Word)class.newInstace(); } if("Excel".equals(args[0])){ Class class=Class.forName(args[0]); Excel excel=(Excel)class.newInstace(); } } } 而且还有Word类 public class Word(){ public Word(){} } javac office2.java,编译没问题 java office2 Word,运行没问题 java office2 Excel,运行出错 Class.forName():动态加载类,运行时刻进行加载。 若是名称为args[0]的类不存在,编译时刻没问题,可是运行会报错。这就是为什么有时候会出现编译经过,运行报错的缘由。 动态加载一个好处,就是能够随时增长须要编译的类。例如没有Excel类,只有Word类,也能够运行,须要Excel类时再由程序员写此类 (为了能统一控制,Word类、Excel类须要继承同一个父类或者继承同一个接口)。 public Interface Micro(){} public class Word implements Micro(){} public class Excel implements Micro(){} public class Test(){ public static void main(String[] args){ Class class=Class.forName(args[0]); Micro micro=(Micro)class.newInstace(); //这里的micro会根据args[0]的值来肯定是哪个实现类(子类)的对象啊 } }
new建立对象,编译时刻(javac)加载类,Class.forName("");运行时刻(java)加载类ide
理解了为何有时候会出现编译经过,运行报错的缘由。(由于使用了动态加载类)函数
public static void pringClassMessage(Object object) { //要获取类的信息,首先要获取类的类型 Class c = object.getClass(); //获取类的名称 System.out.println("类的名称是:" + c.getName()); /* * Method类,方法对象 * 一个成员方法就是一个Method对象 * getMethods()方法获取的是全部public函数,包括父类继承而来的 * getDeclaredMethods()获取的是全部该类本身声明的方法,不问访问权限 * */ Method[] ms = c.getMethods();//c.getDeclaredMethods(); for (int i = 0; i < ms.length; i++) { //获得方法的返回值类型的类类型 Class returnType = ms[i].getReturnType(); System.out.println(returnType.getName()); //获得方法名 System.out.println(ms[i].getName() + "("); //获取参数类型-->获得的是参数列表的类型的类类型 Class[] paramType = ms[i].getParameterTypes(); for (Class class1 : paramType) { System.out.println(class1.getName() + ","); } System.out.println(")"); } } }
java的方法也是类对象,是java.lang.refelect.Method的对象工具
经过下面两个方法,能够得到类类型是c1的类的方法数组学习
c1.getMethod();spa
c1.getDeclareMethod();3d
返回值的类类型
m[0].getReturnType();
参数的类类型数组
m[0].getParameterTypes();
Java反射机制——获取成员变量 成员变量是java.lang.reflect.Field的对象 一、Field类封装了关于成员变量的操做 二、Field[] fs = c.getFields()方法获取全部public的成员变量Field[]信息 三、c.getDeclaredFields获取的是该类本身声明的成员变量信息 四、field.getType()得到成员类型的类类型 五、field.getName()得到成员的名称
类的成员变量是java.lang.reflect.Field的对象
c1.getField();
c1.getDeclareField();
成员变量的类类型
f[0].getType();
成员变量的名称
f[0].getName();
Java反射机制——获取构造函数 构造函数是java.lang.Constructor类的对象 一、经过Class.getConstructor()得到Constructor[]全部公有构造方法信息 二、建议getDeclaredConstructors()获取本身声明的构造方法 三、Constructor.getName():String 四、Constructor.getParameterTypes():Class[]
方法的反射: 1.获取A类中的print(int,int)方法: //要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型 A a1=new A(); Class c= a1.getClass(); //获取方法 由名称和参数列表来决定,getMethod获取的是public方法,getDelcaredMethod获取本身声明的方法 Method m =c.getMethod(methodName,paramtypes);//paramtypes能够用数组的形式 表示new Class[]{int.class,int.class},也能够直接列举类类型 2.方法的反射操做:是用m对象来进行方法调用,和a1.print(10,20)调用的方法相同 m.invoke(a1,new Object[]{10,20}) Object o=m.invoke(对象名,参数);//方法若是没有返回值返回null,若是有返回值返回具体值,参数可用数组的方式表示,也能够直接列举,没有参数就不写 public Class A{ public void print(){}; public void Print(Sting a,String b){} public void Print(int a,int b){}; } public Class B{ public static void main(String[] args){ A a1 = new A(); Class c= a1.getclass; Method getMet=c.getMethod("print",String.class,String.class);//忘了加引号 Object obj=getMet.invoke(a1,"df","df"); } }
获取方法
c1.getMethod("方法名",Class[]);
调用方法
m.invoke(c1,参数);
Java反射机制——经过反射了解集合泛型的本质 1:反射的操做都是编译以后的操做;就是运行阶段 2:java中集合的泛型是防止错误输入的;只在编译阶段有效,只要绕过编译就无效啦 咱们能够经过方法的反射来操做,绕过编译 ArrayList list1=new ArrayList(); ArrayList<String> list2=new ArrayList<String>(); Class c1=list1.getClass(); Class c2=list2.getClass(); System.out.print(c1==c2); //true Method m=c2.getMethod("add",Object.class); m.invoke(list2,20); //向list2集合中添加一个int 型的值,绕过编译 固然是不能直接foreach list2集合的,会报类型转换错误
1:反射的操做都是编译以后的操做
2:java中集合的泛型是防止错误输入的;只在编译阶段有效,只要绕过编译就无效啦,咱们能够经过方法的反射来操做,绕过编译
反射是运行阶段处理的,绕过了编译,因此好多东西编译阶段是不处理的
我的开发中反射用到的会比较少,具体会不会用也要看需求,功能主要就是根据一个String来获得你要的实体对象,而后调用它包含的东西。
可是若是是要本身写框架的话,那就会用得比较多了。