Java基础:反射

JAVA编程基础:反射 Java反射机制是程序在运行时动态获取类信息并操作类成员的能力。其核心是通过Class对象获取类的构造方法、属性和方法,实现动态创建对象、调用方法和访问属性(包括私有成员)。反射为框架开发提供了灵活性,但会带来性能开销和安全风险。典型应用包括对象实例化、方法调用和属性操作,常见于Spring等框架中。使用反射需权衡其动态性优势和性能、封装性等代价。 阅读详情

反射的概述

Reflection是被视为动态语言的关键,反射机制允许程序在执行期间,借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。
加载完类后,产生一个class类型的对象,包含完整的类的结果信息。
这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射


动态语言:Object-C,C#,JavaScript,PHP,Pyehon,
静态语言:Java,C,C++



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


反射相关的主要API
    1.java.lang.Class:代表一个类
    2.java.lang.reflect.Method:代表类的方法
    3.java.lang.reflect.Field:代表类的成员变量
    4.java.lang.reflect.Constructor:代表类的构造器
    


关于java.lang.Class类的理解
1.类的加载过程:
	程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。
	接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件
	加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此
	运行时类,就作为Class的一个实例。

2.换句话说,Class的实例就对应着一个运行时类。

3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式
来获取此运行时类。
疑问1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个?
建议:直接new的方式。
什么时候会使用:反射的方式。 反射的特征:动态性

疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
不矛盾。
封装性:是建议你哪些结构可以调用,哪些结构不需要调用
反射:是需要需要调用哪些结构

此文章所有类的为

@MyAnnotation(value="hi")
public class Person extends Creature<String> implements Comparable<String>,MyInterface{

    private String name;
    int age;
    public int id;

    public Person(){}

    @MyAnnotation(value="abc")
    private Person(String name){
        this.name = name;
    }

     Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    @MyAnnotation
    private String show(String nation){
        System.out.println("我的国籍是:" + nation);
        return nation;
    }

    public String display(String interests,int age) throws NullPointerException,ClassCastException{
        return interests + age;
    }


    @Override
    public void info() {
        System.out.println("我是一个人");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    private static void showDesc(){
        System.out.println("我是一个可爱的人");
    }

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

public interface MyInterface {
    void info();
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "hello";

}

public class Creature<T> implements Serializable {
    private char gender;
    public double weight;

    private void breath(){
        System.out.println("生物呼吸");
    }

    public void eat(){
        System.out.println("生物吃东西");
    }

}

通过反射创建对象:可以调用私有的构造器

//获取类
Class<Person> clazz = Person.class;
//获取类的构造器
Constructor<Person> cons = clazz.getDeclaredConstructor(String.class, int.class);
//设置可以使用私有的构造器权限
cons.setAccessible(true);
//实例化
Object obj = cons.newInstance("Tom",12);
System.out.println(obj.toString());
//强转为Person
Person p = (Person)obj;
System.out.println(p);

通过反射使用类中的方法和属性:可以设置和使用私有的属性和方法

//需要先获取类的实例化
Class<Person> clazz = Person.class;
Constructor<Person> cons = clazz.getDeclaredConstructor(String.class, int.class);
cons.setAccessible(true);
Object obj = cons.newInstance("Tom",12);
System.out.println(obj.toString());
Person p = (Person)obj;
System.out.println(p);

//获取属性
Field age = clazz.getDeclareField("age");
//设置权限
age.setAccessible(true);
//设置属性:将上面实例化对象的年龄赋值为10
age.set(p,10);
System.out.println(p);


//获取方法
Method show = clazz.getDeclaredMethod("show", String.class);
//设置权限
show.setAccessible(true);
//调用方法
show.invoke(p,"中国");


通过反射获取class实例的四种方式

 Class<Person> clazz = Person.class;
 System.out.println(clazz);

 Person p1 = new Person();
 Class clazz2 = p1.getClass();
 System.out.println(clazz2);

 Class<?> clazz3 = Class.forName("Person");
 System.out.println(clazz3);

 System.out.println(clazz == clazz2);
 System.out.println(clazz == clazz3);


 //4
 ClassLoader classLoader = reflection.class.getClassLoader();
 Class<?> clazz4 = classLoader.loadClass("Person");
 System.out.println(clazz4);

系统类加载器、拓展类加载器、引导类加载器的了解

 //对于自定义类,使用系统类加载器进行加载
 ClassLoader classLoader = reflection.class.getClassLoader();
 System.out.println(classLoader);
 //调用系统类加载的getParent():获取扩展类加载器
 ClassLoader parent = classLoader.getParent();
 System.out.println(parent);
 //无法获取引导类加载器
 //引导类加载器主要负责加载java的核心内库,无法加载自定义类的
 ClassLoader parent1 = parent.getParent();
 System.out.println(parent1);

读取配置Properties文件的的方法

        //Properties:用来读取配置文件
        Properties pro = new Properties();

        //读取配置文件的方式一:
        //此时的文件默认在当前的Module下
        FileInputStream fis = new FileInputStream("jdbc.properties");
        pro.load(fis);
        String user = pro.getProperty("user");
        String password = pro.getProperty("password");
        System.out.println(user + "    password" + password);

        //读取配置文件的方式二:
        //此时文件默认在src中
        ClassLoader classLoader = reflection.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
        pro.load(is);

        String user1 = pro.getProperty("user");
        String password1 = pro.getProperty("password");
        System.out.println(user1 + "    password" + password1);



通过实例体会反射的动态性

 for(int i = 0;i < 100;i++){
     int num = new Random().nextInt(3);//0,1,2
     String classPath = "";
     switch(num){
         case 0:
             classPath = "java.util.Date";
             break;
         case 1:
             classPath = "java.lang.Object";
             break;
         case 2:
             classPath = "Person";
             break;
     }

     try {
     //通过不同的字符串来创建对象
         Object obj = getInstance(classPath);
         System.out.println(obj);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }



public Object getInstance(String classPath) throws Exception {
    Class clazz =  Class.forName(classPath);
    return clazz.newInstance();
}

getFields()获取public的属性 vs getDeclareFields()获取所有的属性

Class<java1.Person> clazz = java1.Person.class;
 //获取属性结构
 //getFields():获取所有pulic的属性
 Field[] field = clazz.getFields();
 for (Field f :
         field) {
     System.out.println(f);
 }

 //getDeclaredFields():获取所有属性(不包含父类中的属性)
 Field[] declaredFields = clazz.getDeclaredFields();
 for (Field f :
         declaredFields) {
     System.out.println(f);
 }

获取具体的结构:getModifiers()权限修饰符,getType()数据类型,getName()变量名

 Class<Person> clazz = Person.class;
 Field[] declaredFields = clazz.getDeclaredFields();
 for(Field f:declaredFields){
     //1.权限修饰符
     int modifiers = f.getModifiers();
     System.out.println(Modifier.toString(modifiers));
     //2.数据类型
     Class<?> type = f.getType();
     System.out.println(type.getName() + "\t");
     
     //3.变量
     String name = f.getName();
     System.out.println(name);
 }

获取方法体 和 构造器体

        Class<java1.Person> clazz = java1.Person.class;

        //获取所有的方法
        Method[] methods = clazz.getMethods();
        for (Method m :methods) {
            System.out.println(m);
        }
        System.out.println("____________________________________");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m :declaredMethods) {
            System.out.println(m);
        }
        System.out.println("**********************************");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c :constructors) {
            System.out.println(c);
        }
        System.out.println("**********************************");
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor c :declaredConstructors) {
            System.out.println(c);
        }

获取运行时,方法的所有修饰

        Class<java1.Person> clazz = java1.Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m : declaredMethods){
            //1.获取方法声明的注解
            Annotation[] annos = m.getAnnotations();
            for(Annotation a : annos){
                System.out.println(a);
            }

            //2.权限修饰符
            System.out.print(Modifier.toString(m.getModifiers()) + "\t");

            //3.返回值类型
            System.out.print(m.getReturnType().getName() + "\t");

            //4.方法名
            System.out.print(m.getName());
            System.out.print("(");
            //5.形参列表
            Class[] parameterTypes = m.getParameterTypes();
            if(!(parameterTypes == null && parameterTypes.length == 0)){
                for(int i = 0;i < parameterTypes.length;i++){

                    if(i == parameterTypes.length - 1){
                        System.out.print(parameterTypes[i].getName() + " args_" + i);
                        break;
                    }

                    System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
                }
            }

            System.out.print(")");

            //6.抛出的异常
            Class[] exceptionTypes = m.getExceptionTypes();
            if(exceptionTypes.length > 0){
                System.out.print("throws ");
                for(int i = 0;i < exceptionTypes.length;i++){
                    if(i == exceptionTypes.length - 1){
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }

                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }


            System.out.println();
        }

获取父类,带泛型的父类,父类的泛型

    @Test//p24:获取运行时类的父类
    public void test18(){
        Class<java1.Person> clazz = java1.Person.class;

        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }
    @Test//获取运行时类的带泛型的父类
    public void test19(){
        Class<java1.Person> clazz = java1.Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }
    @Test// 获取运行时类的带泛型的父类的泛型
    public void test20(){
        Class<Person> clazz = java1.Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
//        System.out.println(actualTypeArguments[0].getTypeName());
        System.out.println(((Class)actualTypeArguments[0]).getName());

    }

获取接口

    @Test//获取运行时类实现的接口
    public void test21(){
        //类实现的接口
        Class<java1.Person> clazz = java1.Person.class;

        Class[] interfaces = clazz.getInterfaces();
        for(Class c : interfaces){
            System.out.println(c);
        }

        System.out.println();

        //获取运行时类的父类实现的接口
        Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
        for(Class c : interfaces1){
            System.out.println(c);
        }
    }

获取运行时类所在的包

    @Test
    public void test24(){
        Class<java1.Person> clazz = java1.Person.class;

        Package pack = clazz.getPackage();
        System.out.println(pack);
    }

获取类的注解

    public void test25(){
        Class<java1.Person> clazz = java1.Person.class;

        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annos : annotations){
            System.out.println(annos);
        }
    }

通过反射调用静态方法:invoke(null)

    @Test//p27:调用运行时类中指定结构:属性、方法、构造器
    public void test2425() throws Exception{
        Class<java1.Person> clazz = java1.Person.class;
        java1.Person p = (java1.Person)clazz.newInstance();
        Method show = clazz.getDeclaredMethod("show", String.class);
        show.setAccessible(true);
        Object chn = show.invoke(p, "CHN");
        System.out.println(chn);

        System.out.println("**********如何调用静态方法");

        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
//        Object invoke = showDesc.invoke(Person.class);
        Object invoke = showDesc.invoke(null);
        System.out.println(invoke);
    }
框架开发秘技:Java反射基础篇 运行时加载需要的类,如果运行时不用该类,即使该类并不存在,也不会报错,降低了依赖性,可以看到,动态加载起始刚好和静态加载相反,它取决于你运行时用到了哪些代码逻辑,用什么加载什么,即使代码中存在不存在的类或者代码块,只要本次运行用不到,那就不会抛异常,不影响正常编译和运行。不过反射也是有一些缺点的,一个明显的不足就是它的执行时间会比较长,相对于传统的方式而言,但是可以通过一些手段进行一定的优化,尽管效果可能不是那么明显。若已知具体的类,通过类的class获取,该方式最安全可靠,程序性能也较高; 阅读详情

相关推荐

从想法到零件:手把手拆解一个汽车功能如何从PRD写到SSTS和CTS

本文详细拆解了汽车电子需求从市场文档(MRD)到零部件技术规范(CTS)的完整流程,以雨天自动关窗功能为例,展示了PRD、SSTS和CTS的编写要点与交互设计。文章重点解析了系统分解的艺术和零部件落地的精确参数要求,为汽车电子工程师提供了从概念到实现的全流程实践指南。

weixin_30300225的博客 480

JAVA---interface和class

Java 接口 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。 除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。 接口无

strong90的博客 6094

【从零开始学产品经理】项目立项实战(1)——基本方案与可行性分析:基于微信小程序的记账本

主要阶段:立项-设计-开发-测试-上线-运营-总结。

Ckiyvo的博客 3210

Java 自定义注解 @interface 笔记

前言 使用自定义注解,反射知识 一、了解一下基础 1、元注解(meta-annotation): 元注解可用于自定义注解。Java定义的元注解:     1).@Target //定义该注解可以使用在什么元素上,如类,接口等     2).@Retention //定义该注解的生命周期,     3).@Documented //是一个标记注解,如可标记在javadoc     4)....

嘻哈嘻哈 483

基于Stigmergy的团队LLM wiki协作机制与FastAPI工程实践

大语言模型驱动的知识管理正在改变个人笔记与团队文档的维护方式,但当多人共同维护一个维基时,如何避免版本覆盖、上下文丢失和幻觉污染成为核心挑战。Stigmergy这一源自生物学的协作机制提供了新思路:通过共享环境中的痕迹(如评论、标记、修订历史)实现异步协作,无需实时沟通或中心协调者。本文将原理落地为可工程化的系统,设计Page、Revision、Trace三大实体,并结合向量索引与LLM审查流程,最终用FastAPI与SQLite搭建一个最小可运行原型。从白蚁筑巢到团队知识库,Stigmergy让每个参与者

weixin_34174322的博客 364

MATLAB PDE工具箱电磁场仿真平行电容板及电偶极子详解

首先打开matlab,在命令行输入pdetool打开PDE工具箱 工具箱的功能我就不赘述了,大概就是以有限元的数值计算方法,计算二阶偏微分方程,因此可以解决电磁场、热力学等问题。 首先点击左上角按钮,画三个矩形 画完一个后可以双击矩形编辑,参数如下: 其中R1表示上极板,R2表示下极板,R3表示整个空间区域。 在上方Set formula为R3-R2-R1,表示求解区域是整个空间区域减去两个极板。下拉框选择Electrostatics表示求解的是静电场问题。 接下来点击上方菜单栏中的这个按钮,表

weixin_42845306的博客 1万+

java @interface 自定义注解

1. 注解的好处 注解可以替代配置文件完成对某些功能的描述,减少程序配置; 在没有配置文件的情况下,我们去观察代码,并不需要同时打开两个文件来观察这个字段到底对应数据库的哪个列,减少了程序繁琐性,使得代码更加清晰易懂; 目前市面上流行的框架基本上都包含了注解配置,那么针对于开源项目,我们在阅读项目代码时,不懂注解如何实现,真的是举步难坚,所以,学习注解也可以加强我们对开源项目源码的解读。 ...

u013161431的博客 403

国产数据库全解析:openGauss、OceanBase、TiDB与KingbaseES的核心优势与应用场景指南

本文将深入剖析openGauss、OceanBase、TiDB和KingbaseES这四款主流国产数据库的核心内容,并针对国产化过程中给出使用建议,以帮助企业根据自身需求选择合适的数据库解决方案。国产数据库在性能、扩展性、兼容性、安全性等方面展现出强大实力,能够满足不同行业、不同场景的需求。企业在进行国产化过程中,应充分考虑业务特点、技术栈、团队能力等因素,结合上述分析,选择最适合自身的国产数据库产品。随着国产数据库技术的持续发展与生态完善,它们将成为推动企业数字化转型、保障数据安全的重要力量。

java专栏 8779

java interface class,Java – 从Interface类型而不是Class声明

在我寻求正确地掌握Interface最佳实践,我注意到声明,如:List myList = new ArrayList();代替ArrayList myList = new ArrayList();– 对我的理解,原因是因为它允许灵活性,在某一天你不想实现一个ArrayList,但可能是另一种类型的列表。有了这个逻辑,我设置了一个例子:public class InterfaceTest {pub...

weixin_26848497的博客 231

YOLOv8 | 损失函数改进,最新提出的Shape-IoU,有效涨点

作为检测器定位分支的重要组成,边框回归损失在目标检测任务中发挥巨大作用。现有的边框回归方法,通常考虑了GT框与预测框之间的几何关系,通过使用边框间的相对位置与相对形状等计算损失,而忽略了边框其自身的形状与尺度等固有属性对边框回归的影响。为了弥补现有研究的不足,本文提出聚焦边框自身形状与尺度的边框回归方法。首先我们对边框回归特性进行分析,得出边框自身形状因素与尺度因素会对回归结果产生影响。

kay_545 1913

【Claude】媒体文件处理错误:PDF 与 Image 过大的检测与预处理方法 bug报错已解决

图片压缩是必须的:原始图片的 base64 会占用大量 TokenPDF 提取文本优于传图片:文本版 PDF 比扫描版更省 Token分块处理大文件:不要一次性处理整个大文件控制分辨率:800x800 通常足够 Claude 分析。

博客 6359

java interface的定义变量_【Java关键字-Interface】为什么Interface中的变量只能是 public static final...

三个关键字在接口中的存在原因:public:接口可以被其他接口继承,也可以被类实现,类与接口、接口与接口可能会形成多层级关系,采用public可以满足变量的访问范围;static:如果变量不是static的,那么接口必须实例化才可以访问自己的变量,接口不能被实例化,故非static的变量是无效的;final:如果变量不是final的,而方法是abstract的,因此接口中的方法又不可以修改变量值,...

weixin_33067503的博客 2038

VS2019项目使用CGAL6.1配置教程详细步骤

在VS2019项目中使用CGAL详细步骤

插件开发 331

java基础:反射

java反射的核心是:程序动态获得加载类,并且获得类当中的各种详细信息,java “万物皆对象”。java反射的适用范围:当我们的程序在运行时,可能需要动态的加载一些类并创建其实例,这些类可能最初用不到,只有在需要时才加载到JVM,即运行时按需加载,例如servelet中没有main方法,需要反射启动,jdbc等jar包加载需要用到class.forName()加载类。

2301_78125917的博客 682

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

基础篇:深入解析JAVA反射机制

JAVA反射机制,JDK动态代理。Class\Constructor\Method\Field

潜行前行的专栏 2969

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Java基础: 反射

静态语言与动态语言 动态语言: 是一类在运行时可以改变其结构的语言:例如新的函数,对象,甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。 主要动态语言:Object-C,C#,JavaScript,PHP,Python等 下面是一段JavaScript代码,它在程序运行时就可以改变x的值 静态语言: 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java,C,C++ Java不是动态语言,但Java可以称之为“

qq_43379465的博客 391

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Java基础加强: 反射

Java基础加强: 反射   字节码: 得到字节码的三种方式: 1.类名.Class(); 2.类的实例对象.getClass(); 3.Class.forName(完整类名); Class.forName(完整类名)作用:返回字节码   当这个类的字节码已经在内存中时直接返回该字节码,当JAVA 虚拟机内中没有加载该字节码时,就用类加载器去加载,把加载进来的字节码在虚拟机内存中缓存

wang6xin6nian6的专栏 587

java 反射基础_Java基础教程:反射基础

Java基础教程:反射基础引入反射反射是什么能够动态分析类能力的程序称为反射。反射是一种很强大且复杂的机制。Class类在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时的类型标识。这个对象追踪着每个对象所属的类。虚拟机利用运行时类的信息选择相应的方法执行。我们可以通过专门的Java类访问这些信息。保存这些信息的类称为Class。直接获取Class cl1 =Date.class...

weixin_39861955的博客 64

Java基础:Java的反射

这篇文章主要介绍了Java的反射详细教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下。放假在家里休息,闲来无事,想巩固巩固自己的基础知识。Java基础这个我会一直更新的,希望大家关注 收藏 点赞。

weixin_42188778的博客 227
上一篇: Java基础:网络编程
下一篇: Java基础:Optional类和lambda表达式
Camellia0212
博客等级 码龄6年 113粉丝 69原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值