只讲干货!!今天拿下:反射机制!!!

反射机制介绍

什么是反射

        Java 反射机制是 Java 语言一个很重要的特性,它使得 Java 具有了 动态性” 。在 Java 程序运行时,对于任意的一个类,我们能不能知道这个类有哪些属性和方法呢?对于任意的一个对象,我们又能不能调用它任意的方法?答案是肯定的!这种动态获取类的信息以及动态调用对象方法的功能就来自于Java 语言的反射( Reflection )机制。

反射的作用

        简单来说两个作用,RTTI (运行时类型识别)和 DC (动态创建)。我们知道反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括其modifiers( 修饰符 ) fields( 属性 ) methods( 方法) 等,并可于运行时改变 fields 内容或调用 methods 。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!

创建对象过程

创建对象时内存结构

Users user = new Users();

        实际上,我们在加载任何一个类时都会在方法区中建立“ 这个类对应的Class 对象 ,由于 “Class 对象 包含了这个类的整个结构信息,所以我们可以通过这个“Class 对象 来操作这个类。我们要使用一个类,首先要加载类;加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象知道类的结构。这个对象就像一面镜子,透过这个镜子可以看到类的结构,所以,我们形象的称之为:反射。 因此,“Class 对象 是反射机制的核心。

反射的具体实现

获取 Class 对象的三种方式:
        通过getClass() 方法 ;
        通过.class 静态属性 ;
        通过Class 类中的静态方法 forName();

创建Users

public class Users {
    private String username;
    private int userage;
    public String getUsername() {
        return username;
   }
    public void setUsername(String username){
        this.username = username;
   }

    public int getUserage() {
        return userage;
  }

    public void setUserage(int userage) {
        this.userage = userage;
   }
 }

通过getClass()方法获取Class对象

 /*
  * 通过getClass()方法获取该类的Class对象
 */
 public class GetClass1 {
    public static void main(String[] args) {
        Users users = new Users();
        Users users1 = new Users();
        Class clazz = users.getClass();
        System.out.println(clazz);
        System.out.println(clazz.getName());
        System.out.println(users.getClass()== users1.getClass());
   }
 }

通过.class 静态属性获取Class对象

/**
 * .class静态属性获取Class对象
 */
 public class GetClass2 {
    public static void main(String[] args) {
        Class clazz = Users.class;
        Class clazz2 = Users.class;
        System.out.println(clazz);
        System.out.println(clazz.getName());
        System.out.println(clazz == clazz2);
   }
 }

通过forName()获取Class对象

/**
* 通过Class.forName("class Name")获取Class对
象
*/
public class GetClass3 {
    public static void main(String[] args)throws Exception {
        Class clazz =Class.forName("com.TUT.Users");
        Class clazz2 =Class.forName("com.TUT.Users");
        System.out.println(clazz);
        System.out.println(clazz.getName());
        System.out.println(clazz == clazz2);
   }
}

获取类的构造方法

方法介绍

 方法使用

        修改Users

 public class Users {
    private String username;
    private int userage;
    public Users(){
   }
    public Users(String username,int userage){
        this.username= username;
        this.userage=userage;
   }
    public  Users(String username){
        this.username= username;
   }
    private Users(int userage){
        this.userage = userage;
   }

    public String getUsername() {
        return username;
   }

    public void setUsername(String username){
        this.username = username;
   }

    public int getUserage() {
        return userage;
   }
    public void setUserage(int userage) {
        this.userage = userage;
   }
 }

        获取构造方法

public class GetConstructor {
    public static void main(String[]args)throws Exception {
        Class clazz = Users.class;
        Constructor[]  arr =clazz.getDeclaredConstructors();
        for(Constructor c:arr){
            System.out.println(c);
       }
        System.out.println("---------------------");
        Constructor[]  arr1 =clazz.getConstructors();
        for(Constructor c:arr1){
            System.out.println(c);
       }
        System.out.println("------------------------");
        Constructor c = clazz.getDeclaredConstructor(int.class);
        System.out.println(c);


        System.out.println("------------------------");
        Constructor c1 =  clazz.getConstructor(null);
        System.out.println(c1);
   }
 }

        通过构造方法创建对象

public class GetConstructor2 {
    public static void main(String[]args)throws Exception {
        Class clazz = Users.class;
        Constructor constructor =clazz.getConstructor(String.class,int.class);
        Object o =constructor.newInstance("秃头小子",18);
        Users users = (Users)o;
      System.out.println(users.getUsername()+"\t"+users.getUserage());
   }
 }

获取类的成员变量

方法介绍

方法使用

        修改Users

public class Users {
    private String username;
    public int userage;
    public Users(){
   }
    public Users(String username,int userage){
        this.username= username;
        this.userage=userage;
   }
    public  Users(String username){
        this.username= username;
   }
    private Users(int userage){
        this.userage = userage;
   }
    public String getUsername() {
        return username;
   }

    public void setUsername(String username){
        this.username = username;
   }

    public int getUserage() {
        return userage;
   }

    public void setUserage(int userage) {
        this.userage = userage;
   }
 }

        获取成员变量

public class GetField {
    public static void main(String[]args)throws Exception {
        Class clazz = Users.class;
        Field[] fields = clazz.getFields();
        for(Field f:fields){
            System.out.println(f);
            System.out.println(f.getName());

       }
        System.out.println("------------------------");
        Field[] fields2 =clazz.getDeclaredFields();
        for(Field f:fields2){
            System.out.println(f);
            System.out.println(f.getName());
      }
        System.out.println("------------------------");
        Field field =clazz.getField("userage");
        System.out.println(field);
        System.out.println("---------------------");
        Field field1 =clazz.getDeclaredField("username");
        System.out.println(field1);
   }
 }

操作成员变量

public class GetField2 {
    public static void main(String[]args)throws Exception {
        Class clazz = Users.class;
        Field field =clazz.getField("userage");
        //对象实例化
        Object obj = clazz.newInstance();
        //为成员变量赋予新的值
        field.set(tut,18);
        //获取成员变量的值
        Object o = field.get(obj);
        System.out.println(o);
   }
}

获取类的方法

方法介绍

方法使用

        修改Users

public class Users {
    private String username;
    public int userage;
    public Users(){
   }
    public Users(String username,intuserage){
        this.username= username;
        this.userage=userage;
   }
    public  Users(String username){
        this.username= username;
   }
    private Users(int userage){
        this.userage = userage;
   }

    public String getUsername() {
        return username;
   }

    public void setUsername(String username){
        this.username = username;
   }

    public int getUserage() {
        return userage;
   }

    public void setUserage(int userage) {
        this.userage = userage;
   }
    private void suibian(){

        System.out.println("Hello tut");
  }
 }

获取方法

public class GetMethod {
    public static void main(String[]args)throws Exception{
        Class clazz = Users.class;
        Method[] methods =clazz.getMethods();
        for(Method m: methods){
            System.out.println(m);
            System.out.println(m.getName());
       }
        System.out.println("---------------------------");
       Method[] methods2 =clazz.getDeclaredMethods();
        for(Method m: methods2){
            System.out.println(m);
            System.out.println(m.getName());
       }
        System.out.println("--------------------------");
        Method method =clazz.getMethod("setUserage", int.class);
      System.out.println(method.getName());

        System.out.println("--------------------------");
        Method method1 =clazz.getDeclaredMethod("suibian");
      System.out.println(method1.getName());
   }
 }

调用方法

public class GetMethod2 {
2    public static void main(String[]args)throws  Exception {
3        Class clazz = Users.class;
4        Method method =clazz.getMethod("setUsername",String.class);
5         //实例化对象
6        Object obj =clazz.getConstructor(null).newInstance();
7        //通过setUserName赋值
8        method.invoke(obj,"tut");
9
10        //通过getUserName获取值
11        Method method1 =clazz.getMethod("getUsername");
12        Object value = method1.invoke(obj);
13        System.out.println(value);
14   }
15 }

获取类的其他信息

public class GetClassInfo {
    public static void main(String[] args) {
        Class clazz = Users.class;
        //获取类名
        String className = clazz.getName();
        System.out.println(className);
        //获取包名
        Package p = clazz.getPackage();
        System.out.println(p.getName());
        //获取超类
        Class superClass =clazz.getSuperclass();
      System.out.println(superClass.getName());
        //获取该类实现的所有接口
        Class[] interfaces =clazz.getInterfaces();
        for(Class inter:interfaces){
          System.out.println(inter.getName());
       }
   }
}

反射应用案例

        需求:根据给定的方法名顺序来决定方法的执行顺序。


class Reflect {
    public void method1(){
      System.out.println("Method1.......");
   }
    public void method2(){
      System.out.println("Method2.......");
   }
    public void method3(){
      System.out.println("Method3.......");
   }
}
public class ReflectDemo {
    public static void main(String[]args)throws Exception {
        Reflect rd = new Reflect();
        if(args != null && args.length > 0){
            //获取ReflectDemo的Class对象
            Class clazz = rd.getClass();
            //通过反射获取ReflectDemo下的所有方法
            Method[] methods =clazz.getMethods();
            for(String str :args){
                for(inti=0;i<methods.length;i++){
                  if(str.equalsIgnoreCase(methods[i].getName())){
                      methods[i].invoke(rd);
                        break;
                   }
               }
           }
       }else{
            rd.method1();
            rd.method2();
            rd.method3();
       }
   }
}

反射机制的效率

        由于Java 反射是要解析字节码,将内存中的对象进行解析,包括了一些动态类型,而JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多!接下来我们做个简单的测试来直接感受一下反射的效率。

反射机制的效率测试

public class Test{
   public static void main(String[] args) {
       try {
           //反射耗时
           Class clazz = Class.forName("com.tut.Users");
           Users users = (Users) clazz.getConstructor(null).newInstance();
           long reflectStart = System.currentTimeMillis();
           Method method = clazz.getMethod("setUsername", String.class);
           for(int i=0;i<100000000;i++){
             method.invoke(users,"tutxz");
          }
           long reflectEnd = System.currentTimeMillis();
           //非反射方式的耗时
           long start = System.currentTimeMillis();
           Users u = new Users();
           for(int i=0;i<100000000;i++){
               u.setUsername("utxz");
          }
           long end = System.currentTimeMillis();
           System.out.println("反射执行时 间:"+(reflectEnd - reflectStart));


           System.out.println("普通方式执行时 间:"+(end - start));
      } catch (Exception e) {
           e.printStackTrace();
      }
  }
}

setAccessible方法

        setAccessible是启用和禁用访问安全检查的开关。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查 ; 默认值为 false 。 由于JDK 的安全检查耗时较多 . 所以通过 setAccessible(true) 的方式关闭安全检查就可以达到提升反射速度的目的。

public class Test2 {
   public static void main(String[]args)throws Exception {
       Users users = new Users();
       Class clazz = users.getClass();
       Field field =clazz.getDeclaredField("username");
       //忽略安全检查
       field.setAccessible(true);
       field.set(users,"tut");
       Object object = field.get(users);
       System.out.println(object);
       System.out.println("-----------------------------");
       Method method =clazz.getDeclaredMethod("suibian");
       method.setAccessible(true);
       method.invoke(users);
  }
}
本章总结
Java 反射机制是 Java 语言一个很重要的特性,它使得 Java 具有了“动态性
反射机制的优点: 更灵活。 更开放。
反射机制的缺点: 降低程序执行的效率。 增加代码维护的困难。
获取 Class 类的对象的三种方式:
        运用getClass()
        运用.class 语法。
        运用Class.forName() (最常被使用)。
反射机制的常见操作:
动态加载类、动态获取类的信息(属性、方法、构造器)。 动态构造对象。
动态调用类和对象的任意方法。 动态调用和处理属性。
获取泛型信息。 处理注解。

只讲干货

#有什么错误的地方大家多多担待,欢迎大家留下意见共同努力。


#需要什么技术的内容大家也可以积极留言。


#有升本的伙伴也可留言,后序也可更新升本内容C 和数据结构。


#有需要的伙伴或有什么问题直接联留下wx或联系邮箱2821835676qq.com

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值