------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一概述
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射这一知识点确实很重要,而且扩展性极强。但是我在第一次学习这一块的基础视频的时候真是有一种云里雾里的感觉,老师讲的写的每一行代码我都会写,但是却理解不透,好像有一种雾里看花隔着一层窗户纸的感觉。尤其是反射调用字段和方法。这种情况一直在我坚持看了2遍张孝祥老师和2遍毕向东老师的反射这一块的视频之后才有了进展。简单的说反射就是动态获取类中信息,对类进行解刨。
二反射的理解
我觉得理解反射首先要明确一个概念:那就是动态语言!因为我在学习时对“动态获取类中信息”很困惑。
动态语言:程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。
从这个观点出发Java语言不是动态语言,所以Java有了一个非常突出的动态相关机制--Reflection,可以在运行时加载,探知,使用编译时期完全未知的classes,也就是说Java可以加载一个运行时才知道名称的class。
也就是说Java反射机制是在运行状态中,对于任意一个类(class文件<字节码文件>),都能知道这个类的属性和方法。
对于任意一个对象,都能调用它的属性和方法。
这种动态获取类的信息以及动态调用对象的方法的功能成为Java语言的反射机制。
简单的说:反射就是把Java类中的各种成分映射成相应的java类。
三 Class类
1字节码
当源程序中用到类时,首先要从硬盘把这个类的那些二进制代码,一个类编译成class文件放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来。
2 Class类的由来
所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。
Class类中包含属性有field(字段)、method(方法)、construction(构造函数)。
要想对一个类进行内容的获取,必须要先获取该字节码文件的对象。该对象是Class类型。
Class类描述的信息:类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表等。每一个字节码就是class的实例对象。如:classcls=Data.class;
3 Class和class的区别
1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。
2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。Class是Java程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。
4 获取Class对象的三种方式
加载XX.class文件进内存时就被封装成了对象,该对象就是字节码文件对象
1).通过对象的getClass方法进行获取。
如:Class clazz=new Person().getClass();//Person是一个类名
弊端:每次都需要具体的类和该类的对象,以及调用getClass方法。
2).任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应 Class对象。
如:Class clazz=Person.class;//Person是一个类名
弊端:还是要使用具体的类,和该类中的一个静态属性class完成。
3). 这种方式较为简单,只要知道类的名称即可。不需要使用该类,也不需要去调用具 体的属性和行为。就可以获取到Class对象了。
如:String className=”Person”;
Class clazz=Class.forName(className);//Person是一个类名
这种方式仅知道类名就可以获取到该类字节码对象的方式,利于扩展。
4 反射的好处:
反射极大的增强了程序的扩展性。
5 反射是使用步骤
步骤:
1,获得Class对象,就是获得指定名称的字节码文件对象。
2,实例化对象,获类的属性,方法和构造函数。
3,调用构造函数创建对象,访问属性,调用方法。
6 常用方法
Class forName(String className)
返回与给定字符串名的类或接口的相关联的Class对象。
Class getClass()
返回的是Object运行时的类,即返回Class对象即字节码对象
Constructor getConstructor()
返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。
Field getField(String name)
返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。
Field[] getFields()
返回包含某些Field对象的数组,表示所代表类中的成员字段。
Method getMethod(String name,Class… parameterTypes)
返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。
Method[] getMehtods()
返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。
String getName()
以String形式返回此Class对象所表示的实体名称。
String getSuperclass()
返回此Class所表示的类的超类的名称
boolean isArray()
判定此Class对象是否表示一个数组
boolean isPrimitive()
判断指定的Class对象是否是一个基本类型。
T newInstance()
创建此Class对象所表示的类的一个新实例。
Method.invoke(obj,null);
四 Constructor类
1 Constructor:Constructor代表某个类的构造方法。
2 获取字节码文件对象后,创建指定类的对象:
两种方式:
1,调用空参数的构造函数,使用了Class类中的newInstance()方法;
2,调用带参数的构造函数,先要获取指定参数列表的构造函数,然后通过该构造函数对象的newInstance (实际参数)进行对象的初始化。
这种方式必须要先明确具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常会提供一个公有的空参数的构造函数。
具体的代码:
Class clazz=Class.forName(“Person”);
Object obj=clazz.newInstance();//该实例化方法调用的就是指定类中的空参数的构造函数。给创建对象进行初始化。
如果指定的类中没有空参数的构造函数:
//获取一个带参数的构造器。
Constructor constructor=clazz.getConstructor(String.class,int.class)
//对对象进行初始化,使用构造器的newInstance()方法;
Object obj=constructor.newInstance(“zhangsan”,25);
//获取所有构造器:
Constructor[] constructors=clazz.getConstructors();//只包含公共的。
Constructor[] constructors1=clazz.getDeclaredConstructors();//包含私有的。
for(Constructor con:constructors)
{
System.out.println(con);
}
五 Field类
常用方法:
Field getField(String s);//只能获取公有和父类中公有
Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有
setAccessible(ture);
//如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。
set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。
Object get(Object obj);//返回指定对象上Field表示的字段的值。
六 Method类
1、概述:Method类代表某个类中的一个成员方法。调用某个对象身上的方法,要先得到方法,再针对某个对象调用。
2、专家模式:谁调用这个数据,就是谁在调用它的专家。
如人关门:
调用者:是门调用关的动作,对象是门,因为门知道如何执行关的动作,通过门轴之类的细节实现。
指挥者:是人在指挥门做关的动作,只是给门发出了关的信号,让门执行。
总结:变量使用方法,是方法本身知道如何实现执行的过程,也就是“方法对象”调用方法,才执行了方法的每个细节的。
3、方法
Method[] getMethods();//只获取公共和父类中的方法。
Method[] getDeclaredMethods();//获取本类中包含私有。
Method getMethod("方法名",参数.class(如果是空参可以写null));
Object invoke(Object obj ,参数);//调用方法
如果方法是静态,invoke方法中的对象参数可以为null。
如:
获取某个类中的某个方法:(如String str =”abc”)
1)通常方式:str.charAt(1)
2)反射方式:
Method charAtMethod =Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
charAtMethod.invoke(str,1);
说明:如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法.
Example:
import java.lang.reflect.*;
class Person implements Comparable
{
private int age;
private String name;
public Person(String name,int age)
{
super();
this.age=age;
this.name=name;
System.out.println("Person param run");
}
public Person()
{
super();
System.out.println("Person run");
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public void show()
{
System.out.println(name+"...show run..."+age);
}
private void method()
{
System.out.println("method run");
}
public void paramMethod(String str,int num)
{
System.out.println("paramMethod run...."+str+":"+num);
}
public void staticMethod()
{
System.out.println("staticMethod run");
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
{
return false;
}
else
{
Person p=(Person)obj;
return this.name.equals(p.name);
}
}
public int hashCode()
{
return name.hashCode()+age*25;
}
public int compareTo(Object obj)
{
if(!(obj instanceof Person))
throw new RuntimeException("不是学生对象");
Person s=(Person)obj;
if( this.age>s.age)
return 1;
if(this.age==s.age)
return this.name.compareTo(s.name);
return -1;
}
public static void main(String[] args)
{
}
}
class FanSheDemo
{
public static void main(String[] args)throws Exception
{
String str="Person";
Class clazz=Class.forName(str);//获取Person类的Class对象。
Constructor c=clazz.getConstructor(String.class,int.class);//获取带惨、指定参数的构造函数。
Object ob=c.newInstance("zhangsan",25);//厂家你一个实例对象。
Field f=clazz.getDeclaredField("name");//获取本类中所有成员,包括私有。
f.setAccessible(true);//暴力访问。
Method m=clazz.getMethod("paramMethod",String.class,int.class);//获取带指定惨数的方法。
Object obj=clazz.newInstance();
m.invoke(obj,"aa",25);//调用该方法。
System.out.println(f.get(obj));
System.out.println(f.get(ob));
}
}
七 反射机制的优点与缺点
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。