15_Java反射机制——1.Java反射机制概述

1、反射的概述
  • 反射的概念:是指程序在运行时,
    1、确定操作的类
    2、获取类的完整结构
    3、调用对应的方法

  • Java反射机制提供的功能
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法
4、在运行时获取泛型信息
5、在运行时调用任意一个对象的成员变量和方法
6、在运行时处理注解
7、生成动态代理
2、反射之前,类的实例化等操作

Person 类用于测试

public class Person {    

    private String name;   
    public int age;   
    
    @Override    
    public String toString() {        
        return "Person{" +                
        "name='" + name + '\'' +               
        ", age=" + age +                '}';   
    }   
    
    public String getName() {       
        return name;   
    }    
    
    public void setName(String name) {        
        this.name = name;   
    }   
    
    public int getAge() {        
        return age;   
    }    
    
    public void setAge(int age) {        
        this.age = age;   
    }    
    
    public Person(String name, int age) {       
        this.name = name;        
        this.age = age;    
    }    
    
    public Person() {        
        System.out.println("Person()");   
    }    
    
    public void show() {       
        System.out.println("你好, 我是一个好人。");    
    }    
    
    private String showNation(String nation) {      
        System.out.println("我的国籍是: " + nation);        
        return nation;  
    }
   
}
class PersonTest {    
    // 反射之前, 对于 Person 的操作    
    @Test    
    void testPerson1() {        
    
        // 1、创建 Person 类的对象        
        Person person = new Person("p1", 10);       
    
        // 2、通用对象, 调用其内部的属性、方法        
        person.age = 20; // 注意其声明为 public int age;   
        System.out.println(person);        
    
        // 在 Person 类外部, 不可以通过 Person 类的对象调用其内部私有结构       
        // 比如: name、showNation() 以及私有的构造器   
        person.show();   
        
     }    
     
  }

output

Person{name='p1', age=20}
你好, 我是一个人。
3、使用反射,实现类的实例化等操作
      @Test
      void testPerson2() throws Exception {   
          Class clazz = Person.class;    
          // 1、通过反射, 创建 Person 类的对象    
          // 注意这里的 int 不能改成 Integer    
          // 因为会报异常    
          // java.lang.NoSuchMethodException:   
          // main.java.com.atzwx.reflection.Person.<init>(java.lang.String, java.lang.Integer)   
          Constructor constructor = clazz.getConstructor(String.class, int.class);    
          Object object = constructor.newInstance("personName", 10);   
          Person person = (Person) object;   
          System.out.println("object: " + object + " ----- " + "person: " + person);    

          // 2、通过反射, 调用对象指定的属性、方法   
          // 调用属性    
          Field age = clazz.getDeclaredField("age");   
          age.set(person, 20);    
          System.out.println("改变 person 的 age 属性之后");  
          System.out.println("object: " + object + " ----- " + "person: " + person);   

          // 调用方法   
          Method show = clazz.getDeclaredMethod("show");    
          show.invoke(person);
    
       }

output

object: Person{name='personName', age=10} ----- person: Person{name='personName', age=10}

改变 person 的 age 属性之后

object: Person{name='personName', age=20} ----- person: Person{name='personName', age=20}

你好, 我是一个人。
4、反射的强大,调用类的私有结构
System.out.println("*************调用类的私有结构***************");

// 通过反射,可以调用类的私有结构。比如: 私有的构造器、方法、属性
// 调用私有构造器

// 在调用私有构造器时, 使用 clazz.getConstructor 会报如下异常
// java.lang.NoSuchMethodException: main.java.com.atzwx.reflection.Person.<init>(java.lang.String)
// Constructor privatedConstructor = clazz.getConstructor(String.class);

// 注意一定要加 privatedConstructor.setAccessible(true), 否则会报如下异常
// java.lang.IllegalAccessException:
// Class test.java.com.atzwx.reflection.PersonTest
// can not access a member of class main.java.com.atzwx.reflection.Person with modifiers "private"

Constructor privatedConstructor = clazz.getDeclaredConstructor(String.class);
privatedConstructor.setAccessible(true);
Person person1 = (Person) privatedConstructor.newInstance("privatedConstructor");
System.out.println(person1);

// 调用私有属性
Field privatedField = clazz.getDeclaredField("name");
privatedField.setAccessible(true);
privatedField.set(person1, "privatedField");
System.out.println(person1);

// 调用私有方法
Method privatedMethod = clazz.getDeclaredMethod("showNation", String.class);
privatedMethod.setAccessible(true);
// 相当于 String nation = person1.showNathon("中国")
String nation = (String) privatedMethod.invoke(person1, "中国");
System.out.println("nation: " + nation);

// 小总结
// 在调用类的私有结构前,必须加上 xxx.setAccessible(true), 获取权限。

output

*************调用类的私有结构***************
Person{name='privatedConstructor', age=0}
Person{name='privatedField', age=0}
我的国籍是: 中国
nation: 中国
5、如何看待反射和封装性两个技术
  • 疑问1:通过直接 new 的方式或反射的方式都可以调用类的公共结构,开发中到底用哪个?
在编译时,就可以确定类的结构
建议:直接 new 的方式 

什么时候会使用:反射的方式。
在运行时,不确定创建哪个类。
反射的特征:动态性
  • 疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
不矛盾。
封装性:关注的是调用类的哪些结构
反射机制:关注的是能不能调用
posted @ 2020-08-28 10:49  hellozwx  阅读(170)  评论(0编辑  收藏  举报