首页 > 编程语言 >一文详解Java反射技术

一文详解Java反射技术

时间:2024-11-16 12:44:43浏览次数:3  
标签:Class Java 一文 System class 详解 println public String

Java反射

什么是Java反射 以及 引出反射的背景?

Java程序中的对象有两种类型,编译时类型 和 运行时类型,而很多时候编译时类型与运行时类型是不一致的。
举个例子给大家看一下:

public class Test1 {

    public static void main(String[] args) {
        Person person = new Man();
        person.shout();
    }

}

class Person{
    String name;

    public void shout(){
        System.out.println("person shout");
    }
}

class Man extends Person{
    String sex;
    public void shout(){
        System.out.println("Man shout");
    }
}

上面代码输出结果 : Man shout
编译类型时Person ,运行时实际时Man; 如果我们有一个方法传入的是一个Person,到底传入的Person具体是哪个类,只有运行的时候才知道,可能是Person类或它的子类。

所以如果现在想要运行的时候知道到底传入的是哪一个类,怎么办?
这个问题就引入了反射这个概念,反射指的是运行期拿到一个对象的所有信息。

Class类

我们编写完java代码后,通过编译生成了.class文件,这个文件里面记录了我们这个类的原始信息,jvm通过读取这个文件,生成对应的一个Class类型的实例。

Class部分源码

public final class Class<T> implements Serializable, GenericDeclaration, Type, AnnotatedElement, OfField<Class<?>>, Constable {

    private static native void registerNatives();

    private Class(ClassLoader loader, Class<?> arrayComponentType) {
        this.classLoader = loader;
        this.componentType = arrayComponentType;
    }

    public String toString() {
        String kind = this.isInterface() ? "interface " : (this.isPrimitive() ? "" : "class ");
        return kind.concat(this.getName());
    }

可以看见Class类型的构造方法是私有的,所以我们不能new出一个Class对象。public final class Class 可以这样理解,每当我们需要加载一个类的时候,JVM会为其创建一个Class类型的class,两者有高度的关联关系。 前面这句话有点绕,但是请仔细理解阅读。相当于我们加入要加载Person类,JVM会new 出来一个Class类型的实例,这个实例与Person是关联的。
例子: 比如我们加载一个 Person类 ,可以看成下面这种形式 Class cls = new Class(Person);

如何获取一个class的Class实例

下面代码给出了4种方法。

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException {

        Class class1 = String.class;
        Class class2 = "helloWorld".getClass();
        Class class3 = Class.forName("java.lang.String");
        Class class4 = ClassLoader.getSystemClassLoader().loadClass("java.lang.String");
        
    }
}

注意:Class类型的实例时单例存储的,所以上面代码里面的class1 - class4 指向的是同一个Class类型的实例。

Class类的使用

java.lang.Class类提供了大量的方法获取该Class对象所对应的类的信息,比如字段,方法,构造方法,注解等

获取属性

  • Field getField(name):根据字段名获取某个public的field,包括继承的field
  • Field getDeclaredField(name):根据字段名获取当前类的某个field,不包括继承的field
  • Field[] getFields():获取所有public的field,包括继承的field)
  • Field[] getDeclaredFields():获取当前类的所有field,不包括继承的field

代码案例: (可以自己执行一下,就不讲解代码了)

public class Test3 {
    public static void main(String[] args) {
        Class<Book> bookClass = Book.class;
        Field[] declaredFields = bookClass.getDeclaredFields();
        Field[] fields = bookClass.getFields();
        for (Field f : declaredFields) {
            System.out.println(f);
            System.out.println(f.getName());
            System.out.println(f.getType());
            System.out.println(f.getModifiers());
        }
        System.out.println("--------------------");
        for (Field f : fields) {
            System.out.println(f);
            System.out.println(f.getName());
            System.out.println(f.getType());
            System.out.println(f.getModifiers());
        }
    }

}

class Book{
    private String name;
    public int id;
    public String author;
}

获取调用方法

我们还能从Class的实例种获取Method,Method记录了类中的方法,Class提供了下面常见的方法来获取Method

  • Method getMethod(name, Class…):获取某个指定name的public的Method,包括继承的方法
  • Method getDeclaredMethod(name, Class…):获取当前类指定name的某个Method,不包括继承的方法
  • Method[] getMethods():获取所有public的Method,包括继承的方法
  • Method[] getDeclaredMethods():获取当前类的所有Method,不包括继承的方法

一个Method对象包含一个方法的所有信息:

  • getName():返回方法名称;
  • getReturnType():返回方法返回值类型;
  • getParameterTypes():返回方法的参数类型;
  • getModifiers():返回方法的修饰符。

实例代码:

public class Test4 {
    public static void main(String[] args) {

        Class<String> stringClass = String.class;
        Method[] methods = stringClass.getMethods();
        for (Method method : methods) {
            String name = method.getName();
            System.out.println(name);
            int modifiers = method.getModifiers();
            System.out.println(Modifier.toString(modifiers));
            Class<?> returnType = method.getReturnType();
            System.out.println(returnType.toString());
            Class<?>[] parameterTypes = method.getParameterTypes();
            System.out.println(Arrays.toString(parameterTypes));
        }
    }
}

获取注解信息

  • public Annotation[ ] getAnnotations( ):返回所有注释。
  • public Annotation[ ] getDeclaredAnnotations( ):获取所有注释,忽略继承。
  • public <T extends Annotation> T getAnnotation(Class<T> annotationClass)​:返回指定类型的注解,如果没有则返回null

注意:通过反射能够读取到的注解必须要注解的生命周期是RetentionPolicy.RUNTIME

详细的可以运行这个案例代码

public class Test5 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Class<Human> humanClass = Human.class;
        Sex annotation = humanClass.getAnnotation(Sex.class);
        // 通过注解给sex注入一个值
        Human human = new Human();
        Field sex = humanClass.getField("sex");
        sex.set(human, annotation.value());
        System.out.println(human.sex);
    }
}

@Sex
class Human{
    String name;
    public String sex;
}

@Retention(RetentionPolicy.RUNTIME)
@interface Sex{
    String value() default "male";
}

获取构造方法

  • public Constructor<T> getDeclaredConstructor(Class<?>…parameterTypes)​:获取某个构造方法
  • public Constructor<?>[ ] getDeclaredConstructors( ):获取所有构造方法
  • public Constructor<T> getConstructor(Class<?>…parameterTypes)​:获取某个public构造方法
  • public Constructor<?>[ ] getConstructors( ):获取所有public构造方法。

这个地方代码比较简单,就给一个简单的代码案例

public class Test6 {

    public static void main(String[] args) throws Exception {
        Constructor cons1 = String.class.getConstructor(int.class);
        // 调用构造方法:
        String instance = (String) cons1.newInstance(123);
        System.out.println(instance);
        
    }
}

反射的应用

反射可以说是框架的灵魂,通过反射,我们得以在运行时生成,操作对象,或者调用对象的任意一个方法,这给了我们极大的自由度。可以让我们写出通用的代码。动态代理就利用了反射技术,这部分待日后补充(补充一些案例,展现反射的强大之处,其实上面解释注解的时候已经通过注解在运行时给类的属性set了一个值)

TODO

  • 补充反射的具体应用

标签:Class,Java,一文,System,class,详解,println,public,String
From: https://blog.csdn.net/Zongkunxue/article/details/143793858

相关文章

  • Java反序列化-Commons Collections3利用链分析详解
    介绍CC3与CC1和CC6的主要区别在于,CC1和CC6依赖反射机制来执行Runtime.getRuntime().exec()等危险命令,而如果服务器将这些方法列入黑名单,这两种方式就会失效。相比之下,CC3通过类加载器动态加载恶意类来执行危险函数,绕过黑名单限制,从而达到命令执行的目的。公众号:T......
  • java笔试题
    请指出下面程序的运行结果(62)publicclassTest{publicstaticvoidmain(String[]args){System.out.println(test());}publicstaticinttest(){try{return2;}catch(Exceptione){return4;......
  • 前端必知必会-JavaScript if、else 和 else if
    文章目录JavaScriptif、else和elseif条件语句if语句else语句elseif语句总结JavaScriptif、else和elseif条件语句用于根据不同的条件执行不同的操作。条件语句编写代码时,您经常希望针对不同的决策执行不同的操作。您可以在代码中使用条件语句来执行......
  • 前端必知必会-JavaScript Switch 语句
    文章目录JavaScriptSwitch语句JavaScriptSwitch语句break关键字default关键字常见代码块switch详细信息严格比较总结JavaScriptSwitch语句switch语句用于根据不同的条件执行不同的操作。JavaScriptSwitch语句使用switch语句从多个代码块中选择一个......
  • java根据时区转换获取时间的方法
    方法一:publicstaticvoidmain(String[]args){//假设这是从MySQL获取的UTC时间字符串StringutcTimeStr="2024-09-30T16:00:00Z";try{//解析UTC时间字符串DateTimeparsedDateTime=DateUtil.parse(utcTimeStr......
  • 数据结构(初阶5)---堆与堆排序(详解)
    堆与堆排序一.二叉树初探1).基本概念2).满二叉树和完全二叉树3.)二叉树的存储方式二.堆与堆排序1.堆(完全二叉树的特例)1).建堆(向下调整法)2).堆排序再将堆排序之前,我们先引入二叉树概念一.二叉树初探1).基本概念二叉树是一种数据结构,二叉树形如:1.其中A节......
  • LangChain的Prompt组件详解
    在大语言模型的应用中,Prompt设计是至关重要的。LangChain通过其强大的Prompt组件,提供了灵活且高效的Prompt管理和应用方式。本文将详细探讨LangChain中Prompt的基本概念、模板使用、高级设计以及与Few-ShotLearning的结合。##Prompt的基本概念和应用Prompt在自然语言处理任务......
  • Java Web 过滤器和拦截器.
    概念过滤器即Servlet过滤器,参见Servlet过滤器入门示例。拦截器(Interceptor)通常是由特定的框架提供的,不是JavaEE标准的一部分。Spring提供了多种类型的拦截器,如方法拦截器(MethodInterceptor)和控制器拦截器(HandlerInterceptor)。方法拦截器可以用于AOP(面向切面编程),而控......
  • javaScript交互补充3(JSON数据)
    3.1、JSON(1)、定义:JSON数据格式JavaScriptObjectNotation缩写即js对象表示法由于JS中的对象只有JS自己认识,其他的语言都不认识,所以引入了JSON,JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,并且可以转换为任意语言中的对象,JSON在开发中主要用来数据的......
  • javaScript交互补充4(本地存储)
    localstorage、Sessionstorage是WebStorage,H5的本地存储机制。是本地存储,存储在客户端,以键/值对的形式存储的,通常以字符串存储。是针对HTML4中Cookie存储机制的一个改善,由于Cookie存储机制有很多缺点,HTML5不再使用它,转而使用改良后的WebStorage存储机制。4.1、Cookie(1......