首页 > 编程语言 >JAVA之反射机制

JAVA之反射机制

时间:2023-11-03 13:11:46浏览次数:36  
标签:反射 JAVA String System println 机制 加载 Class out

反射的JAVA的一个重要的机制

静态语言:在编译期间检查类型,所有的类型检查发生在编译时。变量的类型在编译时是已知的,不会随着程序运行时期的变化而变化。典型的静态语言包括 Java、C#、C++等。

动态语言:在运行时检查类型,类型检查发生在运行时。变量的类型可以在运行时随程序的执行而改变。典型的动态语言包括 Python、JavaScript、Ruby等。

虽然java是一个静态语言,但是反射机制让java可以成为一个准动态语言。

正常方式实例化对象的过程:导入包类->new关键字实例化对象->获取实例化对象

反射方式:实例化对象->getClass()方法->得到完整的包类

可以说反射是正常的逆过程,但是因为是逆推导过程,运行速度要比正常的慢不少

以下是java中与反射有关的API

  • java.lang.Class:类
  • java.lang.reflect.Field:类的字段
  • java.lang.reflect.Method:类的方法
  • java.lang.reflect.Constructor:类的构造器
  • java.lang.reflect.Modifier:类的修饰符

反射初体验

//Student
package com.std.www.javaReflection;

public class Student {
    private int id;
    private String name;
    private int age;

    public Student() {
    }

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }

    @Override
    public String toString() {
        return "student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


//ReflectionTest
package com.std.www.javaReflection;

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1=Class.forName("com.std.www.javaReflection.Student");
        System.out.println(c1);
        Class c2=Class.forName("com.std.www.javaReflection.Student");
        Class c3=Class.forName("com.std.www.javaReflection.Student");
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
    }
}

从上面可以发现,一个类在内存加载中只会有一个Class对象,并且整个类的结构都会保存到该Class对象中

Class类介绍

方法:

  • forName(String className):静态方法,根据类的完全限定名(包括包名)返回对应的 Class 对象。

  • newInstance():通过默认构造函数创建类的新实例(已经过时)。

  • getDeclaredFields():获取类中所有字段的数组,包括公共、受保护、默认(包)访问和私有字段,但不包括继承的字段。

  • getDeclaredMethods():获取类中所有方法的数组,与 getDeclaredFields 类似,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法。

  • getDeclaredConstructors():获取类中声明的所有构造函数。

  • getMethod(String name, Class<?>... parameterTypes):获取类中指定方法名和参数类型的公共方法。

  • getField(String name):获取类中指定名称的公共字段。

属性:

  • static final Class<?> TYPEClass 对象表示的类的基本类型,如果该类不是基本类型,则返回 null

  • ClassLoader getClassLoader():获取加载这个类的类加载器。

  • String getName():获取类的名称。

  • Class<?>[] getInterfaces():获取该类实现的接口列表。

  • Class<? super T> getSuperclass():获取该类的父类。

得到Class类的几种方法

package com.std.www.javaReflection;

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Student stu=new Student();
        //通过对象直接获取
        Class c1=stu.getClass();
        //forName获取
        Class c2=Class.forName("com.std.www.javaReflection.Student");
        //类名获取
        Class c3=Student.class;
        //包装类独有的获取方法
        Class c4=Integer.TYPE;
        //获取父类的Class类
        Class c5=c1.getSuperclass();
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);

    }
}

哪些类有Class对象

  • 外部类,成员类,局部内部类,匿名内部类
  • 接口
  • 数组
  • 枚举
  • 注解
  • 基本数据类型
  • void

类加载器

类加载器(Class Loader)是 Java 运行时环境的一部分,它负责加载 Java 类文件并将其转换为在 JVM 中运行的 Java 类。类加载器的主要任务是在运行时查找和加载类文件。它按需加载类文件,使得在程序运行时可以动态加载类。

类加载器的主要特点如下:

  1. 加载类:负责将类文件的二进制数据加载到内存中。
  2. 检查类的唯一性:确保加载的类在 JVM 中是唯一的,即对于同一个类文件,不会被加载多次。
  3. 类的链接:在加载类时,进行验证、准备、解析等步骤,最终生成可执行代码。
  4. 加载顺序:类加载器采用双亲委派模型,按照一定的顺序加载类,首先交由父类加载器加载,如果父类加载器无法加载,则由当前类加载器加载。

在 Java 中,有如下几种类加载器:

  1. 引导类加载器(Bootstrap Class Loader):负责加载 Java 核心库,是最顶层的类加载器。
  2. 扩展类加载器(Extension Class Loader):负责加载 Java 的扩展库,例如我们自定义的lib目录下的jar包。
  3. 系统类加载器(System Class Loader):也称为应用类加载器,负责加载应用程序的类。

我们也可以通过扩展自定义类加载器

package com.std.www.javaReflection;

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统加载类可以加载类的路径
       String loaders=System.getProperty("java.class.path");
       String[] str=loaders.split(";");
        for (String s : str) {
            System.out.println(s);
        }
    }
}

 如果类不在上面的路径中就无法加载

反射获取类的结构

package com.std.www.javaReflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1=Class.forName("com.std.www.javaReflection.Student");
        //获取类的公有属性
        System.out.println("==================类的公有属性==================");
        Field[] fields = c1.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //获取类的全部属性
        System.out.println("==================类的全部属性==================");
        fields=c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        //获取指定类的属性
        System.out.println("==================指定类的属性==================");
        Field field=c1.getDeclaredField("name");
        System.out.println(field);
        System.out.println("==================类的公共方法==================");
        Method[] methods = c1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("==================类的全部方法==================");
        methods=c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("==================类的指定方法=================");
        Method method = c1.getMethod("setName", String.class);//这里为参数的类型,因为可能存在参数重载
        System.out.println(method);
        System.out.println("==================类的公共构造器=================");
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("==================类的指定构造器=================");
        constructors=c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("==================类的指定构造器=================");
        System.out.println(c1.getConstructor(null));
        System.out.println(c1.getConstructor(int.class,String.class,int.class));

    }
}

Class对象的用法

package com.std.www.javaReflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
       //通过反射获取Class对象
        Class c=Class.forName("com.std.www.javaReflection.Student");
        //获取构造器
        Constructor con = c.getConstructor(int.class, String.class, int.class);
        //通过构造器创建对象
        Object stu = con.newInstance(2,"张三",20);
        System.out.println(stu);
        //通过反射获取方法并调用
        Method setName = c.getDeclaredMethod("setName", String.class);
        //方法.invoke(对象,方法实参),激活,把获取到的方法和实际的对象进行绑定调用
        setName.invoke(stu,"王五");
        System.out.println(stu);
        //通过反射获取属性
        Field name=c.getDeclaredField("name");
        name.setAccessible(true);
        name.set(stu,"程序员");
        System.out.println(stu);
        Field age=c.getDeclaredField("age");
        age.set(stu,40);

    }
}

这里我们可以发现私有属性的方法和值无法直接调用,但是可以通过关闭其的属性检测来进行更改,这里设置为可以访问

这就是反射的基本操作

标签:反射,JAVA,String,System,println,机制,加载,Class,out
From: https://www.cnblogs.com/liyiyang/p/17806146.html

相关文章

  • Java学习之路(四)
    Java学习之路(四)1、方法的概念​ 方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集注意:方法必须先创建才可以使用,该过程成为方法定义方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用2、方法的定义和调用2.1、无参......
  • jar包的精细化运营,Java模块化简介 | 京东云技术团队
    图:模块化手机概念一、什么是Java模块化Java模块化(module)是Java9及以后版本引入的新特性。官方对模块的定义为:一个被命名的,代码和数据的自描述集合。(themodule,whichisanamed,self-describingcollectionofcodeanddata)。早在Java7的时候就被提出,但由于其复杂性,不断跳票,直......
  • Java 8: 异步利器 CompletableFuture vs Parallel Stream 选哪个
    应人们对性能和体验的要求,异步在项目中用的越来越多,CompletableFuture和ParallelStream无疑是异步并发的利器。既然两者都可以实现异步并发,那么带来一个问题:什么时候该使用哪个呢,哪个场景下使用哪个会更好呢?这篇文章因此出现,旨在当执行异步进行编程时CompletableFuture与Parall......
  • APK检测管理系统 JAVA开源项目 毕业设计
    https://gf.bilibili.com/item/detail/1104293029为了帮助小白入门Java,博主录制了本项目配套的《项目手把手启动教程》,希望能给同学们带来帮助。一、摘要基于JAVA+Vue+SpringBoot+MySQL的APK检测管理系统,包含了软件档案模块、软件检测模块、软件举报模块、开放平台模块,还包含系统......
  • JAVA技术栈的有福啦!这款IDEA插件,写完代码即可调试
    国产API调试工具Apipost推出IDEA插件,写完代码就可以调试接口并一键生成接口文档!而且还可以根据已有的方法帮助您快速生成url和params。ApipostHelper=API调试工具+API管理工具+API搜索工具。在商店中搜索或直接点击下方链接即可下载:https://plugins.jetbrains.com......
  • JAVA技术栈的有福啦!这款IDEA插件,写完代码即可调试
    国产API调试工具Apipost推出IDEA插件,写完代码就可以调试接口并一键生成接口文档!而且还可以根据已有的方法帮助您快速生成url和params。ApipostHelper=API调试工具+API管理工具+API搜索工具。在商店中搜索或直接点击下方链接即可下载:https://plugins.jetbrains.com/p......
  • Java面试题:链表-合并两个排序的链表
    描述输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。示例输入:{1,3,5},{2,4,6}返回值:{1,2,3,4,5,6}原题地址:https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337代码实现packagecom.example.demo.linked;......
  • java基础学习:path,java_home环境变量配置
    1.path变量: 装jdk后会自动配置java和javac的path路径 2.JAVA_HOME环境变量:   ......
  • JAVA内存分配
    1.类(包含该类的方法)的字节码文件进入方法区处于候命状态2.虚拟机调用了该类的方法后,方法进入栈内存,并执行方法3.当运行方法过程中出现了“new”,就会在堆内存中开辟对应空间,并把该空间的地址返回给arr变量记录,因此就可以通过arr找到对应的堆内存空间 注意: ......
  • java笔记_15_动态生成Excel文件
    //创建表头数据//内层List按纵向创建,外层List按横向添加,横向重复的名称会自动合并表格。List<List<String>>list=newArrayList<>();List<String>childList1=newArrayList<>();childList1.add("aaa");childList1.add("bbb");childList1.add......