java的反射机制原理
一反射机制的概念:指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制.java反射机制是围绕Class类展开的,在深入java反射原理之前,需要对类加载机制有一个大致的了解。jvm使用ClassLoader将字节码文件(class文件)加载到方法区内存中:Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.mypackage.MyClass");可见ClassLoader根据类的完全限定名加载类并返回了一个Class对象,而java反射的所有起源都是从这个class类开始的。看个列子://1.获取类
Class c = Class.forName("_12_CustomerService");
//获取某个特定的方法
//通过:方法名+形参列表
Method m = c.getDeclaredMethod("login",String.class,String.class);
//通过反射机制执行login方法.
Object o = c.newInstance();
//调用o对象的m方法,传递"admin""123"参数,方法的执行结果是retValue
Object retValue = m.invoke(o, "admin","123");
System.out.println(retValue); //true
二.反射机制的作用
1.在运行时判断任意一个对象所属的类;
2.在运行时获取类的对象;
3.在运行时访问java对象的属性,方法,构造方法等。
三.反射机制的优点与缺点
首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。静态编译:在编译时确定类型,绑定对象,即通过。动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。
1.通过一个对象获得完整的包名和类名
添加一句:所有类的对象其实都是Class的实例。
class Demo{ //other codes... } class hello{public static void main(String[] args) {Demo demo=new Demo(); System.out.println(demo.getClass().getName());}}
2.实例化Class类对象
public static void main(String[] args) {
Class> demo1=null;
Class> demo2=null;
Class> demo3=null;
try{
//一般尽量采用这种形式
demo1=Class.forName("Reflect.Demo");
}catch(Exception e){
e.printStackTrace();
}
emo2=new Demo().getClass();
demo3=Demo.class;
System.out.println("类名称 "+demo1.getName());
System.out.println("类名称 "+demo2.getName());
System.out.println("类名称 "+demo3.getName());
【运行结果】:
类名称Reflect.Demo
类名称Reflect.Demo
类名称Reflect.Demo
3.通过Class实例化其他类的对象
class Person{
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString(){
return "["+this.name+" "+this.age+"]";
}
private String name;
private int age;
}
class hello{
public static void main(String[] args) {
Class> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Person per=null;
try {
per=(Person)demo.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
per.setName("Rollen");
per.setAge(20);
System.out.println(per);
}
}
4.通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)
package Reflect;
import java.lang.reflect.Constructor;
class Person{
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 String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString(){
return "["+this.name+" "+this.age+"]";
}
private String name;
private int age;
}
class hello{
public static void main(String[] args) {
Class> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Person per1=null;
Person per2=null;
Person per3=null;
Person per4=null;
//取得全部的构造函数
Constructor> cons[]=demo.getConstructors();
try{
per1=(Person)cons[0].newInstance();
per2=(Person)cons[1].newInstance("Rollen");
per3=(Person)cons[2].newInstance(20);
per4=(Person)cons[3].newInstance("Rollen",20);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(per1);
System.out.println(per2);
System.out.println(per3);
System.out.println(per4);
}
}
5.取得其他类中的父类
class hello{
public static void main(String[] args) {
Class> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
//取得父类
Class> temp=demo.getSuperclass();
System.out.println("继承的父类为: "+temp.getName());
}
}
//【运行结果】
//继承的父类为: java.lang.Object
6.通过反射操作属性
class hello {
public static void main(String[] args) throws Exception {
Class> demo = null;
Object obj = null;
demo = Class.forName("Reflect.Person");
obj = demo.newInstance();
Field field = demo.getDeclaredField("sex");
field.setAccessible(true);
field.set(obj, "男");
System.out.println(field.get(obj));
}
7.通过反射调用其他类中的方法
class hello {
public static void main(String[] args) {
Class> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
try{
//调用Person类中的sayChina方法
Method method=demo.getMethod("sayChina");
method.invoke(demo.newInstance());
//调用Person的sayHello方法
method=demo.getMethod("sayHello", String.class,int.class);
method.invoke(demo.newInstance(),"Rollen",20);
}catch (Exception e) {
e.printStackTrace();
}
}
}
//【运行结果】:
//hello ,china
//Rollen 20
用几句话总结反射的实现原理:
1.反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;
2.每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;
3.反射也是考虑了线程安全的,放心使用;
4.反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;
5.反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;
6.当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;
7.调度反射方法,最终是由jvm执行invoke0()执行;