何时Java反射

写的不是很详细,可能会有看不懂的地方,建议去慕课网的视频:https://www.imooc.com/video/3735java

之前就学习过java的反射,可是后来一直没有用过,如今回过头来看了一下,并把知识点作了整理程序员

  • Class类

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();框架

  • Java 动态加载类

这一部分使用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

理解了为何有时候会出现编译经过,运行报错的缘由。(由于使用了动态加载类)函数

  •  Java 获取方法信息

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反射机制——获取成员变量
成员变量是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反射机制——获取构造函数
构造函数是java.lang.Constructor类的对象
一、经过Class.getConstructor()得到Constructor[]全部公有构造方法信息
二、建议getDeclaredConstructors()获取本身声明的构造方法
三、Constructor.getName():String
四、Constructor.getParameterTypes():Class[]
  •  Java 方法反射的基本操做

方法的反射:
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 经过反射了解集合泛型的本质

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来获得你要的实体对象,而后调用它包含的东西。

可是若是是要本身写框架的话,那就会用得比较多了。

相关文章
相关标签/搜索