您的位置:首页 > 编程语言 > Java开发

Java的反射机制

2016-09-28 20:46 204 查看
1.概念
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能成为java语言的反射机制。这种在程序运行时,允许改变程序结构和变量类型的语言称之为动态语言。
通俗点说:这个机制允许程序在运行时透过Reflection
APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。

java的运行需要经历:java源程序(.java文件)----java编译器(.class文件)——java解释器(机器代码)——真正的执行
2.反射机制的作用:
1)反编译(反编译概念:计算机软件反向工程(Reverse engineering)也称为计算机软件还原工程,是指通过对他人软件的目标程序(比如可执行程序)进行“逆向分析、研究”工作,以推导出他人的软件产品所使用的思路、原理、结构、算法、处理过程、运行方法等设计要素,某些特定情况下可能推导出源代码。反编译作为自己开发软件时的参考,或者直接用于自己的软件产品中。)
2)通过反射机制访问java对象的属性,方法,构造方法等,动态的改变程序的结果或者变量的类型等;
3.JDK中提供的Reflection API提供的关于反射的类主要有:
java.lang.Class;                
java.lang.reflect.Constructor; 构造方法反射类
java.lang.reflect.Field;    属性反射类    
java.lang.reflect.Method; 方法反射类
java.lang.reflect.Modifier; 修饰符反射类
反射中的方法,属性等操作可以从这四个类中查询(这些类都重写了toString方法)
4.反射的具体使用
<1>反射机制获取类(即获取类的Class对象。Class
类的实例表示正在运行的 Java 应用程序中的类或者接口。获取类的Class对象有多种方式:)的三种方法:

Class 类的实例表示正在运行的 Java 应用程序中的类或者接口。获取类的Class对象有三种方式:

调用getClassBoolean var1 = true;

Class<?> classType2 = var1.getClass();

System.out.println(classType2);

输出:class java.lang.Boolean
运用.class 语法Class<?> classType4 = Boolean.class;

System.out.println(classType4);

输出:class java.lang.Boolean
运用static method Class.forName()Class<?> classType5 = Class.forName("java.lang.Boolean");

System.out.println(classType5);

输出:class java.lang.Boolean
 如下三种实验:
package demo;
public class GetClassDemo {
public static void main(String[] args) {
/*
* 利用反射获取类的三种方法
*/
try {
//1.第一种方法:Class.forName("包名+类名类的完整路径");
Class type_1 =Class.forName("demo.Person");
if (type_1!=null) {

System.out.println(type_1.toString());
}else {
System.out.println("1位空");
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//第二种方法 类的对象.getClass()来获取该类的类对象
Person person =new Person();
Class type_2 =person.getClass();
System.out.println(type_2+"--->2");
//第三种方法 类.class获取该类的类对象
Class type_3 =Person.class;
System.out.println(type_3+"----->3");
}
}
运行结果:
class demo.Person
class demo.Person--->2
class demo.Person----->3
<2>获取类对象之后创建原始类的对象
依旧接着上面的程序:
Object object =type_2.newInstance(); 且object instanceof Person ==true
也就是 object可以强制转换为Person类型
<3>获取属性
分为获取所有属性和指定属性
获取 所有属性:
//获取类中的所有属性
Field [] fields =class1.getFields();
for(Field f:fields)
{
StringBuilder builder =new StringBuilder();
int a = f.getModifiers();//获取属性的修饰符号不知为何这里竟然是int类型,待会考究
String typeNameString =f.getType().getSimpleName();//获取属性的类型的名字
String name = f.getName();//获取属性的名字
builder.append(typeNameString+" "+name);
System.out.println(builder);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//输出结果为: int min_value
int max_value
Class type
int size
int bytes
获取特定的属性(程序承接上面)
try {
//获取类中特定name属性
Field feild_name =type_2.getDeclaredField("name");
//实例化这个类
Object
object =type_2.newInstance();

//打破封装
原来的时候类中属性name为private修饰

//不能被其他类访问
反射中为name赋值必须打破封装

//不利之处:导致java对象的属性不安全
feild_name.setAccessible(true);
//给原始类对象object的属性name赋值
feild_name.set(object,
"张晓华");

//也可以从中取出来值
System.out.println(feild_name.get(object));
/*
* 注解上面:原来在源码中都是【对象.setXXX(值)】给类的实例赋值
* 【对象.getXXX()从类的对象中取值】,在反射中使用XXX.set(对象,值)给XXX本身赋值
* XXX.get(对象)获取XXX本身的值
*/
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
<4>、获取类的Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法
Class<T>类提供了几个方法获取类的方法。

public MethodgetMethod(String name,Class<?>... parameterTypes)返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法
public Method[] getMethods()返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
public MethodgetDeclaredMethod(Stringname,Class<?>... parameterTypes)返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法
public Method[] getDeclaredMethods()返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法
<5>获取类的Constructor
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例 
Class<T>类提供了几个方法获取类的构造器。

public Constructor<T> getConstructor(Class<?>... parameterTypes)返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法
public Constructor<?>[] getConstructors()返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法
public Constructor<?>[] getDeclaredConstructors()返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。它们是公共、保护、默认(包)访问和私有构造方法
//获取构造器的两种方法
// 1.使用getConstructors获取构造器
Constructor<?>[] constructors = type_2.getConstructors();
for (int i = 0; i < constructors.length; i++) {
System.out.println(constructors[i]);
}
//2.使用getDeclaredConstructor()获取构造器 type_2.getDeclaredConstructors();
//创建类的实例的3种方法
/* 第一种方法.调用类的Class对象的newInstance方法,该方法会调用对象的默认构造器,如果没有默认构造器,会调用失败. */
Class person_class =Person.class;
Object object = person_class.newInstance();
/* 第二种方法.调用默认Constructor对象的newInstance方法 */
Constructor<?> constructor = person_class.getConstructor();
Object object2 = constructor.newInstance();
/* 第二种方法调用Constructor对象的newInstance方法*/
Constructor<?> constructor2 =
person_class.getDeclaredConstructor(int.class, String.class);
Object object3 = constructor2.newInstance(1, "123");
}
<6>新建类的实例
通过反射机制创建新类的实例,有几种方法可以创建

调用无自变量ctor1、调用类的Class对象的newInstance方法,该方法会调用对象的默认构造器,如果没有默认构造器,会调用失败.

Class<?> classType = ExtendType.class;

Object inst = classType.newInstance();

System.out.println(inst);

输出:

Type:Default Constructor

ExtendType:Default Constructor

com.quincy.ExtendType@d80be3

2、调用默认Constructor对象的newInstance方法

Class<?> classType = ExtendType.class;

Constructor<?> constructor1 = classType.getConstructor();

Object inst = constructor1.newInstance();

System.out.println(inst);

输出:

Type:Default Constructor

ExtendType:Default Constructor

com.quincy.ExtendType@1006d75
调用带参数ctor3、调用带参数Constructor对象的newInstance方法

Constructor<?> constructor2 =

classType.getDeclaredConstructor(int.class, String.class);

Object inst = constructor2.newInstance(1, "123");

System.out.println(inst);

输出:

Type:Default Constructor

ExtendType:Constructor with parameters

com.quincy.ExtendType@15e83f9
 
<7>调用类的函数
通过反射获取类Method对象,调用Field的Invoke方法调用函数。
//获取所有方法
Method[] ms = type_2.getDeclaredMethods();
Object object3 = type_2.newInstance();
for(Method m:ms)
{
System.out.println(m);
//根据不同的方法中存在的参数执行不同的调用 这里除了无参的就是有一个String类型参数的因此这样简单判断
否则得进行严格逻辑判断

Parameter []ps = m.getParameters();
if(ps.length>0&&ps!=null)
{
//利用invoke调用方法
m.invoke(object3,"张三");
}
对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
 参考博客http://blog.csdn.net/liujiahan629629/article/details/18013523
http://blog.csdn.net/yongjian1092/article/details/7364451
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 反编译