7月26日JavaSE学习笔记

news2024/11/25 16:38:11

反射

Java是面向对象的,有对象必须先有类, 有static修饰类的属性和方法;在Java中存储了类的内容,这个内容也应该是一个对象;Java中每一个用到的类都会加载一块内存,这每一块内存都是一个对象;这些对象记录了这些类中声明了哪些属性和方法以及构造方法,Java将这类抽象为一个Class类

类对象

类的类对象中存储了类中定义的内容:属性、方法、构造方法

Class类的对象是不能new的。

获取类对象的方式有三种:

1.通过类名获取类对象

        //通过类名获取类对象
        Class clazz = EasyClassA.class;

2.通过对象获取类对象

        //通过对象获取类对象
        clazz = new EasyClassA().getClass();

3.通过Class类的forName方法获取

        //通过Class类的forName方法获取
        clazz = Class.forName("com.easy725.EasyColor");

Field 类:字段

在Java中用Field类来记录类的属性

获取类中的public声明的公有属性:getField、getFields 

        c=Class.forName("com.easy726.Easy");        
        //获取类的属性
        //fName变量指向的对象就是Easy类中的name属性
        Field fName = c.getField("name");//传入属性名获取公共的属性

获取属性的值 get

        //可以获取某一个Easy类的对象的name属性的值
        Object objectName = fName.get(easy);
        System.out.println(objectName+"---反射");

设置属性的值 Set

        //注入该属性的值
        fName.set(easy,"李四");
        System.out.println(easy.name);

获取类中声明的任意属性:getDeclaredField

        Field fSex = c.getDeclaredField("sex");//默认访问权限
        Field fAddress = c.getDeclaredField("address");//私有private访问权限

访问私有属性必须先获取访问权限:setAccessible(true)

        //反射访问私有属性  必须先获取访问权限
        fAddress.setAccessible(true);//把访问权限设置为true
        fAddress.set(easy,"青岛市城阳区");
        System.out.println(fAddress.get(easy));

什么是反射?

在Java中,反射是指程序在运行时动态地检测、获取和操作类、对象、方法和属性的能力。通过反射,我们可以在运行时获取任意一个类的信息,包括类的名称、方法、字段等,并且可以在运行时创建对象、调用方法和访问属性。

反射就是在程序运行期间,可以动态的获取类中定义的属性和方法以及构造方法的机制(思想)的实现

反射的核心是 Class类程序中使用的每一个类,都有一个唯一的对应的Class对象


反射的API:能够调用的属性和方法 FieldMethodConstructor

API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

反射会破坏类的封装性,需要通过场景说明,反射和封装没有绝对的好坏,只是应用场景不同


通过反射创建对象
Easy easy = c.newInstance();//调用类的无参构造方法创建对象

下面演示了一个通过反射创建对象的案例:利用泛型写一个方法,根据读取到的Map中的键值对,通过反射创建对象并为对应属性赋值。

    public static <T> T getInstance(Class<T> tClass, Map values) throws InstantiationException, IllegalAccessException {
        //通过反射获取实例  创建对象
        T t = tClass.newInstance();//通过类中的无参构造方法创建对象
        //通过反射获取类中定义的属性
        Field[] farr = tClass.getDeclaredFields();//获取类中声明的所有属性
        //System.out.println(Arrays.toString(farr));
        for (Field fItem:farr){
            //获取属性的名字
            String fName = fItem.getName();
            //获取该属性在Map中的键值对    属性对应的值
            Object value = values.get(fName);
            //设置属性访问权限
            fItem.setAccessible(true);
            fItem.set(t,value);//把t对象的fItem属性的值设置为value
        }
        return t;//返回对象t
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Map map = new HashMap();
        map.put("code","C1001");
        map.put("name","张三");
        map.put("sex","女");
        Student stu = getInstance(Student.class,map);
        System.out.println(stu);
    }

Method 类:方法

在前面的Easy类中,已经写好了一个无参和一个有两个int类型参数的成员方法

    public void methodA(){
        System.out.println("methodA");
    }
    public void methodB(int a, int b){
        System.out.println("methodB");
        System.out.println("两个参数分别为:"+a+","+b);
    }

先通过类对象的 newInstance() 方法创建类的实例

        //获取类对象
        Class<Easy> c=Easy.class;
        Easy easy = c.newInstance();//创建实例

反射获取public方法:getMethod ( 传入方法名和参数列表 )

        //获取public方法,传入方法名和参数列表
        Method ma=c.getMethod("methodA");
        Method mb=c.getMethod("methodB", int.class, int.class);

面向对象的思想调用成员方法: 对象.方法名()

在反射中用 invoke ( 对象,参数 ) 驱动对象执行方法

        ma.invoke(easy);
        mb.invoke(easy,23,45);

Constructor 类:构造方法

前面提到,可以通过类对象的newInstance()方法直接调用无参构造方法创建实例,因而推荐每个类都要有一个无参的构造方法

        //反射获取构造方法
        Class<Easy> c= Easy.class;
        c.newInstance();//调用无参的构造方法

也可以通过 getConstructor() 方法直接获取一个构造方法的对象,因为构造函数名有约束,必须和类名相同,获取指定的构造函数只需要传入参数列表即可。

        Constructor<Easy> con = c.getConstructor();
        con.newInstance();//构造方法是谁就调用谁
        con = c.getConstructor(String.class);
        con.newInstance("张三");

Modifier 类:修饰符

使用Modifier的方法判断方法/属性/构造方法的修饰符

Modifier类将不同的修饰符定义为 int 类型的16进制整型常量;

相当于二进制的每一位都对应一个特定的修饰符

判断时只需要把获取的修饰符对应的整数,进行按位与运算,只要结果不为0,就说明有对应二进制位置的修饰符修饰:

        //修饰符 使用Modifier的方法判断方法/属性/构造方法的修饰符
        Field f = c.getDeclaredField("test");
        int fmod = f.getModifiers();
        //判断是否使用了某个修饰符
        Boolean bool = Modifier.isStatic(fmod);//           1 0 0 0
        System.out.println(fmod);//                 1 0 0 1 1 0 0 1 按位与运算不为 0
        System.out.println(bool);
        System.out.println(Modifier.toString(fmod));

内省

内省(Introspection)是一种通过反射机制来获取和操作类的属性、方法和事件的方式。

底层还是通过反射实现的,内省不会破坏封装性

通过获取属性的读方法和写方法(getter/setter)来获取和设置属性的内容,不会破坏类的封装性

        BeanInfo bi = Introspector.getBeanInfo(c);
        //只能获取setter和getter方法
        bi.getBeanDescriptor();
        PropertyDescriptor[] pds = bi.getPropertyDescriptors();//获取属性描述

        String pName = pds[0].getName();//获取属性的名字
        Method read = pds[0].getReadMethod();//对应属性的getter方法
        Method write = pds[0].getWriteMethod();//对应属性的setter方法
        System.out.println(pName);

        Easy easy = c.newInstance();
        write.invoke(easy,"张三");

补充

synchronized同步机制的底层原理:

synchronized在JVM内部是通过Monitor(监视器)来实现的,Monitor是一种同步机制,它依赖于底层操作系统的Mutex Lock(互斥锁)来实现。Monitor与Java对象相关联,当线程尝试进入synchronized修饰的方法或代码块时,它会尝试获取与该对象关联的Monitor的锁。

Monitor的获取与释放:当线程进入synchronized块时,它会执行一个monitorenter指令,尝试获取对象关联的Monitor的锁。如果Monitor处于无锁状态,该线程会成功获取锁,并在对象头中标记为已锁定。如果Monitor已被其他线程锁定,则进入该方法的线程将被阻塞直到获取到Monitor的锁。当线程退出synchronized块时,它会执行monitorexit指令,释放Monitor的锁,并允许其他等待的线程获取锁。


在JVM中,每个Java对象在内存中都有特定的结构,通常分为三块区域:对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)。其中,对象头是实现synchronized同步机制的关键部分。

对象头:对象头包含了对象的元数据信息,如哈希码(Hash Code)、GC分代年龄、锁状态标志、偏向线程ID、偏向时间戳等。这部分信息在JVM中用于支持对象的同步机制。


JVM(Java Virtual Machine)生命周期

JVM的生命周期可以概括为以下几个阶段:

1. 加载(Loading)
  • 将Java字节码文件(.class文件)从磁盘加载到JVM的内存中,并创建对应的Class对象,为程序的执行准备必要的类信息。
2. 链接(Linking)
  • 验证(Verification)检查加载的字节码是否符合JVM规范,确保没有违反安全性的操作,防止执行恶意代码或包含错误的字节码。
  • 准备(Preparation)为类的静态变量分配内存空间,并赋予其Java语言规范中定义的默认值(如int为0,boolean为false等),为类的初始化做准备。
  • 解析(Resolution)将符号引用(如类名、字段名、方法名)转换为直接引用(即内存中的实际地址),确保在程序执行时能够快速地定位到类和成员。
3. 初始化(Initialization)
  • 执行类构造器<clinit>()方法中的代码,包括静态变量的显式初始化和静态代码块的内容,完成类的初始化,准备类的实例创建和方法的调用
4. 使用(Using)
  • 在JVM运行时,根据程序逻辑执行方法调用、对象创建等操作,执行Java程序的逻辑功能。
5. 卸载(Unloading)
  • 当类不再被JVM中的任何对象、线程或类加载器引用时,该类会被从内存中卸载,回收内存资源,防止内存泄漏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1952575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习周报:文献阅读+HEC RAS案例

目录 摘要 Abstract 文献阅读&#xff1a;通过HEC RAS软件为罗马尼亚布加勒斯特市的Dmbovița河水管理的水力模型 文献摘要 讨论|结论 理论知识 边界条件计算 流量计算方式 曼宁公式 (Mannings Equation) 连续性方程 (Continuity Equation) 能量方程 (Energy Equatio…

EB Tresos 基于S32K3芯片 ICU模块实现gpio外部中断配置[后续更新实现icu模块的其他功能]

环境&#xff1a;eb tresos 27.0.1 port 模块配置&#xff1a; 选择一个具有erq功能的引脚并配置为erq功能。如下我选择的是 PTB0 -EIRQ[8] - SIUL2_EXT_IRQ_8_15_ISR Platform 模块配置 在这个模块中配置中断的开关以及中断句柄 ICU模块配置 具体配置参考博客&#xff1a;…

【python】python大学排名数据抓取+可视化(源码+数据集+可视化+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

深度强化学习 ②(DRL)

参考视频&#xff1a;&#x1f4fa;王树森教授深度强化学习 前言&#xff1a; 最近在学习深度强化学习&#xff0c;学的一知半解&#x1f622;&#x1f622;&#x1f622;&#xff0c;这是我的笔记&#xff0c;欢迎和我一起学习交流~ 这篇博客目前还相对比较乱&#xff0c;后面…

黑马Java零基础视频教程精华部分_5_面向对象综合练习

系列文章目录 文章目录 系列文章目录一、文字版格斗游戏二、文字版格斗游戏进阶版三、对象数组练习1、对象数组1先学习一下键盘录入。注意&#xff1a;两套体系不能混用 对象数组2对象数组3对象数组4对象数组5 一、文字版格斗游戏 GameTes.javat代码如下&#xff1a; package …

[数通网络基础]——广播域与路由器

广播域 广播域概述 广播域是指网络中能接收到同一广播消息的所有设备的集合。 广播域的大小会影响网络的性能和效率。当同一个广播域内广播报文过多时&#xff0c;会对局域网造成干扰&#xff0c;导致网络延迟&#xff0c;网络拥塞&#xff08;上网卡&#xff0c;上网慢&…

hot100-3滑动窗口

3无重复字符得最长字串 438找出字符串中得所有字母异位词 遇到没有限制字母排列方式的&#xff0c;都可以考虑维护一个charCode数组 和第567题相似 567字符串得排列&#xff08;和438一个思路&#xff09;

docker dotnet-dump离线部署

1.下载指定dotnet版本的dotnet-dump 示例地址&#xff1a; https://www.nuget.org/packages/dotnet-dump/3.1.141901#dependencies-body-tab 我本地测试的是netcore 3.1 2. 在本地解压 将文件解压出来。看到any目录,能看到我们要用的dotnet-dump文件 3. 将tools/netcoreapp2.…

AccessLog| 一款开源的日志分析系统

前言 ClkLog作为分析系列产品中的前端数据分析系统&#xff0c;通过采集前端应用数据进行用户行为分析。其社区版从23年9月发布至今已有近一年&#xff0c;商业版也上线快半年&#xff0c;感谢大家一直以来的关注和支持&#xff0c;ClkLog会继续做好产品升级与服务&#xff0c;…

算法-----递归~~搜索~~回溯(宏观认识)

目录 1.什么是递归 1.1二叉树的遍历 1.2快速排序 1.3归并排序 2.为什么会用到递归 3.如何理解递归 4.如何写好一个递归 5.什么是搜索 5.1深度&#xff08;dfs&#xff09;优先遍历&优先搜索 5.2宽度&#xff08;bfs&#xff09;优先遍历&优先搜索 6.回溯 1.什…

微信小游戏之 三消(一)

首先设定一下 单个 方块 cell 类&#xff1a; 类定义和属性 init 方法 用于初始化方块&#xff0c;接收游戏实例、数据、宽度、道具类型和位置。 onWarning 方法 设置警告精灵的帧&#xff0c;并播放闪烁动作&#xff0c;用于显示方块的警告状态。 grow 方法 根据传入的方向…

【科研技巧】如何查找一个人发表的所有文章

使用此网站 点击作者检索 点击作者名字 可以看到全部文章

SpringBoot运行流程源码分析

run方法核心流程 我们在启动SpringBoot的时候调用的是SpringApplication类的静态run方法。其核心流程如下图所示&#xff1a; 在run方法内完成了SpringApplication的声明周期。&#xff0c;这个过程涉及的几个核心类如下&#xff1a; SpringApplicationRunListeners&#xff…

【C++】:红黑树的应用 --- 封装map和set

点击跳转至文章&#xff1a;【C】&#xff1a;红黑树深度剖析 — 手撕红黑树&#xff01; 目录 前言一&#xff0c;红黑树的改造1. 红黑树的主体框架2. 对红黑树节点结构的改造3. 红黑树的迭代器3.1 迭代器类3.2 Begin() 和 End() 四&#xff0c;红黑树相关接口的改造4.1 Find…

Qt基础 | 自定义界面组件 | 提升法 | 为UI设计器设计自定义界面组件的Widget插件 | MSVC2019编译器中文乱码问题

文章目录 一、自定义 Widget 组件1.自定义 Widget 子类2.自定义 Widget 组件的使用 二、自定义 Qt Designer 插件1.创建 Qt Designer Widget 插件项目2.插件项目各文件的功能实现3.插件的编译与安装4.使用自定义插件5.使用 MSVC 编译器输出中文的问题 一、自定义 Widget 组件 当…

【React】详解受控表单绑定

文章目录 一、受控组件的基本概念1. 什么是受控组件&#xff1f;2. 受控组件的优势3. 基本示例导入和初始化定义函数组件处理输入变化处理表单提交渲染表单导出组件 二、受控组件的进阶用法1. 多个输入框的处理使用多个状态变量使用一个对象管理状态 2. 处理选择框&#xff08;…

leetcode-104. 二叉树的最大深度

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,n…

24款美规奔驰GLS450更换中规高配主机系统,提升车辆功能和使用体验

平行进口奔驰GLS450 语音小助手要说英语 十分的麻烦 而且也没有导航&#xff0c;原厂记录仪也减少了 很不方便 那要怎么解决呢 往下看 其实很简单&#xff0c;我们只需要更换一台中规的新主机就可以实现以下功能&#xff1a; ①中国地图 ②语音小助手&#xff08;你好&#…

C++编译jsoncpp库

下载https://github.com/hailong0715/jsoncpp/tree/master windows编译工程 jsoncpp-master\makefiles\vs71 1.msvcprtd.lib(MSVCP140D.dll) : error LNK2005 解决办法&#xff1a; (1).工程(Project)->属性(Properties)->配置属性(Configuration Properties)->c/c-…

OZON打开哈萨克斯坦市场,OZON测试开通哈萨克斯坦市场中国产品

在全球化日益深入的今天&#xff0c;跨境电商成为了连接不同国家和地区消费者的重要桥梁。2024年7月26日&#xff0c;Ozon Global宣布了一项重大扩展计划&#xff0c;正式将中国卖家的销售版图拓展至哈萨克斯坦市场&#xff0c;为中国企业打开了新的增长机遇之门。 OZON哈萨克斯…