黑马程序员_JAVA基础加强——反射

本文深入讲解Java反射机制的基本概念及应用场景,包括类的加载过程、如何通过反射获取类的构造函数、方法和字段等内容。
---------------------- <a href="http://edu.youkuaiyun.com"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.youkuaiyun.com"target="blank">.Net培训</a>、期待与您交流! ----------------------

--什么是反射?

想要知道反射的概念,要先明白java类的作用是什么?java类就是用于描述一类事物的共性,这些事物包括现实中存在的事物,也包括虚拟的一些事物。把具有相同属性和行为的一类事物抽象化,就形成了类。那么,java中的所有类是不是也有一些共性的内容呢?我们知道,一个类是由多个部分组成的:成员变量、成员方法和构造方法等。那么我们是不是也可以把这些共性的内容抽取成一个类呢?在java中,使用Class这个类来描述java中所有的类。

在java中,所有的类都是Class的一个实例对象,它们的内容不同,但是,它们的特征相同,譬如,都有方法,有字段,有父类,有包。那么,它们的实例对象又是什么呢?学java基础的时候我们知道,每个类在被加载进内存时,都会先把它们对应的.class字节码加载进内存,那么,这份字节码就是Class的实例对象。那么,反射就是将类的字节码加载进内存,而后剖析出这个类的各个组成部分,包括构造函数、成员变量和方法等。这些信息用相应类的实例对象来表示,它们是Constructor、Field和Method等。
--加载类
了解了反射的概念后,我们就先创建一个类:Person。加载该类的字节码,然后通过反射技术剖析这个类的组成部分。
package cn.itcast.reflect;

import java.io.InputStream;
import java.util.List;
/**
 * 人类
 * @author 中关村阿旺
 *
 */
public class Person {
	
	public int age=44;   //年龄(public修饰)
	private static String address;   //住址(private static修饰)

	public Person(){
		System.out.println("person");
	}
		
	//构造方法,private修饰
	private Person(List list){
		System.out.println("list");
	}
	
	public void aa1(){
		System.out.println("aa1");
	}
	
	private void aa1(InputStream in){
		System.out.println(in);
	}
	
	//方法,static修饰
	public static void aa1(int num){
		System.out.println(num);
	}
	
	//main方法,static修饰,有点特殊
	public static void main(String[] args){
		System.out.println("main");
	}
}


  加载Person类就是将硬盘上的Person类的字节码文件内容加载到内存里,并封装成Class对象。
  加载类有三种方式:
  第一种方式:通过Class类的静态方法forName()加载类,该方法接收一个参数,字符串类型的完整类名称。
  例如:Class clazz=Class.forName("cn.itcast.reflect.Person");
  第二种方式:通过实例化类的对象加载该类。因为实例化对象的过程是先要加载该类到内存中,然后才会初始化对象。
  通过对象的getClass()方法获得Class对象,也就是该类的字节码。
  例如:Class clazz1=new Person().getClass();
  第三种方式:直接将该类的字节码加载进内存中。
  例如:Class clazz2=Person.class;
  以上三种方式,我们使用哪种方式都可以,类已经进内存了,就可以用反射技术剖析类的组成部分了。
--反射类的构造函数
 在java中Constructor类提供关于类的单个构造方法的信息以及对它的访问权限。
 例如:反射构造函数:public Person(){}
 通过Class类的getConstructor()方法可以得到一个Constructor对象。该方法接收一个参数,就是你反射的那个构造方法的参数的类型(字节码)。
 因为我们反射的是无参的构造函数,所以传入null值,得到构造函数对象。
 代码:Constructor c=clazz.getConstructor(null);
 此构造函数对象中有一个方法:newInstance(),可以返回我们反射的类的实例对象。该方法接收的参数是实际传入构造方法的参数。
 我们反射的是Person类,所以用Person对象接收。由于newInstance()方法返回类型是Object,所以需要强转。
 代码:Person p=(Person)c.newInstance(null);
 用得到的这个对象,我们可以获取该对象中封装的信息。
 System.out.println(p.age);        //返回44
 上面反射的是public修饰符修饰的构造函数,我们也可以反射非public修饰符修饰的构造函数。
 例如:反射构造函数:private Person(List list){}
 由于此构造函数反射的是private修饰的,所以可以通过Class类的getDeclaredConstructor()方法获取构造函数对象。 getDeclaredConstructor()方法可以反
 射在Person类中所有声明(定义)过的构造方法,包括private修饰的。
 由于此构造函数有参数,我们可以传入此构造函数参数的字节码即可。
 代码:Constructor c=clazz.getDeclaredConstructor(List.class);
 由于private修饰的成员只能在本类中被访问,但是,暴力反射可以在让其在本类外被访问。
 所谓暴力反射,就是将那些在反射的类中不是public修饰的成员方法、属性、构造方法等,强行打开它们的访问权限,使其可以在本类外访问。
 代码:c.setAccessible(true);这就是暴力反射
 代码:Person p=(Person) c.newInstance(new ArrayList());
 System.out.println(p.age);   //返回44
 
 注:另一种使用反射创建对象的方法,不是反射构造函数,而是直接使用Class类的newInstance()方法。这是因为java为了方便通过反射技术创建类的实例而添加的方法。
 例如:Person p=(Person) clazz.newInstance();
           System.out.println(p.age);   //返回44
--反射类的方法
 在java中Method类提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
1.反射类中的普通方法
 通过Class类的getMethod()方法得到Method对象,该方法接收两个参数,第一个指明需要反射的方法名称,第二个指明需要反射的方法的参数类型。
 例如:反射类的方法:public void aa1(){}
 代码:Method m=clazz.getMethod("aa1", null);
 使用Method对象的invoke()方法可以调用反射的方法,需要传入对象名(指明反射的是哪个对象的方法)和参数类型。
 代码:m.invoke(p, null);          //返回aa1
 上面的代码反射的是public修饰的方法,想要访问非public修饰的方法可以通过Class类的getDeclaredMethod()方法访问在Person类中定义(声明)的所有方法。
 例如:反射类的方法:private void aa1(InputStream in){}
 由于要反射的此方法有参数,那么在第二个参数中传入该参数的字节码即可。
 代码:Method m=clazz.getDeclaredMethod("aa1", InputStream.class);
 m.setAccessible(true);  //暴力反射
 代码:m.invoke(p, new FileInputStream("e:\\黑马\\黑马视频笔记
\\033java 基础加强\\课堂笔记1.txt"));    //返回java.io.FileInputStream@150bd4d
 注:如果反射的方法是一个静态方法,比如:public static void aa1(int num){}
 那么在用反射技术得到Method对象后,调用invoke()方法传入对象时,可以传入null。
 代码:m.invoke(null, 56);    //返回56
 2.反射类中的main方法
 反射类中的main方法:public static void main(String[] args)
 有两种调用方式:
 第一种方式:
  代码:Method m=clazz.getMethod("main", String[].class);
  由于main方法也是静态方法,所以可以不用传入对象。
  代码:m.invoke(null, new Object[]{new String[]{"aaa","bbb"}});    //返回main
  那么之所以这样写,是因为JDK1.4当中没有可变参数这一特性,它使用的是Object类型的数组作为参数,调用invoke()方法时,会把数组中的每一个元素当做一个参数来看待,也就是会把数组拆开。JDK1.5虽然有了可变参数这一新特性,但是它兼容JDK1.4,所以,它也会把可变参数当做是一个数组进行拆封。这样一拆,就成了两个字符串对象了,就与main方法的参数类型不一致了,所以会出现参数类型不匹配异常。为了解决这一异常,需要把数组再一次封装成数组,这样在进行拆封时,得到的仍然是一个数组,刚好符合main方法的参数类型。
  第二种方式:
  强制让java虚拟机把参数类型当做是一个Object类型的参数,而不是一个Object类型的数组。这样就不会进行拆封,而里面实际存放的是字符串数组,所以仍然与main方法的参数类型一致。
  代码:m.invoke(null, (Object)new String[]{"rrrr","dddd"});    //返回main
--反射类的字段
  在java中Field类提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
  通过Class类的getField()方法可以得到Field对象,该方法接收一个参数,即需要反射的字段的名称。
  例如:反射类的字段:public int age=44;
  代码:Field f=clazz.getField("age");
  可以根据Field类对象的get()方法得到该字段的值,该方法接收一个参数,指明需要反射的那个对象的字段。
  代码:int num=(Integer) f.get(p);  //由于该方法返回值为Object类型,而age字段为int,所以需要强转。
  代码:System.out.println(num);     //返回44
  注:由于Person类文件可能不是我们自己编写的,所以不知道字段的类型,我们可以通过Field类对象的getType()方法得到该字段所属类型的字节码,根据字节码判断该字段的类型。
  代码:Object value=f.get(p);
  代码:Class type=f.getType();   //获得指定字段的类型,返回字节码对象
  由于每种类型的字节码只存在一份,所以用“==”判断比较高效,当然equals()方法也可以。
  if(type == int.class){
       int newValue=(Integer) value;   //自动拆箱
       System.out.println(newValue);  //自动装箱
  }
  上面的代码反射的是public修饰的字段,那么反射非public修饰的字段需要使用Class类的getDeclaredField()方法,该方法可以反射在Person类中定义(声明)过的所有字段。
  例如:反射类的字段:private static String address;
  代码:Field f=clazz.getDeclaredField("address");
  代码:f.setAccessible(true);   //由于反射的是private修饰的字段,所以需要暴力反射。
  该字段没有手动赋予值,可以通过Field类对象的set()方法写入指定的值。该方法接收两个参数,一个是需要反射的类的对象,一个是赋予该字段的实际值。由于所要获取的字段是静态的,不必创建该类的对象,所以传入null。
  代码:f.set(null, "北京市");
  如果我们不知道该字段的类型,同样可以通过getType()方法得到。
  代码:Object value=f.get(null);
  代码:Class type=f.getType();
  if(type == String.class){
       String newValue=(String)value;
       System.out.println(newValue);    //返回北京市
  }
---------------------- <a href=" http://edu.youkuaiyun.com"target="blank">ASP.Net+Android+IOS 开发</a>、<a href=" http://edu.youkuaiyun.com"target="blank">.Net 培训</a>、期待与您交流! ----------------------
详细请查看:<a href="http://edu.youkuaiyun.com" target="blank"> http://edu.youkuaiyun.com </a>
AI 代码审查Review工具 是一个旨在自动化代码审查流程的工具。它通过集成版本控制系统(如 GitHub 和 GitLab)的 Webhook,利用大型语言模型(LLM)对代码变更进行分析,并将审查意见反馈到相应的 Pull Request 或 Merge Request 中。此外,它还支持将审查结果通知到企业微信等通讯工具。 一个基于 LLM 的自动化代码审查助手。通过 GitHub/GitLab Webhook 监听 PR/MR 变更,调用 AI 分析代码,并将审查意见自动评论到 PR/MR,同时支持多种通知渠道。 主要功能 多平台支持: 集成 GitHub 和 GitLab Webhook,监听 Pull Request / Merge Request 事件。 智能审查模式: 详细审查 (/github_webhook, /gitlab_webhook): AI 对每个变更文件进行分析,旨在找出具体问题。审查意见会以结构化的形式(例如,定位到特定代码行、问题分类、严重程度、分析和建议)逐条评论到 PR/MR。AI 模型会输出 JSON 格式的分析结果,系统再将其转换为多条独立的评论。 通用审查 (/github_webhook_general, /gitlab_webhook_general): AI 对每个变更文件进行整体性分析,并为每个文件生成一个 Markdown 格式的总结性评论。 自动化流程: 自动将 AI 审查意见(详细模式下为多条,通用模式下为每个文件一条)发布到 PR/MR。 在所有文件审查完毕后,自动在 PR/MR 中发布一条总结性评论。 即便 AI 未发现任何值得报告的问题,也会发布相应的友好提示和总结评论。 异步处理审查任务,快速响应 Webhook。 通过 Redis 防止对同一 Commit 的重复审查。 灵活配置: 通过环境变量设置基
【直流微电网】径向直流微电网的状态空间建模与线性化:一种耦合DC-DC变换器状态空间平均模型的方法 (Matlab代码实现)内容概要:本文介绍了径向直流微电网的状态空间建模与线性化方法,重点提出了一种基于耦合DC-DC变换器的状态空间平均模型的建模策略。该方法通过数学建模手段对直流微电网系统进行精确的状态空间描述,并对其进行线性化处理,以便于系统稳定性分析与控制器设计。文中结合Matlab代码实现,展示了建模与仿真过程,有助于研究人员理解和复现相关技术,推动直流微电网系统的动态性能研究与工程应用。; 适合人群:具备电力电子、电力系统或自动化等相关背景,熟悉Matlab/Simulink仿真工具,从事新能源、微电网或智能电网研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握直流微电网的动态建模方法;②学习DC-DC变换器在耦合条件下的状态空间平均建模技巧;③实现系统的线性化分析并支持后续控制器设计(如电压稳定控制、功率分配等);④为科研论文撰写、项目仿真验证提供技术支持与代码参考。; 阅读建议:建议读者结合Matlab代码逐步实践建模流程,重点关注状态变量选取、平均化处理和线性化推导过程,同时可扩展应用于更复杂的直流微电网拓扑结构中,提升系统分析与设计能力。
内容概要:本文介绍了基于物PINN驱动的三维声波波动方程求解(Matlab代码实现)理信息神经网络(PINN)求解三维声波波动方程的Matlab代码实现方法,展示了如何利用PINN技术在无需大量标注数据的情况下,结合物理定律约束进行偏微分方程的数值求解。该方法将神经网络与物理方程深度融合,适用于复杂波动问题的建模与仿真,并提供了完整的Matlab实现方案,便于科研人员理解和复现。此外,文档还列举了多个相关科研方向和技术服务内容,涵盖智能优化算法、机器学习、信号处理、电力系统等多个领域,突出其在科研仿真中的广泛应用价值。; 适合人群:具备一定数学建模基础和Matlab编程能力的研究生、科研人员及工程技术人员,尤其适合从事计算物理、声学仿真、偏微分方程数值解等相关领域的研究人员; 使用场景及目标:①学习并掌握PINN在求解三维声波波动方程中的应用原理与实现方式;②拓展至其他物理系统的建模与仿真,如电磁场、热传导、流体力学等问题;③为科研项目提供可复用的代码框架和技术支持参考; 阅读建议:建议读者结合文中提供的网盘资源下载完整代码,按照目录顺序逐步学习,重点关注PINN网络结构设计、损失函数构建及物理边界条件的嵌入方法,同时可借鉴其他案例提升综合仿真能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值