反射怎么理解,菲涅尔反射原理
刚开始学反射的时候,我是一脸懵逼的,这玩意真的是“抽象的妈妈给抽象开门-抽象到家了。”
为什么创建对象要先获取 Class 对象?这不多此一举吗?我直接 new 一下不是更简单吗?
什么是程序运行时获取类的属性和方法?平时都是程序编译出错了再修改代码,我为什么要考虑程序运行时的状态?
我平时开发也用不到,学这玩意有啥用?
后来学了注解、spring、SpringMVC 等技术之后,发现反射无处不在。
2.JVM 加载类
1. 啥是反射
1.初识反射
刚开始学反射的时候,我是一脸懵逼的,这玩意真的是“抽象的妈妈给抽象开门-抽象到家了。”
为什么创建对象要先获取 Class 对象?这不多此一举吗?我直接 new 一下不是更简单吗?
什么是程序运行时获取类的属性和方法?平时都是程序编译出错了再修改代码,我为什么要考虑程序运行时的状态?
我平时开发也用不到,学这玩意有啥用?
后来学了注解、spring、SpringMVC 等技术之后,发现反射无处不在。
2.JVM 加载类
我们写的 java 程序要放到 JVM 中运行,所以要学习反射,首先需要了解 JVM 加载类的过程。
1.我们写的 .java 文件叫做源代码。
2.我们在一个类中写了一个 main 方法,然后点击 IDEA 的 run 按钮,JVM 运行时会触发 jdk 的 javac 指令将源代码编译成 .class 文件,这个文件又叫做字节码文件。
3.JVM 的类加载器(你可以理解成一个工具)通过一个类的全限定名来获取该类的二进制字节流,然后将该 class 文件加载到 JVM 的方法区中。
4.类加载器加载一个 .class 文件到方法区的同时会在堆中生成一个唯一的 Class 对象,这个 Class 包含这个类的成员变量、构造方法以及成员方法。
5.这个 Class 对象会创建与该类对应的对象实例。
所以表面上你 new 了一个对象,实际上当 JVM 运行程序的时候,真正帮你创建对象的是该类的 Class 对象。
也就是说反射其实就是 JVM 在运行程序的时候将你创建的所有类都封装成唯一一个 Class 对象。这个 Class 对象包含属性、构造方法和成员方法。你拿到了 Class 对象,也就能获取这三个东西。
你拿到了反射之后(Class)的属性,就能获取对象的属性名、属性类别、属性值,也能给属性设置值。
你拿到了反射之后(Class)的构造方法,就能创建对象。
你拿到了反射之后(Class)的成员方法,就能执行该方法。
3.反射的概念
JAVA 反射机制是在程序运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 java 语言的反射机制。
知道了 JVM 加载类的过程,相信你应该更加深入的了解了反射的概念。
反射:JVM 运行程序 --> .java 文件 --> .class 文件 --> Class 对象 --> 创建对象实例并操作该实例的属性和方法
接下来我就讲一下反射中的相关类以及常用方法。
2. Class 对象获取 Class 对象先建一个 User 类:
public class User { private String name = "知否君"; public String sex = "男"; public User() { } public User(String name, String sex) { this.name = name; this.sex = sex; } public void eat(){ System.out.println("人要吃饭!"); } private void run(){ System.out.println("人要跑步!"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; }}复制代码获取 Class 对象的三种方式:
1. Class.forName("全类名")
全类名:包名 类名
Class userClass = Class.forName("com.xxl.model.User");复制代码2. 类名.class
Class userClass = User.class;复制代码3. 对象.getClass()
User user = new User();Class userClass = user.getClass();复制代码尽管有三种方式获取 Class 对象,但是我们一般采用上述第一种方式。
拿到 Class 对象之后,我们就可以操作与它相关的方法了。
3. 获取类名1.获取完整类名:包名 类名
getName()
Class userClass = Class.forName("com.xxl.model.User");String name = userClass.getName();System.out.println(name);复制代码打印结果:
2.获取简单类名:不包括包名
getSimpleName()
Class userClass = Class.forName("com.xxl.model.User");String simpleName = userClass.getSimpleName();System.out.println(simpleName);复制代码打印结果:
4. 属性4.1 获取属性
1.获取所有公有属性:public 修饰
getFields()
Class userClass = Class.forName("com.xxl.model.User");Field[] fields = userClass.getFields();for (Field field : fields) { System.out.println(field);}复制代码打印结果:
2.获取单个公有属性
getField("属性名")
Class userClass = Class.forName("com.xxl.model.User");Field field = userClass.getField("sex");System.out.println(field);复制代码打印结果:
3.获取所有属性:公有 私有
getDeclaredFields()
Class userClass = Class.forName("com.xxl.model.User");Field[] fields = userClass.getDeclaredFields();for (Field field : fields) { System.out.println(field);}复制代码打印结果:
4.获取单个属性:公有或者私有
getDeclaredField("属性名")
Class userClass = Class.forName("com.xxl.model.User");Field nameField = userClass.getDeclaredField("name");Field sexField = userClass.getDeclaredField("sex");System.out.println(nameField);System.out.println(sexField);复制代码打印结果:
4.2 操作属性
1.获取属性名称
getName()
Class userClass = Class.forName("com.xxl.model.User");Field nameField = userClass.getDeclaredField("name");System.out.println(nameField.getName());复制代码打印结果:
2.获取属性类型
getType()
Class userClass = Class.forName("com.xxl.model.User");Field nameField = userClass.getDeclaredField("name");System.out.println(nameField.getType());复制代码打印结果:
3.获取属性值
get(object)
Class userClass = Class.forName("com.xxl.model.User");Field nameField = userClass.getDeclaredField("sex");User user = new User();System.out.println(nameField.get(user));复制代码打印结果:
注: 通过反射不能直接获取私有属性的值,但是可以通过修改访问入口来获取私有属性的值。
设置允许访问私有属性:
field.setAccessible(true);复制代码例如:
Class userClass = Class.forName("com.xxl.model.User");Field nameField = userClass.getDeclaredField("name");nameField.setAccessible(true);User user = new User();System.out.println(nameField.get(user));复制代码打印方法:
4.设置属性值
set(object,"属性值")
Class userClass = Class.forName("com.xxl.model.User");Field nameField = userClass.getDeclaredField("name");nameField.setAccessible(true);User user = new User();nameField.set(user,"张无忌");System.out.println(nameField.get(user));复制代码打印结果:
5. 构造方法
1.获取所有公有构造方法
getConstructors()
Class userClass = Class.forName("com.xxl.model.User");Constructor[] constructors = userClass.getConstructors();for (Constructor constructor : constructors) { System.out.println(constructor);}复制代码打印结果:
2.获取与参数类型匹配的构造方法
getConstructor(参数类型)
Class userClass = Class.forName("com.xxl.model.User");Constructor constructor = userClass.getConstructor(String.class, String.class);System.out.println(constructor);复制代码打印结果:
6. 成员方法6.1获取成员方法
1.获取所有公共方法
getMethods()
Class userClass = Class.forName("com.xxl.model.User");Method[] methods = userClass.getMethods();for (Method method : methods) { System.out.println(method);}复制代码打印结果:
我们发现,打印结果除了自定义的公共方法,还有继承自 Object 类的公共方法。
2.获取某个公共方法
getMethod("方法名", 参数类型)
Class userClass = Class.forName("com.xxl.model.User");Method method = userClass.getMethod("setName", String.class);System.out.println(method);复制代码打印结果:
3.获取所有方法:公有 私有
getDeclaredMethods()
Class userClass = Class.forName("com.xxl.model.User");Method[] declaredMethods = userClass.getDeclaredMethods();for (Method method : declaredMethods) { System.out.println(method);}复制代码打印结果:
4.获取某个方法:公有或者私有
getDeclaredMethod("方法名", 参数类型)
Class userClass = Class.forName("com.xxl.model.User");Method method = userClass.getDeclaredMethod("run");System.out.println(method);复制代码打印结果:
6.2 执行成员方法
invoke(object,"方法参数")
Class userClass = Class.forName("com.xxl.model.User");Method method = userClass.getDeclaredMethod("eat");User user = new User();method.invoke(user);复制代码打印结果:
注: 通过反射不能直接执行私有成员方法,但是可以设置允许访问。
设置允许执行私有方法:
method.setAccessible(true);复制代码7. 注解1.判断类上或者方法上时候包含某个注解
isAnnotationPresent(注解名.class)复制代码例如:
Class userClass = Class.forName("com.xxl.model.User");if(userClass.isAnnotationPresent(Component.class)){ Component annotation = (Component)userClass.getAnnotation(Component.class); String value = annotation.value(); System.out.println(value);};复制代码2.获取注解
getAnnotation(注解名.class)复制代码例如:
Class userClass = Class.forName("com.xxl.model.User");// 获取类上的注解Annotation annotation1 = userClass.getAnnotation(Component.class);Method method = userClass.getMethod("eat");// 获取方法上的某个注解Annotation annotation2 = userClass.getAnnotation(Component.class);复制代码8. 创建类的实例1.通过 Class 实例化对象
Class.newInstance()
Class userClass = Class.forName("com.xxl.model.User");User user = (User)userClass.newInstance();System.out.println("姓名:" user.getName() " 性别:" user.getSex());复制代码打印结果:
2.通过构造方法实例化对象
constructor.newInstance(参数值)
Class userClass = Class.forName("com.xxl.model.User");Constructor constructor = userClass.getConstructor(String.class, String.class);User user = (User)constructor.newInstance("李诗情", "女");System.out.println("姓名:" user.getName() " 性别:" user.getSex());复制代码打印结果:
9. 反射案例
有一天技术总监对张三说:"张三,听说你最近学反射了呀。那你设计一个对象的工厂类给我看看。"
张三心想:"哟,快过年了,领导这是要给我涨工资啊。这次我一定好好表现一次。"
5分钟过后,张三提交了代码:
public class ObjectFactory { public static User getUser() { User user = null; try { Class userClass = Class.forName("com.xxl.model.User"); user = (User) userClass.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return user; } public static UserService getUserService() { UserService userService = null; try { Class userClass = Class.forName("com.xxl.service.impl.UserServiceImpl"); userService = (UserService) userClass.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return userService; }}复制代码技术总监瞄了一眼代码,对张三说:"你这个工厂类存在两个问题。"
1.代码存在大量冗余。如果有一万个类,你是不是要写一万个静态方法?
2.代码耦合度太高。如果这些类存放的包路径发生改变,你再用 forName()获取 Class 对象是不是就会有问题?你还要一个个手动改代码,然后再编译、打包、部署。。你不觉得麻烦吗?
“发散你的思维想一下,能不能只设计一个静态类,通过传参的方式用反射创建对象,传递的参数要降低和工厂类的耦合度。顺便提醒你一下,可以参考一下 JDBC 获取数据库连接参数的方式。”
张三一听:"不愧是总监啊,醍醐灌顶啊!等我 10 分钟。"
10 分钟后,张三再次提交了代码:
object.properties
user=com.xxl.model.UseruserService=com.xxl.service.impl.UserServiceImpl复制代码ObjectFactory
public class ObjectFactory { private static Properties objectProperty = new Properties(); // 静态方法在类初始化时执行,且只执行一次 static{ try { InputStream inputStream = ObjectFactory.class.getResourceAsStream("/object.properties"); objectProperty.load(inputStream); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } public static Object getObject(String key){ Object object = null; try { Class objectClass = Class.forName(objectProperty.getProperty(key)); object = objectClass.newInstance(); } catch (Exception e) { e.printStackTrace(); } return object; }}复制代码测试方法:
@Test void testObject() { User user = (User)ObjectFactory.getObject("user"); UserService userService = (UserService)ObjectFactory.getObject("userService"); System.out.println(user); System.out.println(userService); }复制代码执行结果:
总监看后连连点头,笑着对张三说:“用 properties 文件存放类的全限定名降低了代码的耦合度,通过传参的方式使用反射创建对象又降低了代码的冗余性,这次改的可以。"
"好啦,今晚项目要上线,先吃饭去吧,一会还要改 bug。”
张三:"..........好的总监。"
10. 反射的作用我们或多或少都听说过设计框架的时候会用到反射,例如 Spring 的 IOC 就用到了工厂模式和反射来创建对象,BeanUtils 的底层也是使用反射来拷贝属性。所以反射无处不在。
尽管我们日常开发几乎用不到反射,但是我们必须要搞懂反射的原理,因为它能帮我们理解框架设计的原理。
原文链接:https://juejin.cn/post/7055090668619694094
你对热辐射的反射了解多少?镜面能反射热辐射吗?为什么?
我们在了解热辐射的反射之前,应该先了解一下什么是热辐射,热辐射是什么意思。物体因为自身的温度而具有向外发射能量的本领,这种热传递的方式叫做热辐射。因此,我们可以明确,热辐射只是一种方式,它是用来传递热量的。而热辐射传播时,是以电磁辐射的形式向外发出能量的,也就是说,温度越高,辐射越强,温度和辐射是成正比关系的。
那么镜面可以反射热辐射吗?答案是肯定的。因为我们从定义来看,热辐射是物体由于具有温度而辐射电磁波的现象,那么光是电磁波的一种,我们知道,光可以通过镜面进行反射。那么这样也就是说,电磁波可以进行反射,从而镜面可以反射热辐射。这是我们所确定的。
对于热辐射,它还有一个名字,就是红外线,因此,热敷辐射不仅可以反射,而且它也可以折射。我们生活中所用到的各种夜视仪,以及各种红外成像技术,都证明了这一点。
提到热辐射,往往会有其他的两个名词与它进行混淆,分别是热传导和热对流。热传导是指热量从系统的一部分传到另一个部分,或者热量从一个系统传到另一个系统的现象。也就是说,热传导是一种象。那么热对流是什么呢?热队对流就是液体或气体中较热部分和较冷部分之间。通过来回的交替循环流动,从而使温度达到一个平衡的过程。这是一个过程,也就是说,热对流是动态的。很明显就可以从它们的定义中区分这三个名词。
那么热辐射都有哪些作用呢?热辐射在日常生活中的应用不是很多,因为当温度处于较低的状态时,热辐射不是主要的传递热量的方式。因此热辐射在高温的情况下使用的比较多,比如说在航空航天领域,能会用到光谱仪以及红外热像仪,但是对于热辐射比较常用的两个方面。
热辐射只是我们市场生活中能量的一种形式之一,我们生活中还有许多其他的能量,比如说太阳能,核能,风能,电能,而太阳能,风能,电能是我们日常生活中常用的能量形式。
这是小编关于对热辐射的一个了解,希望对大家有所帮助。
什么是声波的反射、透射和衍射,有什么区别?
1、反射是遇到介质后改变传播方向,就像小球遇到障碍物被反弹一样,放射后的传播方向按光的反射原理进行。2、透射是遇到介质后通过介质继续传播,强度上会有一定衰减。
3、衍射是遇到障碍物后会绕过障碍物继续传播(主要指偏离直线传播方向,绕道了账障碍物的阴影区),此时与障碍物的尺寸有关,障碍物越小,衍射现象越明显。
文章评论