首页 > 编程语言 >Java技术复习提升 17反射

Java技术复习提升 17反射

时间:2024-11-30 15:28:53浏览次数:7  
标签:Java 复习 17 System class public println Class out

本章涉及到框架开发中必用的反射以及常用方法 很重要 注重理解并实践

第17章 反射

17.1 一个需求引出反射

package com.fsl;
public class Cat {
    private String name = "招财猫";
    public int age = 10; //public的
    public Cat() {} //无参构造器
    public Cat(String name) {
        this.name = name;
    }
    public void hi() { //常用方法
        //System.out.println("hi " + name);
    }
    public void cry() { //常用方法
        System.out.println(name + " 喵喵叫..");
    }
}

 

package com.fsl;

import com.fsl.Cat;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
 * 反射问题的引入
 */
@SuppressWarnings({"all"})
public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //根据配置文件 re.properties 指定信息, 创建Cat对象并调用方法hi
        //老韩回忆
        //传统的方式 new 对象 -》 调用方法
//        Cat cat = new Cat();
//        cat.hi(); ===> cat.cry() 修改源码

        //我们尝试做一做 -> 明白反射
        //1. 使用Properties 类, 可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\main\\resources\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"
        String methodName = properties.get("method").toString();//"hi"
        System.out.println("classfullpath=" + classfullpath);
        System.out.println("method=" + methodName);

        //2. 创建对象 , 传统的方法,行不通 =》 反射机制
        //new classfullpath();

        //3. 使用反射机制解决
        //(1) 加载类, 返回Class类型的对象cls
        Class cls = Class.forName(classfullpath);
        //(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例
        Object o = cls.newInstance();
        System.out.println("o的运行类型=" + o.getClass()); //运行类型
        //(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi"  的方法对象
        //    即:在反射中,可以把方法视为对象(万物皆对象)
        Method method1 = cls.getMethod(methodName);
        //(4) 通过method1 调用方法: 即通过方法对象来实现调用方法
        System.out.println("=============================");
        method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)
    }
}

 

classfullpath=com.fsl.Cat
method=cry

 

 

17.2 反射机制

  • java reflection

反射机制允许程序执行期借助于Reflection API取得任何类的内部信息 比如成员变量 构造器 成员方等 并能操作对象的属性和方法 反射在设计模式和框架底层都会用到

加载完类之后 在堆中就产生了一个Class类型的对象 一个类只有一个Class对象 这个对象包含了类的完整结构信息 通过这个对象得到类的结构 这个对象就像一面镜子 通过这个镜子看到类的结构 所以形象地称之为 反射

  • Java反射原理图

  •  反射相关的主要类

package com.fsl;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

class reflection{
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\main\\resources\\re.properties"));

        String classFullPath=properties.get("classfullpath").toString();
        String methodName=properties.get("method").toString();
        System.out.println(classFullPath+" "+methodName);

        Class cls=Class.forName(classFullPath);
        System.out.println(cls);

        //获取method,field,constructor
        Method method=cls.getMethod(methodName);
        Field field=cls.getField("age");//注意只能获取非private属性
        Constructor constructor1=cls.getConstructor();
        Constructor constructor2=cls.getConstructor(String.class);
        System.out.println(method+" "+field+" "+constructor1+" "+constructor2);
    }
}

 

  •  反射优点缺点

个人理解:

首先 我们要了解编译时与运行时的本质区别

编译时:编译器在这个阶段处理源代码,将其转换为字节码(对于 Java 而言)。在编译时,编译器只能基于已有的源代码和静态的配置(如固定的代码逻辑、常量等)进行操作。它无法知道运行时的实际情况,例如用户在运行程序时可能更改的配置文件内容。

运行时:程序在运行时,JVM(Java 虚拟机)加载字节码并执行。在这个阶段,程序可以获取外部环境的信息,如配置文件的内容、用户输入等,并根据这些信息动态地调整行为。

编译时创建对象适合对性能要求较高且业务逻辑简单的场景,而运行时创建对象(尤其是通过反射等机制)更适合框架开发等需要高度灵活性和扩展性的场景。框架开发选择运行时创建对象主要是为了满足多样化的用户需求、支持插件扩展和实现松耦合设计。

而反射可以做什么事呢?

在框架开发中(如Spring),我们往往都是通过配置文件来确定创建哪些对象 因为框架通常需要处理各种各样的业务场景和用户需求 例如在 Spring 框架中,通过运行时创建对象,可以根据配置文件(如 XML 配置或 Java 配置类)动态地决定要创建哪些对象,并处理它们之间的依赖关系 不同的用户可能有不同的配置需求 运行时创建对象可以很好地适应这种变化 所以我们属于运行时创建对象 而运行时创建对象就是通过反射来做的

17.3 Class类

 

 

 

package com.fsl;

class class1{
    public static void main(String[] args) throws ClassNotFoundException {
        Class cls1=Class.forName("com.fsl.Cat");
        Class cls2=Class.forName("com.fsl.Cat");
        Class cls3=Class.forName("com.fsl.Cat");
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
        System.out.println(cls3.hashCode());
    }
}

 //三个Class对象的hashcode()一样 说明对于存放在对立的Class类对象 内存中只有一份 因为类只加载一次

 

  •  class类常用方法

 17.4 获取class类对象

 

 

package com.fsl;
class getclass{
    public static void main(String[] args) throws ClassNotFoundException {
        //获取class对象的六种方式
        Class<?> cls1=Class.forName("com.fsl.Cat");
        System.out.println(cls1);

        Class cls2=Cat.class;
        System.out.println(cls2);

        Cat cat = new Cat();
        Class cls3=cat.getClass();
        System.out.println(cls3);

        ClassLoader cl=cat.getClass().getClassLoader();
        Class cls4=cl.loadClass("com.fsl.Cat");
        System.out.println(cls4);

        Class cls5=int.class;
        System.out.println(cls5);

        Class cls6=Integer.TYPE;
        System.out.println(cls6);
    }
}

 

 

17.5 哪些类型有Class对象

 

 

package com.fsl;

import java.io.Serializable;
/**
 * 演示哪些类型有Class对象
 */
public class AllTypeClass {
    public static void main(String[] args) {
        Class<String> cls1 = String.class;//外部类
        Class<Serializable> cls2 = Serializable.class;//接口
        Class<Integer[]> cls3 = Integer[].class;//数组
        Class<float[][]> cls4 = float[][].class;//二维数组
        Class<Deprecated> cls5 = Deprecated.class;//注解
        //枚举
        Class<Thread.State> cls6 = Thread.State.class;
        Class<Long> cls7 = long.class;//基本数据类型
        Class<Void> cls8 = void.class;//void数据类型
        Class<Class> cls9 = Class.class;//

        System.out.println(cls1);
        System.out.println(cls2);
        System.out.println(cls3);
        System.out.println(cls4);
        System.out.println(cls5);
        System.out.println(cls6);
        System.out.println(cls7);
        System.out.println(cls8);
        System.out.println(cls9);
    }
}

 

17.6 类加载

  • 类加载时机

  • 类加载过程图

  •  类加载各阶段完成任务

  •  加载阶段
  •  连接阶段 -验证

  • 连接阶段-准备
  •  连接阶段-解析

  •  Initialzation初始化

 17.7 通过反射获取类结构信息

 

 

 

package com.fsl;

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
 * 演示如何通过反射获取类的结构信息
 */
public class ReflectionUtils {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        ReflectionUtils re=new ReflectionUtils();
        re.api_01();
        re.api_02();
    }
    @Test
    public void api_02() throws ClassNotFoundException, NoSuchMethodException {
        //得到Class对象
        Class<?> personCls = Class.forName("com.fsl.Cat");
        //getDeclaredFields:获取本类中所有属性
        //规定 说明: 默认修饰符 是0 , public  是1 ,private 是 2 ,protected 是 4 , static 是 8 ,final 是 16
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性=" + declaredField.getName()
                    + " 该属性的修饰符值=" + declaredField.getModifiers()
                    + " 该属性的类型=" + declaredField.getType());
        }

        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法=" + declaredMethod.getName()
                    + " 该方法的访问修饰符值=" + declaredMethod.getModifiers()
                    + " 该方法返回类型" + declaredMethod.getReturnType());

            //输出当前这个方法的形参数组情况
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("该方法的形参类型=" + parameterType);
            }
        }

        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("====================");
            System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名

            Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("该构造器的形参类型=" + parameterType);
            }
        }
    }

    //第一组方法API
    @Test
    public void api_01() throws ClassNotFoundException, NoSuchMethodException {
        //得到Class对象
        Class<?> personCls = Class.forName("com.fsl.Cat");
        //getName:获取全类名
        System.out.println(personCls.getName());//com.hspedu.reflection.Person
        //getSimpleName:获取简单类名
        System.out.println(personCls.getSimpleName());//Person
        //getFields:获取所有public修饰的属性,包含本类以及父类的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {//增强for
            System.out.println("本类以及父类的属性=" + field.getName());
        }
        //getDeclaredFields:获取本类中所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性=" + declaredField.getName());
        }
        //getMethods:获取所有public修饰的方法,包含本类以及父类的
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println("本类以及父类的方法=" + method.getName());
        }
        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法=" + declaredMethod.getName());
        }
        //getConstructors: 获取所有public修饰的构造器,包含本类
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("本类的构造器=" + constructor.getName());
        }
        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名
        }
        //getPackage:以Package形式返回 包信息
        System.out.println(personCls.getPackage());//com.hspedu.reflection
        //getSuperClass:以Class形式返回父类信息
        Class<?> superclass = personCls.getSuperclass();
        System.out.println("父类的class对象=" + superclass);//
        //getInterfaces:以Class[]形式返回接口信息
        Class<?>[] interfaces = personCls.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println("接口信息=" + anInterface);
        }
        //getAnnotations:以Annotation[] 形式返回注解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("注解信息=" + annotation);//注解
        }
    }
}

 

 

 

 

标签:Java,复习,17,System,class,public,println,Class,out
From: https://blog.csdn.net/weixin_60566743/article/details/144153608

相关文章

  • Java入门:20.Calendar类与新日期类的使用
     1Calendar日历类*可以针对于日期中的每一个日期项,进行操作 *年,月,日,时,分,秒,毫秒,星期*Calendar对象创建Calendartime=Calendar.getInstance();//默认表示当前系统时间  *Calendar对象与Date对象之间的转换//Date-->Calendar Calendartime=Cale......
  • P1135 奇怪的电梯 JAVA题解
    题目描述呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 ii 层楼(1≤i≤N1≤i≤N)上有一个数字 KiKi​(0≤Ki≤N0≤Ki​≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例......
  • P2658 汽车拉力比赛 JAVA题解
    package篮桥杯.d;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.StreamTokenizer;importjava.util.LinkedList;importjava.util.Queue;publicclassMain{//自定义的输入类,比普通Scanner快两......
  • Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
    背景事件:近日,优衣库宣布不再使用新疆棉花,这一举措引发了广泛的社会讨论。消费者的反应和舆论的压力,让优衣库的决策迅速影响了市场和品牌形象。类似的,许多系统也面临着需要根据外部事件或状态的变化,做出即时反应的需求。在软件设计中,观察者模式(ObserverPattern)就是为了处理这种......
  • 如何让Java的线程彼此同步?
    在Java中,线程同步是一个重要的概念,用于确保多个线程在访问共享资源时能够保持数据的一致性和正确性。Java提供了多种线程同步机制,以下是具体的同步方法:一、使用synchronized关键字synchronized同步方法:即在方法声明中使用synchronized关键字。当一个线程访问某个对象的synchr......
  • 【无标题】JAVA策略模式代码例子
    在Java中,您可以使用面向对象编程中的继承和多态性来实现您的需求。首先,我们定义一个`Good`类,该类包含满减策略和打折策略。然后,我们可以让`Shoe`类和`Cloth`类继承自`Good`类。为了实现不同的折扣或满减策略,可以考虑使用策略模式。 下面是一个简单的实现示例: ###1.定义......
  • C# mvc +axios + web api + javascript
    2024年,是Insus.NET生命中转折的一年,许久没有更新博客了。许多网友在通讯或邮件私聊,希望在博客上更新内容,分享一些技能与通用的博文。 回归正题,在C#mvc使用javascriptaxios访问webapi。在mssqlserver创建数据表 存储过程... C#MVC程序与数据库交互,创建entity:上......
  • Educational Codeforces Round 171 (Rated for Div
    EducationalCodeforcesRound171(RatedforDiv.2)-CodeforcesProblem-A-Codeforces几何构造没什么好说的,\(45\)度交的时候长度最大#include<bits/stdc++.h>usingnamespacestd;constintN=3e5+10;voidsolve(){ intx,y,k;cin>>x>>y>>k; if(x......
  • 婚纱摄影管理系统|Java|SSM|VUE| 前后端分离
    【重要1⃣️】前后端源码+万字文档+部署文档【重要2⃣️】正版源码有问题包售后【重要3⃣️】虚拟可复制品不支持退换货【重要3⃣️】虚拟可复制品不支持退换货【重要3⃣️】虚拟可复制品不支持退换货            【包含内容】【一】项目提供非常完整的源......
  • JavaEE进阶-----mybatis操作数据库(新手教程)
    文章目录1.创建项目2.mysql相关操作3.安装插件4.工程创建4.1Bean文件夹4.2Dao文件夹4.3xml文件内容解读4.4配置文件4.5测试文件1.创建项目我们创建项目的时候需要注意下面的这个内容:1)maven项目;2)选择配置:我们之前使用的这个lombok和这个web还是要继续选择的;与之前......