Java - 反射机制

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()执行;

你可能感兴趣的:(Java - 反射机制)