首页 > 编程语言 >java反射

java反射

时间:2024-03-20 11:35:51浏览次数:28  
标签:反射 java String newInstance Class 方法 public

java反射

概念

反射就是java中一种可以获取一个对象的类的方法,类可以通过反射拿到所有方法,并且调用。

获取类方法

获取一个类的方法有三种:

  1. 对象直接调用getclass()
  2. 每个类都有一个静态class属性
  3. Class类自带的静态方法forName(String className)
package java_learn;

import java.io.Serializable;
public class Student implements Serializable{
    private static final long serialVersionUID = -5215701594592700115L;
    private String name;
    private String number;
    private String gender;
    public String capt;
    private transient int grade;
    public Student(String name,String number,String gender,int grade) {
        this.name=name;
        this.number=number;
        this.gender=gender;
        this.grade=grade;
        System.out.println("pp");
    }
    public Student(){
        System.out.println("np");
    }
    public void getInformation(){
        System.out.println("name:"+this.name+" number:"+this.number+" gender:"+this.gender+" grade:"+this.grade);
    }
    public void woparam(){
        System.out.println("无参数");
    }
    public void doparam(String pr){
        System.out.println(pr);
    }
}
package learn_java;
import learn_java.Students;

public class reflect {
    public  static void  main(String args[]) throws ClassNotFoundException {
        Students A = new Students("capt","11111","male",2);
        //第一种获取Class的方法
        Class clazz1 = A.getClass();
        System.out.println(clazz1);
        //通过静态属性获取Class
        Class clazz2 = Students.class;
        System.out.println(clazz1 == clazz2);
        //通过类的静态方法获得Class
        Class clazz3 = Class.forName("learn_java.Students");
        System.out.println(clazz3 == clazz1);
    }
}

注意到所有返回类型是Class类型,该类型的对象中包含了对应类的类名、方法等属性。

反射利用方法

反射中常用的方法有三个:

  1. Invoke方法用于执行函数
  2. forName方法用于获取实例的类
  3. getMethod方法用于获取该类中的方法
  4. newInstance()方法用于实例化该类的对象

demo:

package java_learn;

import java.lang.reflect.InvocationTargetException;

public class reflect {
    public  static void  main(String args[]) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, InstantiationException {
        Class clazz3 = Class.forName("java_learn.Student");
        // clazz3.getMethod("woparam", new Class[]{}).invoke(clazz3.newInstance());
        // clazz3.getMethod("doparam", String.class).invoke(clazz3.newInstance(),"capt");
        Class cls = Class.forName("java.lang.Runtime");
        cls.getMethod("exec",String.class).invoke(cls.getMethod("getRuntime").invoke(cls),"open -a Calculator");

    }
}

这里需要注意的是

  1. newInstance()方法在实例化对象时,会默认调用类中的无参数构造函数,当类中不存在无参数构造函数或者无参数构造函数是私有的时,函数会执行失败。
  2. Runtime类是一个典型的单例模式,即该类只能存在一个对象,可以进入到该包中查看,其构造方法是私有的。该类的实例只能通过其public方法getRuntime方法获取。

invoke()概述

对于invoke函数的第一个参数:

  1. 如果这个方法是一个普通方法,第一个参数就是类对象
  2. 如果这个方法是一个静态方法,第一个参数就是该类(Class)

一般需要先通过getMethod方法得到Method对象,然后该Method对象调用invoke方法,从而实现该Method方法的运行。

同时invoke方法是支持多态机制的,即子类对象也可以通过invoke方法执行父类的方法,父类对象则不可以通过invoke方法执行子类方法。

第二种实例化方法

在上面提到newInstance()在实例化中可能会遇到两种问题,我们已经通过Runtime举例解决了无参数构造函数是私有的这种情况,下面分析要实例化类中不存在无参数构造函数的情况。

  • getConstructor()方法:该方法可以获取类的构造函数,并且因为类的构造函数是支持重载的,有时会有存在多个构造方法,getConstructor()函数还可以通过这些构造函数的传参类型进行区分。在进行实例化时使用newInstance()。

    将Student类中的无参数构造方法删除,我们执行这个demo发现,成功创建实例:

        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
            Class clazz = Class.forName("java.lang.ProcessBuilder");
            Method start = clazz.getMethod("start");
            Constructor c = clazz.getConstructor(String[].class);
            Object pb = c.newInstance((Object) new String[]{"open", "-a", "Calculator"});
            start.invoke(pb);
        }
    
  • ProcessBuilder类:这是另一个常用于执行命令的类,该类用于创建操作系统进程,其start()方法可以创建一个新的Process实例。它存在两个构造方法:

    • public ProcessBuilder(List<String> command)

      demo:

      public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
              Class clazz = Class.forName("java.lang.ProcessBuilder");
              Method start = clazz.getMethod("start");
              Constructor c = clazz.getConstructor(List.class);
              Object pb = c.newInstance(Arrays.asList("open","-a","Calculator"));
              start.invoke(pb);
          }
      

      这里因为Objec是祖先类,所以pb可以使用Obejct来引用。

    • public ProcessBuilder(String... command)

      这里需要的参数是一个可变长参数,参数数目不固定,可以当作数组来看待。

          public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
              Class clazz = Class.forName("java.lang.ProcessBuilder");
              Method start = clazz.getMethod("start");
              Constructor c = clazz.getConstructor(String[].class);
              Object pb = c.newInstance((Object) new String[]{"open", "-a", "Calculator"});
              start.invoke(pb);
          }
      

      可以发现,这里在调用newInstance方法时,将String数组强制转化成了Object类型。因为newInstance()方法其实也是接收可变长参数的,如果直接传输数组,newInstance()方法会将传输的字符串拆开,作为自己的参数,这样就会导致命令无法执行。

获取私有方法、属性

在反射中,利用的类存在两种:

  • getMethod()方法来获取类中的公有方法,getField()方法来获取类中的公有属性。getConstructor()方法来获取类的公有构造方法。
  • getDeclearedMethod()方法来获取类中的私有方法,getDeclearedField()方法来获取类中的私有属性。getDeclearedConstructor()方法来获取类的私有构造方法。

通常是由getMethod()方法来获取public方法,通过getDeclearedMethod()获取类的私有方法。

这样对于之前Runtime类的利用就有了新的方式。我们不需要调用getRuntime()方法来实现对Runtime对象的引用,可以直接使用getDeclearedConstructor()获取其私有的构造器:

Class clazz = Class.forName("java.lang.Runtime");
        Constructor con = clazz.getDeclaredConstructor(null);
        con.setAccessible(true);
        Method ex = clazz.getMethod("exec", String.class);
        ex.invoke(con.newInstance(), "open -a Calculator");

这里需要注意的是在获取私有构造方法(属性、构造器)之后,需要使用setAccessible(true),对权限进行修改,将newInstance()判断中的override设置成了true。

总结

  • 首先需要了解反射获取某个方法所属类的三种手段:.class、forName()、getClass()
  • 在进行命令执行时可以用到Runtime类和ProcessBuilder类
  • newInstance()方法存在两种不可执行的情况
    • 类中没有无参数构造函数:使用getConstructor()方法获取
    • 类中无参数构造函数私有:
      • 单例模式下一般存在别的方法可以直接返回该实例的引用,如getRuntime();
      • 使用getDeclearedConstrucotr()直接获取私有方法,setAccessible(true)。

标签:反射,java,String,newInstance,Class,方法,public
From: https://www.cnblogs.com/CAPD/p/18084865

相关文章

  • Java根据模板生成excel文件【EasyExcel】【xls、xlsx】
    本文章参考:作者:WaiSaa  原文链接:https://blog.csdn.net/qq_42761569/article/details/1190251711、简介如下图所示,template目录下是准备好的模板,export目录下是生成数据文件。我们这里以第一个模板《theUser蒸汽历史数据.xls》为例进行测试,theUser为占位符,生成的文件中会被替换......
  • 基于Js和Java实现xlsx\xls文档的导入和下载
    基于Js和Java+MyBatis实现xlsx\xls文档的导入下载、导出背景:​ 实现xlsx\xls文档的导入、导出​ 导入效果:​ 导出效果:导出效果图1、导入、下载1.1、前台<divstyle="margin-left:15px"><inputtype="file"id="selectFile"name="selectFile"/>......
  • 深入理解Java双冒号(::)运算符的使用
    Jdk8中有好多新的特性,比如引入Lambda,简化代码的书写等等我们先看一个关于Lambda的使用 /***输出list*/@Testpublicvoidtest(){String[]array={"aaaa","bbbb","cccc"};List<String>list=Arrays.asList(array);//Java7for(......
  • springboot/java/php/node/python情侣空间微信小程序【计算机毕设】
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:在当今社会,随着科技的迅猛发展和智能移动设备的普及,人们的社交方式正在经历着翻天覆地的变化。特别是年轻情侣之间,他们更倾向于通过数字化平台来表达情感......
  • springboot/java/php/node/python企业内部订餐小程序【计算机毕设】
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着互联网科技的飞速发展,企业运营模式正逐步向数字化、智能化方向转型。在这一背景下,企业内部服务流程的优化变得尤为重要。订餐作为企业日常工作中不可......
  • JAVASE各模块结构图:面向对象、常用类、多线程、异常、IO流、集合、网络编程
    ......
  • 230_解决 | idea导航查看源码时总是出现 .class而不是 .java源码
    转载:https://www.yuque.com/yxrpangyu/kls5lq/sg8sh01、File-->Settings-->Maven-->importing(勾选上Sources和Documentation)2、右键项目的pom.xml-->Maven–>Reimport3、窗口右边点击MavenProjects完成下图操作下载即可注意:在下载的时候要保证你的电脑有网络。转换......
  • 深入浅出Java多线程(十三):阻塞队列
    引言大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第十三篇内容:阻塞队列。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!!在多线程编程的世界里,生产者-消费者问题是一个经典且频繁出现的场景。设想这样一个情况:有一群持续不断地生产资源的线程(我们称之......
  • Java学习笔记:异常处理
    目录Java学习笔记:异常处理什么是异常异常体系结构:Error、Exception自定义异常Java学习笔记:异常处理​ **2024/3/19**什么是异常异常体系结构:Error、Exception自定义异常......
  • Java-委托
    概述Supplier、Function、Predicate、Consumer、BiFunction、BiPredicate、BiConsumer是Java函数式接口的一部分,它们用于定义不同类型的函数,从而在函数式编程中提供了更灵活的方式来处理数据。这些函数式接口可以通过Lambda表达式来实现,从而简化代码的编写。在函数式编程中,它们......