java 反射(Reflection)
看了很多关于java 反射的文章,自己把所看到的总结一下。对自己,对他人或多或少有帮助吧。
Java Reflection是什么?
首先来看看官方文档Oracle里面对Reflection的描述:
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
简单的讲:
- 反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们。
再简单一点的讲:
- 我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。
举个例子:
Java是面向对象语言,我们可以把老虎,狮子等具有相同性质的动物归类(抽象)为猫科动物,他们具有牙齿,胡须等一些属性。同时具有吃肉()的动作。
同样的道理,我们所接触到的类Class,也可以把他们抽象出来,有类名,成员变量,方法等。
那么既然能够把类看做是对象,那么java就可以对其进行处理。
Java反射(Reflection)框架主要提供以下功能:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
- 在运行时调用任意一个对象的方法
Java反射(Reflection)的主要用途
- 工厂模式:Factory类中用反射的话,添加了一个新的类之后,就不需要再修改工厂类Factory了
- 数据库JDBC中通过Class.forName(Driver).来获得数据库连接驱动
- 分析类文件:毕竟能得到类中的方法等等
- 访问一些不能访问的变量或属性:破解别人代码
Java反射(Reflection)的基本运用
获取Class有一下三种方法:
1. 使用Class类的forName静态方法
//在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),
//这通过java.lang.Class类的静态方法forName(String className)实现。
//例如:
try{
//加载MySql的驱动类
Class.forName("com.mysql.jdbc.Driver") ;
}catch(ClassNotFoundException e){
//System.out.println("找不到驱动程序类 ,加载驱动失败!");
e.printStackTrace() ;
}
//成功加载后,会将Driver类的实例注册到DriverManager类中。
2. 直接获取某一个对象的class
Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;
3. 调用某个对象的getClass()方法
public class Test{
public static void main(String[] args) {
Demo demo=new Demo();
System.out.println(demo.getClass().getName());
}
}
下面是一个完整的Demo展示Java Reflection的操作:
package com.b510.hongten.test.reflex; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; public class ReflectionDemo {
/**
* 为了看清楚Java反射部分代码,所有异常我都最后抛出来给虚拟机处理!
*
* @param args
* @throws ClassNotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws NoSuchFieldException
* @throws SecurityException
* @throws NoSuchMethodException
*/
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchFieldException, NoSuchMethodException {
// Demo1. 通过Java反射机制得到类的包名和类名
Demo1();
System.out.println("==============================================="); // Demo2. 验证所有的类都是Class类的实例对象
Demo2();
System.out.println("==============================================="); // Demo3. 通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在],无参构造
Demo3();
System.out.println("==============================================="); // Demo4: 通过Java反射机制得到一个类的构造函数,并实现构造带参实例对象
Demo4();
System.out.println("==============================================="); // Demo5: 通过Java反射机制操作成员变量, set 和 get
Demo5();
System.out.println("==============================================="); // Demo6: 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等
Demo6();
System.out.println("==============================================="); // Demo7: 通过Java反射机制调用类中方法
Demo7();
System.out.println("==============================================="); // Demo8: 通过Java反射机制获得类加载器
Demo8();
System.out.println("==============================================="); } /**
* Demo1: 通过Java反射机制得到类的包名和类名
*/
public static void Demo1() {
Person person = new Person();
System.out.println("Demo1: 包名: " + person.getClass().getPackage().getName() + "," + "完整类名: " + person.getClass().getName()); /**
运行结果:
Demo1: 包名: com.b510.hongten.test.reflex,完整类名: com.b510.hongten.test.reflex.Person
*/
} /**
* Demo2: 验证所有的类都是Class类的实例对象
*
* @throws ClassNotFoundException
*/
public static void Demo2() throws ClassNotFoundException {
// 定义两个类型都未知的Class , 设置初值为null, 看看如何给它们赋值成Person类
Class<?> class1 = null;
Class<?> class2 = null; // 写法1, 可能抛出 ClassNotFoundException [多用这个写法]
class1 = Class.forName("com.b510.hongten.test.reflex.Person");
System.out.println("Demo2:(写法1) 包名: " + class1.getPackage().getName() + "," + "完整类名: " + class1.getName()); /**
运行结果:
Demo2:(写法1) 包名: com.b510.hongten.test.reflex,完整类名: com.b510.hongten.test.reflex.Person
*/ // 写法2
class2 = Person.class;
System.out.println("Demo2:(写法2) 包名: " + class2.getPackage().getName() + "," + "完整类名: " + class2.getName()); /**
运行结果:
Demo2:(写法2) 包名: com.b510.hongten.test.reflex,完整类名: com.b510.hongten.test.reflex.Person
*/
} /**
* Demo3: 通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在]
*
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static void Demo3() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> class1 = null;
class1 = Class.forName("com.b510.hongten.test.reflex.Person");
// 由于这里不能带参数,所以你要实例化的这个类Person,一定要有无参构造函数哈~
Person person = (Person) class1.newInstance();
person.setAge(20);
person.setName("Hongten");
System.out.println("Demo3: " + person.getName() + " : " + person.getAge()); /**
运行结果:
Demo3: Hongten : 20
*/
} /**
* Demo4: 通过Java反射机制得到一个类的构造函数,并实现创建带参实例对象
*
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IllegalArgumentException
*/
public static void Demo4() throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<?> class1 = null;
Person person1 = null;
Person person2 = null; class1 = Class.forName("com.b510.hongten.test.reflex.Person");
// 得到一系列构造函数集合
Constructor<?>[] constructors = class1.getConstructors(); person1 = (Person) constructors[0].newInstance();
person1.setAge(30);
person1.setName("Hongten"); person2 = (Person) constructors[1].newInstance(20, "Hongten"); System.out.println("Demo4: " + person1.getName() + " : " + person1.getAge() + " , " + person2.getName() + " : " + person2.getAge()); /**
运行结果:
Demo4: Hongten : 30 , Hongten : 20
*/
} /**
* Demo5: 通过Java反射机制操作成员变量, set 和 get
*
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws NoSuchFieldException
* @throws SecurityException
* @throws InstantiationException
* @throws ClassNotFoundException
*/
public static void Demo5() throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException, InstantiationException, ClassNotFoundException {
Class<?> class1 = null;
class1 = Class.forName("com.b510.hongten.test.reflex.Person");
Object obj = class1.newInstance(); Field personNameField = class1.getDeclaredField("name");
personNameField.setAccessible(true);
personNameField.set(obj, "HONGTEN"); System.out.println("Demo5: 修改属性之后得到属性变量的值:" + personNameField.get(obj)); /**
运行结果:
Demo5: 修改属性之后得到属性变量的值:HONGTEN
*/
} /**
* Demo6: 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等
*
* @throws ClassNotFoundException
*/
public static void Demo6() throws ClassNotFoundException {
Class<?> class1 = null;
class1 = Class.forName("com.b510.hongten.test.reflex.SuperMan"); // 取得父类名称
Class<?> superClass = class1.getSuperclass();
System.out.println("Demo6: SuperMan类的父类名: " + superClass.getName()); /**
运行结果:
Demo6: SuperMan类的父类名: com.b510.hongten.test.reflex.Person
*/ System.out.println("==============================================="); Field[] fields = class1.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println("类中的成员: " + fields[i]);
}
/**
运行结果:
类中的成员: private boolean com.b510.hongten.test.reflex.SuperMan.BlueBriefs
*/ System.out.println("==============================================="); // 取得类方法
Method[] methods = class1.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println("Demo6,取得SuperMan类的方法:");
System.out.println("函数名:" + methods[i].getName());
System.out.println("函数返回类型:" + methods[i].getReturnType());
System.out.println("函数访问修饰符:" + Modifier.toString(methods[i].getModifiers()));
System.out.println("函数代码写法: " + methods[i]);
} /**
运行结果:
Demo6,取得SuperMan类的方法:
函数名:isBlueBriefs
函数返回类型:boolean
函数访问修饰符:public
函数代码写法: public boolean com.b510.hongten.test.reflex.SuperMan.isBlueBriefs()
Demo6,取得SuperMan类的方法:
函数名:setBlueBriefs
函数返回类型:void
函数访问修饰符:public
函数代码写法: public void com.b510.hongten.test.reflex.SuperMan.setBlueBriefs(boolean)
Demo6,取得SuperMan类的方法:
函数名:fly
函数返回类型:void
函数访问修饰符:public
函数代码写法: public void com.b510.hongten.test.reflex.SuperMan.fly()
Demo6,取得SuperMan类的方法:
函数名:walk
函数返回类型:void
函数访问修饰符:public
函数代码写法: public void com.b510.hongten.test.reflex.SuperMan.walk(int)
*/ System.out.println("==============================================="); // 取得类实现的接口,因为接口类也属于Class,所以得到接口中的方法也是一样的方法得到哈
Class<?> interfaces[] = class1.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
System.out.println("实现的接口类名: " + interfaces[i].getName());
} /**
运行结果:
实现的接口类名: com.b510.hongten.test.reflex.ActionInterface
*/ } /**
* Demo7: 通过Java反射机制调用类方法
*
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InstantiationException
*/
public static void Demo7() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> class1 = null;
class1 = Class.forName("com.b510.hongten.test.reflex.SuperMan"); System.out.println("Demo7: \n调用无参方法fly()");
Method method = class1.getMethod("fly");
method.invoke(class1.newInstance()); System.out.println("调用有参方法walk(int m)");
method = class1.getMethod("walk", int.class);
method.invoke(class1.newInstance(), 100); /**
运行结果:
Demo7:
调用无参方法fly()
fly method....
调用有参方法walk(int m)
fly in 100 m
*/ } /**
* Demo8: 通过Java反射机制得到类加载器信息
*
* 在java中有三种类类加载器。[这段资料网上截取]
*
* 1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
*
* 2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
*
* 3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
*
* @throws ClassNotFoundException
*/
public static void Demo8() throws ClassNotFoundException {
Class<?> class1 = null;
class1 = Class.forName("com.b510.hongten.test.reflex.SuperMan");
String nameString = class1.getClassLoader().getClass().getName(); System.out.println("Demo8: 类加载器类名: " + nameString); /**
运行结果:
Demo8: 类加载器类名: sun.misc.Launcher$AppClassLoader
*/
} } class Person {
private int age;
private String name; public Person() { } public Person(int age, String name) {
this.age = age;
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
} class SuperMan extends Person implements ActionInterface {
private boolean BlueBriefs; public void fly() {
System.out.println("fly method....");
} public boolean isBlueBriefs() {
return BlueBriefs;
} public void setBlueBriefs(boolean blueBriefs) {
BlueBriefs = blueBriefs;
} public void walk(int m) {
System.out.println("fly in " + m + " m");
}
} interface ActionInterface {
public void walk(int m);
}
说说工厂模式和Java 反射(Reflection)机制
如果在工厂模式下面,我们不使用Java 反射(Reflection)机制,会是什么样子呢?
package com.b510.hongten.test.reflex; /**
* @author hongten
* @created Apr 18, 2018
*/
public class FactoryTest { public static void main(String[] args) {
Cats cats = FactoryTest.getInstance("Tiger");
cats.eatMeat(); /*
* The Result : The tiger eat meat.
*/
} public static Cats getInstance(String name) {
Cats cats = null;
if ("Tiger".equals(name)) {
cats = new Tiger();
}
if ("Lion".equals(name)) {
cats = new Lion();
}
return cats;
}
} interface Cats {
public abstract void eatMeat();
} class Tiger implements Cats { public void eatMeat() {
System.out.println("The tiger eat meat.");
} } class Lion implements Cats { public void eatMeat() {
System.out.println("The lion eat meat.");
} }
我们会发现:
当我们在添加一个子类(Puma-美洲狮)的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。
我们对程序进行修改,加入反射机制。
package com.b510.hongten.test.reflex; /**
* @author hongten
* @created Apr 18, 2018
*/
public class FactoryTest { public static void main(String[] args) {
//Cats cats = FactoryTest.getInstance("com.b510.hongten.test.reflex.Lion");
Cats cats = FactoryTest.getInstance("com.b510.hongten.test.reflex.Tiger");
cats.eatMeat(); /*
* The Result : The tiger eat meat.
*/
} public static Cats getInstance(String name) {
Cats cats = null;
try {
try {
//use Class.forName() with java reflection
cats = (Cats) Class.forName(name).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return cats;
}
} interface Cats {
public abstract void eatMeat();
} class Tiger implements Cats { public void eatMeat() {
System.out.println("The tiger eat meat.");
} } class Lion implements Cats { public void eatMeat() {
System.out.println("The lion eat meat.");
} }
我们会发现利用了Java Reflection以后,现在就算我们添加任意多个子类的时候,工厂类就不需要修改。我们只需要传递工厂类的实现类的名称即可。
然而,在这样的情况下面,如果我们需要运行Lion实例的时候,我们还需要去修改java代码。
Cats cats = FactoryTest.getInstance("com.b510.hongten.test.reflex.Lion");
上面的代码虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。
能不能不需要修改java代码,同样可以完成相同的操作呢?是可以的。
我们可以让工厂模式结合属性文件(如:*.properties, *.xml文件)
属性文件:/reflex/cats.properties
lion=com.b510.hongten.test.reflex.Lion
tiger=com.b510.hongten.test.reflex.Tiger
测试文件:/reflex/FactoryTest.java
package com.b510.hongten.test.reflex; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties; /**
* @author hongten
* @created Apr 18, 2018
*/
public class FactoryTest { public static void main(String[] args) {
Cats cats;
try {
cats = FactoryTest.getInstance(getPro().getProperty("tiger"));
if (cats != null) {
cats.eatMeat();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} /*
* The Result : The tiger eat meat.
*/
} public static Cats getInstance(String name) {
Cats cats = null;
try {
try {
// use Class.forName() with java reflection
cats = (Cats) Class.forName(name).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return cats;
} public static Properties getPro() throws FileNotFoundException, IOException {
Properties pro = new Properties();
File f = new File("cats.properties");
if (f.exists()) {
pro.load(new FileInputStream(f));
} else {
pro.setProperty("lion", "com.b510.hongten.test.reflex.Lion");
pro.setProperty("tiger", "com.b510.hongten.test.reflex.Tiger");
pro.store(new FileOutputStream(f), "FRUIT CLASS");
}
return pro;
}
} interface Cats {
public abstract void eatMeat();
} class Tiger implements Cats { public void eatMeat() {
System.out.println("The tiger eat meat.");
} } class Lion implements Cats { public void eatMeat() {
System.out.println("The lion eat meat.");
} }
作为开发者,我们只需要配置cats.properties属性文件即可。极大的提高了程序的扩展性能。
Java反射(Reflection)的一些注意事项
- 由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。
- 另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
========================================================
More reading,and english is important.
I'm Hongten
大哥哥大姐姐,觉得有用打赏点哦!多多少少没关系,一分也是对我的支持和鼓励。谢谢。
Hongten博客排名在100名以内。粉丝过千。
Hongten出品,必是精品。
E | hongtenzone@foxmail.com B | http://www.cnblogs.com/hongten
========================================================
java 反射(Reflection)的更多相关文章
- 公共技术点( Java 反射 Reflection)
转载路径:http://p.codekk.com/blogs/detail/5596953ed6459ae7934997c5 本文为 Android 开源项目源码解析 公共技术点中的 Java 反射 ...
- 公共技术点之 Java 反射 Reflection
本文摘录地址: http://codekk.com/open-source-project-analysis/detail/Android/Mr.Simple/%E5%85%AC%E5%85%B1%E ...
- Java反射reflection与注解annotation的应用(自动测试机)
一.关于自动测试机 1.什么是自动测试机? 对类中的指定方法进行批量测试的工具 2.自动测试机有什么用? a.避免了冗长的测试代码 当类中的成员方法很多时,对应的测试代码可能会很长,使用测试能够让测试 ...
- Java反射机制(Reflection)
Java反射机制(Reflection) 一.反射机制是什么 Java反射机制是程序在运行过程中,对于任意一个类都能够知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法和属性,这种 ...
- Java - 反射机制(Reflection)
Java - 反射机制(Reflection) > Reflection 是被视为 动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的 ...
- Java反射(Reflection)
基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于J ...
- java学习--Reflection反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...
- Java之reflection(反射机制)——通过反射操作泛型,注解
一.反射操作泛型(Generic) Java采用泛型擦除机制来引入泛型.Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦.但是编译一旦完成,所有和泛型有关的类型 ...
- 4 Java学习之 反射Reflection
1. 反射概念 反射机制就是:动态地获取类的一切信息,并利用这些信息做一些你想做的事情. java反射机制能够知道类名而不实例化对象的状态下,获得对象的属性或调用方法. JAVA反射机制是在运行状态 ...
随机推荐
- ASCII十进制转字符串的方法
/// <summary> /// ASCII转字符串 /// </summary> /// <param name="asciiCode">A ...
- Java基础学习笔记二十五 MySQL
MySQL 在dos中操作mysql 连接mysql命令: mysql -uroot -p密码 ,连接OK,会出现mysql> 对数据库的操作 创建一个库 create database 库名 ...
- springboot elasticsearch 集成注意事项
文章来源: http://www.cnblogs.com/guozp/p/8686904.html 一 elasticsearch基础 这里假设各位已经简单了解过elasticsearch,并不对es ...
- java冒泡排序和快速排序
本ID技术干货公众号"java工会",欢迎关注指正. 一.冒泡排序 1.算法介绍 设排序表长为n,从后向前或者从前向后两两比较相邻元素的值,如果两者的相对次序不对(A[i-1] & ...
- [福大软工] W班 软件产品案例分析
作业要求 https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/1300 评分细则 第一部分 调研,评测 (3 ...
- Alpha冲刺Day5
Alpha冲刺Day5 一:站立式会议 今日安排: 首先由于经过黄腾飞短暂的测试,发现导入导出仍然有一些问题,今天需要进行完善 由黄腾飞负责企业自查风险管理子模块,要求为单元进行风险点的管理 由张梨贤 ...
- Linux进程间通信--信号量
信号量绝对不同于信号,一定要分清,关于信号,上一篇博客中已经说过,如有疑问,请移驾! 信号量 一.是什么 信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件 ...
- 201621123031 《Java程序设计》第10周学习总结
作业10-异常 1.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 1.捕捉异常 Java中的异常捕获结构由try.catch和finally三个部分组成.其中try语句 ...
- Mybatis学习日志
在Mybatis深入学习的一周中,总感觉跟着师傅的视屏讲解什么都能懂,但实际自己操作的时候才发现自己一脸懵逼,不知道从何入手.但还好自己做了点笔记.在此记录一下自己浅度学习Mybatis遇到几个小问题 ...
- 爬虫模块BeautifulSoup
中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html# 1.1 安装BeautifulSoup模块 ...