java的反射机制(重要)
1,反射的概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
java程序的加载过程:源文件 .java --- 经过编译(javac.exe)--- 得到一个或多个 .class文件 --- 再运行(java.exe) --- 就会对需要用到的类进行加载(通过JVM的类加载器)--- 把 .class 加载到内存后 JVM会自动根据.class给java.lang.Class实例化一个Class对象,该对象和.class一一对应(即一个类就一个Class对象)--- 然后再根据 Class对象创建该类的对象。

因此:java.lang.Class就是反射的源头。
1)java.lang.Class的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)
2)java.lang.Class没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
2,反射的优缺点
静态编译:在编译时确定类型,绑定对象,即通过。
        动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行反编译。
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且让它满足我们的要求。这类操作总是慢于直接执行相同的操作。
3,反射的用法
3.1,获取java.lang.Class对象的三种方法
- 通过运行时类的对象,调用其getClass()方法
 - 调用运行时类的.class属性
 - 调用Class的静态方法forName(String className)。此方法报ClassNotFoundException
 
public class Student {
}
public class Reflect {
    public static void main(String[] args) {
        // (1)通过运行时类的对象,调用其getClass()方法
        Student stu1 = new Student();// 这一new 产生一个Student对象,一个Class对象。
        Class stuClass = stu1.getClass();// 获取Class对象
        System.out.println(stuClass.getName());
        // (2)调用运行时类的.class属性
        Class stuClass2 = Student.class;
        System.out.println(stuClass == stuClass2);// 判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
        // (3)调用Class的静态方法forName(String className)。此方法报ClassNotFoundException
        try {
            Class stuClass3 = Class.forName("com.jp.Student");// 注意此字符串必须是真实路径
            System.out.println(stuClass3 == stuClass2);// 判断三种方式是否获取的是同一个Class对象
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
说明:
1)在运行期间,一个类,只有一个Class对象产生。上面三种方法都是去内存获取这个Student这个类(即java.lang.Class的一个实例)
2)如果Student类写错了,第一二种编译时就报错(编译器会对java源码进行词法分析、语法分析、语义分析等步骤才编译为字节码); 第三种编译时会通过,但是运行时会报错;这就说明了第三种是动态的编译。
为了说明 2)来做个试验
第一步:把Student类改成错的
public class Student {
    int a = gg;//很明显错的
}
第二步:分别单独运行Reflect类里的三种获取Class实例对象的方法
运行前涉及到的两个类

单独运行第一种方法的结果:编译错误。说明也对Student.java进行了编译,如果Student类没有错误也会生成.class(单独运行第二种方法和第一种结果一样)


单独运行第三种方法的结果:编译成功,说明编译时并不会去编译Class.forName()里的类


3.2,有了java.lang.Class实例(即除Class类的其他类的运行时类)后可以做什么
3.2.1 应用一:可以创建对应的运行时类的对象
//方法一:Class的newInstanc()方法
@Test
public void test1() throws Exception{
Class clazz = Class.forName("com.jp.Animal");//拿到Class实例(即运行时类)
Object obj = clazz.newInstance();
Animal a = (Animal)obj;
System.out.println(a);
}
//方法二:Class的getDeclaredConstructor()方法,拿到指定的构造器,再用构造器的newInstance()方法
@Test
public void test2() throws Exception{
Class clazz = Animal.class;//拿到Class实例(即运行时类)
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);//这里和上面说的一致,对象都有Class实例,包括基本数据类型、字符串等等
cons.setAccessible(true);
Animal a = (Animal)cons.newInstance("Tom",10);
System.out.println(a);
}
3.2.2 应用二:调用对应的运行时类中指定的结构(某个指定的属性、方法、构造器等)
1)获取构造方法
批量的方法:
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
获取单个的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
2)获取成员变量
批量的
Field[] getFields():获取所有的"公有字段"
Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
获取单个的
public Field getField(String fieldName):获取某个"公有的"字段;
public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
3)获取方法
批量的:
- 参数:
 - name : 方法名;
 - Class ... : 形参的Class类型对象
 
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
- 参数说明:
 - obj : 要调用方法的对象;
 - args:调用方式时所传递的实参
 
Method m = stuClass.getMethod("show1", String.class);//拿到运行时类Method的实例对象
System.out.println(m);
//实例化一个Student对象
Object obj = stuClass.getConstructor().newInstance();
Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(反射得到),一个是实参(m方法需要的参数)
如果获得的Method的实例对象 是 静态方法的,则运行该静态方法时,.invoke(null,20),对象类型可以写null。
4,典型的应用
1)代理设计模式中的动态代理
动态代理:在程序运行时,根据被代理类及其实现的接口,动态的创建一个代理类。当调用代理类的实现的抽象方法时,就发起对被代理类同样 方法的调用。
2)通过反射运行配置文件内容(这就是IOC容器的基本原理)
Student类:
public class Student {
    public static void show(){
        System.out.println("is show()");
    }
}
配置文件以txt文件为例子(pro.txt):
className = Student
methodName = show
测试类(应用程序):
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties; /*
* 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改
* 我们只需要将新类发送给客户端,并修改配置文件即可
*/
public class Demo {
public static void main(String[] args) throws Exception {
// 通过反射获取Class对象
Class stuClass = Class.forName(getValue("className"));// "Student"
// 2获取show()方法
Method m = stuClass.getMethod(getValue("methodName"));// show
// 3.调用show()方法
m.invoke(stuClass.getConstructor().newInstance());
}
// 此方法接收一个key,在配置文件中获取相应的value
public static String getValue(String key) throws IOException {
Properties pro = new Properties();// 获取配置文件的对象
FileReader in = new FileReader("pro.txt");// 获取输入流
pro.load(in);// 将流加载到配置文件对象中
in.close();
return pro.getProperty(key);// 返回根据key获取的value值
}
}
控制台输出

需求:
当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动
要替换的student2类:

配置文件更改为:

3)通过反射越过泛型检查
泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的
package fanXing; import java.lang.reflect.Method;
import java.util.ArrayList; /*
* 通过反射越过泛型检查
*
* 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
*/
public class FanXing {
public static void main(String[] args) throws Exception {
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb"); // strList.add(100);//如果直接在这添加 100 的话 编译就报错了。
// 获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); // 得到 strList 对象的字节码 对象
// 获取add()方法
Method m = listClass.getMethod("add", Object.class);
// 调用add()方法
m.invoke(strList, 100); // 遍历集合
for (Object obj : strList) {
System.out.println(obj);
}
}
}

参考:
https://blog.csdn.net/sinat_38259539/article/details/71799078
https://blog.csdn.net/fuzhongmin05/article/details/61614873
java的反射机制(重要)的更多相关文章
- Java 类反射机制分析
		
Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...
 - java的反射机制
		
一.java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...
 - Java中反射机制和Class.forName、实例对象.class(属性)、实例对象getClass()的区别
		
一.Java的反射机制 每个Java程序执行前都必须经过编译.加载.连接.和初始化这几个阶段,后三个阶段如下图: 其中
 - java笔记--反射机制之基础总结与详解
		
一.反射之实例化Class类的5种方式: java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型). 对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象 ...
 - JAVA的反射机制学习笔记(二)
		
上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...
 - java笔录---反射机制(1)
		
引言 为了方便记忆java的反射机制,在这里仔细的总结了一下.主要是怕以后忘记了,这样也方便回忆.因为最近利用空余时间深入的了解spring和Mybatis框架, 像spring中核心模块IO ...
 - Java高新技术 反射机制
		
 Java高新技术 反射机制 知识概要: (1)反射的基石 (2)反射 (3)Constructor类 (4)Field类 (5)Method类 (6)用反射方 ...
 - java的反射机制浅谈(转)
		
原文链接:java的反射机制浅谈 一.java的反射机制浅谈 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...
 - 【转】Java利用反射机制访问私有化构造器
		
Java利用反射机制访问私有化构造器 博客分类: java 我们都知道,当一个类的构造方法被设为私有的时候(private),在其他类中是无法用new来实例化一个对象的. 但是有一种方法可以把带有 ...
 - 【转】java原理—反射机制
		
一.什么是反射:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言 ...
 
随机推荐
- android优化 清除无效代码 UCDetector
			
android下优化 清除无效 未被使用的 代码 UCDetector 官方下载地址:http://www.ucdetector.org/index.html UCDetector 是 eclips ...
 - UML中的序列图(时序图)
			
序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸. 横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色用一条虚线表示,当对象的过程处于激活状态时.生命 ...
 - sql不显示反复列
			
在报表里,基本上都能够把反复的资料不显示,在SQL里怎么才干做到例如以下情况呢? a 10 a 20 b 30 b 40 b 50 显示为: a 10 20 b 30 40 50 SQL 例如以下: ...
 - codecombat之边远地区的森林1-11关及地牢38关代码分享
			
codecombat中国游戏网址:http://www.codecombat.cn/ 全部代码为javascript代码分享 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...
 - Unable to access the IIS metabase
			
https://stackoverflow.com/questions/12859891/error-unable-to-access-the-iis-metabase 解决方法1 On Window ...
 - Oracle动态性能表-V$SESSION_WAIT,V$SESSION_EVENT
			
(1)-V$SESSION_WAIT 这是一个寻找性能瓶颈的关键视图.它提供了任何情况下session在数据库中当前正在等待什么(如果session当前什么也没在做,则显示它最后的等待事件).当系统存 ...
 - 捣鼓TinyMCE 粘贴图片并上传+Django后台
			
前面一篇写了上传到Flask后台,但是我不熟悉Flask,原先想学习一下,据说是轻量级. 但是我发现,学习会浪费我大量的时间,因为我并不是以这个为生的,我的目标只是要完成功能,让我自己能尽早使用起来, ...
 - TLP电源管理
			
笔记本电脑电池坏了, 换了块电池, 顺手装了一下这个电源管理软件. https://linrunner.de/en/tlp/docs/tlp-linux-advanced-power-manage ...
 - 项目中解决实际问题的代码片段-javascript方法,Vue方法(长期更新)
			
总结项目用到的一些处理方法,用来解决数据处理的一些实际问题,所有方法都可以放在一个公共工具方法里面,实现不限ES5,ES6还有些Vue处理的方法. 都是项目中来的,有代码跟图片展示,长期更新. 1.获 ...
 - Spring《三》ref 引用其他bean
			
local属性 1.被引用id必须在同一个xml中. 2.被引用id必须使用id命名. 优点提前检查所使用的bean id是否正确. Bean属性 1.Bean指定的id可以在不同的xml中. 2.B ...