1.什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
//实现效果就好比于我们new了一个目标类的对象一样,可以调用该类的所有属性和方法,但两者还是有很大不同,只是为了让大家更好的理解反射机制实现的效果而已。不同之处在于“动态”一词。
2.什么是动态?
用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。
换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),
并生成其对象实体、或对其fields设值、或唤起其methods
其实这里的两个动态是一个意思,都指的是非编译时处理,抑或运行时处理。这种机制,可以让程序的弹性增加不少。
举个栗子:一个应用程序由两个程序猿来写,A程序猿写的代码需要调用B程序猿写的类中的方法,此时A程序猿已经完成了自己的任务,而B程序猿还没有写完,如果没有使用反射机制的话,这两个人的代码肯定编译就过不了的,但是如果使用反射,在A程序就是可以通过编译的,只是在运行时去调用B程序的代码时会报错。—栗子中关键点:A程序是在运行时才去调用B程序的。不理解的仔细琢磨这句话应该就能理解了。
讲道理,应该是直接上代码的,但是为了更好的理解,还是先介绍一下反射中涉及的几个类吧。(感觉文字有点多了,大家先忍着看吧)
1–java.lang.Class;
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。
虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。也就是说,ClassLoader找到了需要调用的类时(java为了调控内存的调用消耗,类的加载都在需要时再进行,很抠但是很有效),就会加载它,然后根据.class文件内记载的类信息来产生一个《重点:与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等等信息。》以后jvm要产生该类的实例,就是根据内存中存在的该Class类所记载的信息(Class对象应该和我所了解的其他类一样会在堆内存内产生、消亡)来进行。而java中的Class类对象是可以人工自然性的(也就是说开放的)得到的(虽然你无法像其他类一样运用构造器来得到它的实例,因为Class对象都是jvm产生的。不过话说回来,客户产生的话也是无意义的),而且,更伟大的是,基于这个基础,java实现了反射机制。总之,大家理解一句话:每个类的都有自己的Class类,Class类封装了该类所有的信息就行。
2.java.lang.reflect.Field;;//用来封装反射得到的域(成员变量)
3.java.lang.reflect.Method;//用来封装反射得到的类的方法
4.java.lang.reflect.Constructor;//用来封装反射得到的构造器(构造方法)
下面直接上代码来了解下,所谓的反射是怎么实现的。
首先我创建了一个实体类Person类:该类也就是我之后要反射的类
package reflect1;
public class Person {
private String name;//域
private int age;
public Person() { //构造器
}
public Person(String name){
this.name=name;
}
public Person(int age){
this.age=age;
}
public Person(String name, int age) {
this.age=age;
this.name=name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString(){
return "["+this.name+" "+this.age+"]";
}
public void sayChina(){//方法
System.out.println("你调用了person中的sayChina方法");
}
public void sayHello(String name,int age){
System.out.println("你调用了person中的sayHello方法,姓名:"+name+"年龄:"+age);
}
}
1.首先得到目标类的反射类:
package reflect1;
public class GetClass {
//这里有三种方式得到一个类的反射类
public static void main(String[] args) {
Class<?> person1=null;
Class<?> person2=null;
Class<?> person3=null;
try{
//一般尽量采用这种形式
person1=Class.forName("reflect1.Person");//注意切记这里写的是类的全类名(包名.类名)
}catch(Exception e){
e.printStackTrace();
}
person2=new Person().getClass();//第二种,用对象.getClass()获得,不常用
person3=Person.class;//第四种,类名.class()获得,较常用
System.out.println("类名称 "+person1.getName());
System.out.println("类名称 "+person2.getName());
System.out.println("类名称 "+person3.getName());
}
}
运行结果:类名称 reflect1.Person
类名称 reflect1.Person
类名称 reflect1.Person
2.我们在项目需求中需要的肯定是类中的属性,方法,构造器等,所以当我们获取到所有的目标类的所有信息之后就是开始得到该类中的所有信息了。
先看如何得到该类中所有的域(成员变量)
package reflect1;
import java.lang.reflect.Modifier;
public class Field {
public static void main(String[] args) {
Class<?> person = null;
try {
person = Class.forName("reflect1.Person");
//得到目标类的类对象(封装了的所有信息)
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("===============本类属性========================");
// 取得本类的全部属性
java.lang.reflect.Field[] field = person.getDeclaredFields();
//getDeclaredFields方法得到所有的属性,用java.lang.reflect.field类去接收
for (int i = 0; i < field.length; i++) {
// 权限修饰符
int mo = field[i].getModifiers();//获得权限的数字格式码
String priv = Modifier.toString(mo);//将格式码转成我们认识的public /private/protect/?等等
// 属性类型
Class<?> type = field[i].getType();
System.out.println(priv + " " + type.getName() + " "
+ field[i].getName() + ";");
}
}
}
运行结果:===============本类属性==================
private java.lang.String name;
private int age;
3,看懂了第一个获得方法的,后面的我就不再做介绍了,因为是一模一样的
package reflect1;
public class Constructor {
//通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)
public static void main(String[] args) throws IllegalArgumentException {
Class<?> person=null;
try{
person=Class.forName("reflect1.Person");
System.out.println(person);
}catch (Exception e) {
e.printStackTrace();
}
Person per1=null;
Person per2=null;
Person per3=null;
Person per4=null;
//取得全部的构造函数
java.lang.reflect.Constructor<?>[] cons=person.getDeclaredConstructors();
for(int i=0;i<cons.length;i++){
System.out.println(cons[i]);
}
//利用得到构造方法创建对象实例
try{
per1=(Person)cons[0].newInstance("hello");
per2=(Person)cons[1].newInstance();
per3=(Person)cons[2].newInstance("hello",66);
per4=(Person)cons[3].newInstance(66);
}catch(Exception e1){
e1.printStackTrace();
}
System.out.println(per1);
System.out.println(per2);
System.out.println(per3);
System.out.println(per4);
}
}
运行结果:
[null 0]
[hello 66]
[null 66]
4得到该类中所有的方法:
package reflect1;
public class Method {
public static void main(String[] args) {
Class<?> person = null;
try {
person = Class.forName("reflect1.Person");
} catch (Exception e) {
e.printStackTrace();
}
java.lang.reflect.Method[] method=person.getDeclaredMethods();//
for(java.lang.reflect.Method me :method ){
System.out.println(me);
}
try{
//调用Person类中的sayChina方法
java.lang.reflect.Method method1=person.getMethod("sayChina");
method1.invoke(person.newInstance());
//调用Person的sayHello方法
java.lang.reflect.Method method2=person.getMethod("sayHello", String.class,int.class);
method2.invoke(person.newInstance(),"Rollen",20);
}catch (Exception e) {
e.printStackTrace();
}
}
}
好了,到这里为止,反射机制基础部分基本上已经介绍完毕了,剩下的就是以后再项目中的实战了,还有很多方法这里就不一一介绍了,大家可以查看之前写的那四个类的帮助文档,里面写的很详细的。