看了很多关于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)框架主要提供以下功能:

  1. 在运行时判断任意一个对象所属的类;
  2. 在运行时构造任意一个类的对象;
  3. 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
  4. 在运行时调用任意一个对象的方法
  • Java反射(Reflection)的主要用途

  1. 工厂模式:Factory类中用反射的话,添加了一个新的类之后,就不需要再修改工厂类Factory了
  2. 数据库JDBC中通过Class.forName(Driver).来获得数据库连接驱动
  3. 分析类文件:毕竟能得到类中的方法等等
  4. 访问一些不能访问的变量或属性:破解别人代码
  • 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)的一些注意事项

  1. 由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。
  2. 另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

========================================================

More reading,and english is important.

I'm Hongten

大哥哥大姐姐,觉得有用打赏点哦!多多少少没关系,一分也是对我的支持和鼓励。谢谢。
Hongten博客排名在100名以内。粉丝过千。
Hongten出品,必是精品。

E | hongtenzone@foxmail.com  B | http://www.cnblogs.com/hongten

========================================================

java 反射(Reflection)的更多相关文章

  1. 公共技术点( Java 反射 Reflection)

    转载路径:http://p.codekk.com/blogs/detail/5596953ed6459ae7934997c5 本文为 Android 开源项目源码解析 公共技术点中的 Java 反射 ...

  2. 公共技术点之 Java 反射 Reflection

    本文摘录地址: http://codekk.com/open-source-project-analysis/detail/Android/Mr.Simple/%E5%85%AC%E5%85%B1%E ...

  3. Java反射reflection与注解annotation的应用(自动测试机)

    一.关于自动测试机 1.什么是自动测试机? 对类中的指定方法进行批量测试的工具 2.自动测试机有什么用? a.避免了冗长的测试代码 当类中的成员方法很多时,对应的测试代码可能会很长,使用测试能够让测试 ...

  4. Java反射机制(Reflection)

    Java反射机制(Reflection) 一.反射机制是什么 Java反射机制是程序在运行过程中,对于任意一个类都能够知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法和属性,这种 ...

  5. Java - 反射机制(Reflection)

    Java - 反射机制(Reflection)     > Reflection 是被视为 动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的       ...

  6. Java反射(Reflection)

    基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于J ...

  7. java学习--Reflection反射机制

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...

  8. Java之reflection(反射机制)——通过反射操作泛型,注解

    一.反射操作泛型(Generic) Java采用泛型擦除机制来引入泛型.Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦.但是编译一旦完成,所有和泛型有关的类型 ...

  9. 4 Java学习之 反射Reflection

    1. 反射概念  反射机制就是:动态地获取类的一切信息,并利用这些信息做一些你想做的事情. java反射机制能够知道类名而不实例化对象的状态下,获得对象的属性或调用方法. JAVA反射机制是在运行状态 ...

随机推荐

  1. java基础--封装

    封 装(面向对象特征之一):是指隐藏对象的属性和实现细节,仅对外提供公共访问方式. 好处:将变化隔离:便于使用:提高重用性:安全性. 封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共 ...

  2. apache学习教程

    5.apache教程 httpd.conf文件分析 ServerRoot "E:/phpwebenv/PHPTutorial/Apache" #apache软件安装的位置 List ...

  3. 用jQuery.delegate()将事件绑定在父元素上面

    1.先看看官方的示例: <html> <head> <script type="text/javascript" src="/jquery/ ...

  4. 关于python词典(Dictionary)的get()用法

    先贴出参考链接:http://www.runoob.com/python/att-dictionary-get.html get()方法语法: dict.get(key, default=None) ...

  5. 1013团队Beta冲刺day5

    项目进展 李明皇 今天解决的进度 服务器端还未完善,所以无法进行联动调试.对页面样式和逻辑进行优化 明天安排 前后端联动调试 林翔 今天解决的进度 完成维护登录态,实现图片上传,微信开发工具上传图片不 ...

  6. C程序设计-----第1次作业

    一. PTA作业.    在完成PTA作业的时候我没有认真读题.每次都是提交完整代码 6-1(1) #include <stdio.h> //P++等价于(p)++还是等价于*(p++)? ...

  7. 异步协程 的 trip库

    import trip headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, ...

  8. mongodb 高级操作

    聚合 aggregate 聚合(aggregate)主要用于计算数据,类似sql中的sum().avg() 语法 db.集合名称.aggregate([{管道:{表达式}}]) 管道 管道在Unix和 ...

  9. Linux进程调度分析

    原文:http://www.2cto.com/os/201112/113229.html 操作系统要实现多进程,进程调度必不可少. 有人说,进程调度是操作系统中最为重要的一个部分.我觉得这种说法说得太 ...

  10. aws中的路由表

    参考官方文档: 由表中包含一系列被称为路由的规则,可用于判断网络流量的导向目的地. 在您的 VPC 中的每个子网必须与一个路由表关联:路由表控制子网的路由.一个子网一次只能与一个路由表关联,但您可以将 ...