随笔

java反射机制学习笔记

2018-11-09  本文已影响23人  朽木亦自雕

定义百度百科解释

JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为[动态语言]”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

API示例

1:准备了一个简单类

public class Person {
    //一个简单的类
    private String name;
    private int gender;
    private String address;
    private String idCardNum;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getGender() {
        return gender;
    }
    public void setGender(int gender) {
        this.gender = gender;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getIdCardNum() {
        return idCardNum;
    }
    public void setIdCardNum(String idCardNum) {
        this.idCardNum = idCardNum;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender=" + gender +
                ", address='" + address + '\'' +
                ", idCardNum='" + idCardNum + '\'' +
                '}';
    }
}

2:调用示例

public class ReflectTest {

    private Person person;

    @Before
    public void init(){
        person = new Person();
        person.setName("demo");
        person.setAddress("北京市天安门");
        person.setGender(1);
        person.setIdCardNum("110000200000000000");
    }

    @Test
    public void test1(){
        System.out.println(person);
    }
}

结果

console:
    Person{name='demo', gender=1, address='北京市天安门', idCardNum='110000200000000000'}

3:通过反射获取类名

@Test
public void test2(){
    Class c = person.getClass();
    System.out.println("c.getName :"+c.getName());
    System.out.println("c.getSimpleName :"+c.getSimpleName());
}

结果

console:
    c.getName :com.example.reflect.Person  
    c.getSimpleName :Person

4:通过反射获取类属性

@Test
public void test3(){
    Class c = person.getClass();
    //获取所有字段
    Field [] fields = c.getDeclaredFields();
    System.out.println("all fields:");
    for (Field f : fields) {
        f.setAccessible(true);
        System.out.println(f+ ":" + f.get(person));
    }
    //获取public的字段
    Field [] fields1 = c.getFields();
    System.out.println("public fields:");
    for (Field f : fields1) {
        System.out.println(f);
    }
}
console:
    all fields:
        private java.lang.String com.example.reflect.Person.name:demo
        private int com.example.reflect.Person.gender:1
        private java.lang.String com.example.reflect.Person.address:北京市天安门
        private java.lang.String com.example.reflect.Person.idCardNum:110000200000000000
    public fields:

5:获取所有方法并且执行调用

@Test
public void test4() throws InvocationTargetException, IllegalAccessException {
      Class c = person.getClass();
        //获取所有方法
      Method  [] methods = c.getDeclaredMethods();
      for (Method m : methods){
          //set方法需要参数
          if(m.getName().startsWith("set")){
              Class [] parameterTypes = m.getParameterTypes();
              //我这里的方法只有一个参数,所以直接取第一个
              System.out.println(m + ",parameterType is "+parameterTypes[0]);
              if("String".equals(parameterTypes[0].getSimpleName())){
                  m.invoke(person, (String)m.getDefaultValue());
              }else{
                  m.invoke(person, 0);
              }
          }else{
              //get方法具有返回值
              Object result = m.invoke(person);
              System.out.println(m +": "+ result +", type is " + m.getReturnType());
          }
      }
      System.out.println(person.toString());
}
public java.lang.String com.example.reflect.Person.toString(): Person{name='demo', gender=1, address='北京市天安门', idCardNum='110000200000000000'}, type is class java.lang.String
public java.lang.String com.example.reflect.Person.getAddress(): 北京市天安门, type is class java.lang.String
public java.lang.String com.example.reflect.Person.getName(): demo, type is class java.lang.String
public void com.example.reflect.Person.setName(java.lang.String),parameterType is class java.lang.String
public void com.example.reflect.Person.setAddress(java.lang.String),parameterType is class java.lang.String
public void com.example.reflect.Person.setGender(int),parameterType is int
public void com.example.reflect.Person.setIdCardNum(java.lang.String),parameterType is class java.lang.String
public int com.example.reflect.Person.getGender(): 0, type is int
public java.lang.String com.example.reflect.Person.getIdCardNum(): null, type is class java.lang.String
Person{name='null', gender=0, address='null', idCardNum='null'}

6:反射创建对象的方式

@Test
public void test5() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
      Person p1 = new Person(); //正向
      System.out.println(p1.getClass());

      Class c = Person.class;
      System.out.println(c.getName());

      Class c1 = Class.forName("com.example.reflect.Person");
      System.out.println(c1.getName());

      Person p2 = (Person) c1.newInstance();
      System.out.println(p2);
  }
console:
  class com.example.reflect.Person
  com.example.reflect.Person
  com.example.reflect.Person
  Person{name='null', gender=0, address='null', idCardNum='null'}

反射创建对象通常在工厂模式中比较常见,是典型的应用场景

结束语:反射是java非常重要的一个内容,java程序员应该熟悉反射的各种api和经典使用场景,反射可以创建对象,修改属性,调用方法,合理的利用反射,可以提高程序的灵活性,降低耦合性,提高自适应能力。

上一篇 下一篇

猜你喜欢

热点阅读