java反射
jopen
10年前
1.首先理解什么是反射?
反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为。
2.为什么需要反射?
反射能够让我们:
- 在运行时检测对象的类型;
- 动态构造某个类的对象;
- 检测类的属性和方法;
- 任意调用对象的方法;
- 修改构造函数、方法、属性的可见性等;
1)在面向对象的世界里,万事万物皆对象。(java语言中,静态的成员、普通数据类型等)
类是不是对象?类是谁的对象?//类是对象,类是java.lang.Class类的实例对象
2)这个对象到底如何表示?
3)Class.forName("类的全称"), 不仅表示了类的类类型,还表示了动态加载类(编译时加载类是静态加载类、运行时加载类是动态加载类)
--------------------------------------华丽分割线-----------------------------------------------
3.Class类实例对象的方法
Class实例对象的三种方法:a.通过类的隐含的静态成员class; b.通过该类的getClass()方法;c.通过类的全称,用Class.forName("类名")获取。eg:
class ClassDemo0{ public static void main(String[] args) { Foo foo1=new Foo(); //1,任何一个类都有一个隐含的静态成员class Class c1=Foo.class; //2,已知该类,通过getClass方法 Class c2=foo1.getClass(); //注c1,c2表示Foo类的类类型(class type) System.out.println(c1==c2); //true, 一个类只可能是Class类的一个实例对象 //3,通过类的全称获取 Class c3=null; try{ c3=Class.forName("Foo"); }catch(ClassNotFoundException e){ e.printStackTrace(); } System.out.println(c2==c3);//true //通过类的类类型创建该类的对象实例,通过c1,c2,c3创建Foo的对象实例 try{ Foo foo=(Foo)c1.newInstance();//前提:该类要有无参构造函数 }catch(InstantiationException e){ e.printStackTrace(); }catch(IllegalAccessException e){ e.printStackTrace(); } } } class Foo{ void print(){ System.out.println("Foo"); } }
假如想要写一个类调用类word或Excel,如下程序,如果没有Word和Excel类编译时肯定会出错,若希望有其中一个类存在也可以编译通过,则需要用到动态加载类
class Office{ public static void main(String[] args) { //new创建对象 是静态加载类,在编译时刻就需要加载所有的可能使用到的类,(若没有建Word类),编译不通过 //若有建Word类,但Excel类没建,但编译还是不能通过 //希望用到时再加载,可以通过动态加载类实现 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]); //通过类类型,创建该类对象 //Word w=(Word)c.newInstance(); //如果加载的是Excel呢? //Excel e=(Excel)c.newInstance(); //如果加载的是Excel呢? //后期增加功能就不用改动OfficeBetter,实现在线升级,扩展性更强 OfficeAble oa=(OfficeAble)c.newInstance(); //所以做一个标准————功能型的类尽量使用动态加载 oa.start(); }catch(Exception e){ e.printStackTrace(); } } } interface OfficeAble{ public void start(); } class Word implements OfficeAble{ public void start(){ System.out.println("word...start..."); } } class Excel implements OfficeAble{ public void start(){ System.out.println("Excel...start..."); } }
5.获取类的信息
a.基本数据类型的类类型
Class c1=int.class; Class c2=String.class;// 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()); /*output: int java.lang.String String double java.lang.String void */
class ClassUtils{ /* *打印类的信息,包括类的成员函数 */ public static void printClassMessage(Object obj){ //要获取类的信息 首先要获取类的类类型 Class c=obj.getClass();//传递的是哪个子类的对象 c就是该子类的类类型 //获取类的名称 System.out.println("类的名称是:"+c.getName()); /* Method类,方法对象 一个成员方法就是一个Method对象 getMethods()方法获取的是所有的public的函数,包括父类继承而来的 getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问父类继承的 */ Methods[] 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(")"); } } /* *打印类的信息,包括类的成员变量 */ public static void printFieldMessage(Object obj){ Class c=obj.getClass(); /* 成员变量也是对象 java.lang.reflect.Field Field类封装了关于成员变量的操作 getFields()方法获取的是所有的public的成员变量的信息 getDeclareFields获取的是该类自己声明的成员变量的信息 */ //Filed[] fs=c.getFileds(); Field[] fs=c.getDeclareFields(); for(Filed field:fs){ //得到成员变量的类型的类类型 Class fieldType=field.getType(); String typeName=fieldType.getName(); //得到成员变量的名称 String fieldName=field.getName(); System.out.println(typeName+" "+fieldName); } } /* 打印对象的构造函数的信息 */ public static void printConMessage(Object obj){ Class c=obj.getClass(); /* 构造函数也是对象 java.lang.Constructor中封装了构造函数的信息 getConstructors获取所有的public的构造函数 getDeclaredConstructors所得的构造函数 */ //Constructor[] cs=c.getContructors(); 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(")"); } } }
1)如何获取某个方法?
方法的名称和方法的参数列表才能唯一决定某个方法
2)方法的反射的操作?
method.invoke(对象,参数列表);
class MethodDemo{ public static void main(String[] args) { //要获取print(int,int)方法 //1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型 A a1=new A(); Class c=a1.getClass(); //2.获取方法名称和参数列表来决定 try{ Method m=c.getMethod("print",new Class[]{int.class,int.class}); //或写成 c.getMethod("print",int.class,int.class); //方法的反射操作 如何达到和a1.print(10,20)的效果? //方法如果没有返回值返回null,有返回值返回具体的返回值 Object o=m.invoke(a1,new Object[]{10,20}); //m.invoke(a1,10,20); //获取方法print(String,String); Method m1=c.getMethod("print",String.class,String.class); m.invoke(a1,"hello","world"); //获取无参方法 Method m2=c.getMethod("print");// or c.getMethod("print",Object[]{}); m.invoke(a1); //m.invoke(a1,new Object[]{}); }catch(Exception e){ 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.toLowerCase()); } public void print(){ System.out.println("helloworld"); } }
class MethodDemo{ public static void main(String[] args) { ArrayList list=new ArrayList(); ArrayList<String> list1=new ArrayList<String>(); list1.add("hello"); //list1.add(20); //error Class c1=list.getClass(); Class c2=list2.getClass(); System.out.println(c1==c2); //true; //反射的操作都是编译之后的操作 /* c1==c2结果返回true说明编译之后集合的泛型是去泛型化 java中集合的泛型,是防止错误输入的,只在编译阶段有效 绕过编译就无效了 验证:可以通过方法的反射来操作,绕过编译 */ try{ Method m=c2.getMethod("add",Object.class); m.invoke(list1,20);//绕过编译的操作,就绕过了泛型 System.out.println(list1.size()); System.out.println(list1); }catch(Exception e){ e.printStackTrace(); } } }
---EOF---