java的反射机制

来源:互联网 发布:arp static ip mac 编辑:程序博客网 时间:2024/05/29 15:24
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
来点代码展现反射形态:
Object obj = new Person("xxc",99);  //获得Class的实例的三种方式  //1.通过对象的getClass()方法获得  Class clazz1 = obj.getClass();  //2.通过表示类名的字符串来获得,注意:这里的字符串必须是完整路径,否则找不到这个类  String className = "com.xxc.reflet.Person";  Class clazz2 = Class.forName(className);  //3.用类名.class的方式获取  Class clazz3 = Person.class;  System.out.println(clazz3);  System.out.println(clazz1 == clazz3);//true  System.out.println(clazz1 == clazz2);//true  System.out.println(clazz3 == clazz2);//true  //获取基本数据类型的Class对象,void也是一种类型。  Class intClazz = int.class;  System.out.println(intClazz);//打印int  Class voidClazz = void.class;  System.out.println(voidClazz);//打印void  
/*  * 获得类中定义的所有属性  * getField(String name)返回一个属性,是这个类或接口当中的公共成员字段   返回类型 Field  * getFields()返回这个类或接口中所有公共成员字段  返回类型 Field[]  *   * getDeclaredField(String name)返回一个已声明的属性,可以是这个类或接口中任意权限的字段   返回类型 Field  * getDeclaredFields() 返回这个类或借口中所有已声明的成员字段,任意权限  返回类型 Field[]  */  Class clazz = Person.class;  Field[] fields = clazz.getDeclaredFields();  for(Field f: fields){      System.out.println("属性名         "+f.getName());      System.out.println("类型:   "+f.getType());  }  /*  * 用反射获取类中的成员字段:  * 1.先根据这个属性的名字,拿到这个属性  * 2.设置反射的对象在使用时应该取消 Java 语言访问检查,说白了就是不受权限的限制,可以访问private  * 3.返回指定对象上此 Field 表示的字段的值。 get(obj)参数的obj表示一个对象。返回obj对象里的字段。  */  Field nameField = clazz.getDeclaredField("name");  nameField.setAccessible(true);  Object value = nameField.get(obj);  System.out.println(value);  /*  * 利用反射来改某个对象里的属性,第一个参数表示要修改哪个对象,第二个表示被修改属性的值。  * 至于修改哪个属性,并不是在参数里指定的,调用set方法的那个类就表示哪个属性  */  nameField.set(obj, "xxm");  System.out.println(obj);  

/*  * 获得类中定义的所有方法  * getMethod(String name, Class<?>... parameterTypes)  返回这个类或接口中公共的方法  返回类型Method  第一个参数表示哪个对象,第二个参数表示参数类型  int.class  *                                                            因为光是指定函数名没用,重载的话就不能明确指出是哪一个方法。  * getMethods() 返回这个类或接口中所有公共的方法  返回类型是Method[]  *   * getDeclaredMethod(String name, Class<?>... parameterTypes)  返回这个类或接口中任意权限的方法  返回类型是Method   *   * getDeclaredMethods() 返回这个类或接口中任意权限的所有方法 返回类型是Method[]  */  Object obj = new Person("xxc",99);  Class clazz = obj.getClass();  Method[] methods = clazz.getDeclaredMethods();  for(Method m : methods){      System.out.println(m.getName());//返回方法名      System.out.println(m.getReturnType().getName());//返回方法的返回类型,如果直接是m.getReturnType()则会在返回类型前加class java.lang.String      Class[] parameterTypes = m.getParameterTypes();//获取方法中的参数类型,并封装在一个数组中      for(Class parameterType : parameterTypes){//遍历参数类型数组      System.out.print("参数类型  "+parameterType.getName());//获取参数类型名称        }  }  Method method = clazz.getDeclaredMethod("run",String.class,int.class,String.class);//获取需要调用的方法对象  第一个参数是方法名字,第二个参数是参数类型  method.invoke(obj, "xxc",20,"男");//调用方法,第一个参数是具体对象,第二个参数是方法的实参  

/*通过反射获取构造函数,以及其中的参数类型,构造函数名称,用构造函数创建对象。  *getConstructors() 获取某一个类中所有的公共权限构造函数  *getConstructor(Class<?>... parameterTypes) 获取某一个类中指定参数类型的公共权限构造函数   *  *getDeclaredConstructors() 获取某一个类中所有的任意权限的构造函数  *getDeclaredConstructor(Class<?>... parameterTypes) 获取某一个类中指定参数类型的任意权限的构造函数  */  Object obj = new Person("xxc",99);  Class clazz = obj.getClass();  Constructor[] constructors = clazz.getDeclaredConstructors();  for(Constructor constructor : constructors){      System.out.println("构造函数名字"+constructor.getName());      System.out.println("构造函数的参数类型:");      Class[] parametersTypes = constructor.getParameterTypes();      for(Class parametersType : parametersTypes){          System.out.print(parametersType.getName());          System.out.println();      }  }  //调用有参构造函数,创建对象  /*  * 下面这句话的第二个参数能写数组的原因是因为在1.5前,这里的第二个参数就是数组类型。  * 它和可变参数最主要的区别就是,当调用的函数是没有参数的,那么可变参数的可以不用写,而用数组类型表示的需要写null  */  Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);  //Constructor constructor = clazz.getDeclaredConstructor(new Class[]{String.class,int.class});JDK1.5之前用的  Person person = (Person)constructor.newInstance("xxx",99);//使用反射获取的有参构造函数创建对象  System.out.println(person);  
persion类
public class Person {      private String name;      private int age;            Person(String name,int age){          this.name = name;          this.age = age;      }        public String toString() {          return "Person [name=" + name + ", age=" + age + "]";      }            public void run(String str,int age,String sex){          System.out.println(str+"  "+age+"  "+sex);      }  }  

获取类或方法前的修饰:
Package pack = clazz.getPackage();//获取某个类的包名  System.out.println("包名--->"+pack.getName());                      int num = clazz.getModifiers();//可以获取类的修饰内容  /*  * 以下这个方法这样用有局限性,因为一个类既有public修饰,又有abstract修饰  * Modifier.PUBLIC=1  * Modifier.abstract=1024  * 那么此时有两个修饰就是1025,所以再用Modifier.PUBLIC就不能正确判断了。  * 这时可以用Modifier.isPublic(num)来进行判断。  */  if(num == Modifier.PUBLIC){      System.out.println("这个类的修饰符是PUBLIC");  }  if(Modifier.isPublic(num)){      System.out.println("这个类的修饰符是PUBLIC");  }  Method run = clazz.getDeclaredMethod("run",String.class,int.class,String.class);  if(Modifier.isPublic(run.getModifiers())){//函数中也有获取修饰符类型的方法      System.out.println("Run方法是PUBLIC修饰的");

练习:通过反射,做一个面向接口的,能计算任何形状面积的方法。

创建接口(此接口中有计算面积的抽象方法):

package com.xxc.reflet.test;    public interface InterfaceTest {      double getArea();  }     

实现接口的类(圆)

package com.xxc.reflet.test;    public class ChangFangXing implements InterfaceTest{      private double height;      private double width;      public double getArea() {          return height*width;      }        }  

实现接口的类(长方形)

package com.xxc.reflet.test;    public class ChangFangXing implements InterfaceTest{      private double height;      private double width;      public double getArea() {          return height*width;      }        }  

测试:

package com.xxc.reflet.test;    import java.io.BufferedReader;  import java.io.InputStreamReader;  import java.lang.reflect.Field;    public class RefletTest {      public static void main(String[] args) throws Exception {          System.out.println("请输入要计算的图形名称");          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));          String name = br.readLine();          Class clazz;          try {              clazz = Class.forName("com.xxc.reflet.test."+name);          } catch (Exception e) {              System.out.println("不存在这样的图形");              return;          }          InterfaceTest ift = (InterfaceTest)clazz.newInstance();          Field[] parameterType = clazz.getDeclaredFields();//获得所有的数据域          for(Field f : parameterType){              System.out.println("请输入:"+f.getName());              double num = Double.parseDouble(br.readLine());              f.setAccessible(true);//将所有的域设置为可访问的。              f.setDouble(ift, num);          }          double area = ift.getArea();          System.out.println("图形面积是:"+area);      }  }  






0 0
原创粉丝点击