您的位置:首页 > 职场人生

黑马程序员---------------高新技术之反射

2014-03-23 07:19 169 查看
----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
反射

        反射技术是指动态的获取类以及类中的成员,并可以调用该类中的成员。我们可以通过以下例子来了解类的字节码文件的概念:当我们定义一个Person类时,它可创建出多个人的实例对象,如小明,小红等。而小明和小红这些人的主要属性在Person类中都有体现,因此我有了Perosn类时就可以创建其它的人对象。同理,我们写的每个程序都会生成一个字节码文件,也可以将这些不同对象的字节码进行向抽取,可以抽出Class这个类出来,它其中就有每个文件的字节码中的共性方法。而当我们拿到了一个文件对应的字节码文件就可以很容易的得到它所对应的对象上所有的方法。

     如何获取一个字节码文件的对象?

     方式一:通过查API文档发现Object类中就有一个直接可以获取字节码的方法。Object getClass().但是它有一个前提是,必须有具体的对象时才能调用此方法,而我们用反射的原因就是我们不知道我们所要操作的对象是哪个,所以这个方法用在反射里作用不大。

      Person  p=new  Person();

      p.class();----->这个就可以获取到p对象的字节码文件

   方式二:所有的数据类型都有自己对应的class对象,直接可以用类名.class就行,数据类型有九大类(八种基本数据类型和void)。这是因为.class是它们的一个静态属性,所以可以直接调用。

        Class clazz=int.class;

  方式三:当我们只知道一个类的名称时,可以通过类名获取这个类的字节码文件。

              Class clazz=Class.forName("it.cast.Person");------>此处一定得注意,要写出类的完整名称,包括包名。要不就会报出ClassNotFoundException异常。

   有了获取一个类的字节码文件的方法我们就可以获取这个类中的各种属性,构造方法,成员变量,成员函数(字段)。

public class Person {

   private String name;

   private int age;

   public Person(String name,int age)

   {
  this.name=name;
  this.age=age;

   }

   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;

}

public void show(){
System.out.println("perosn show run");

}

public static void staticShow(){
System.out.println("person static show run");

}

public void paramShow(String name,int age){
System.out.println("show:"+name+"----"+age);

}

}

首先,获取以上这个Person类中的构造方法。

   String className="GaoXing.Person";
//得到了字节码文件,可以获取它的成员
Class clazz=Class.forName(className);
//创建一个 Person对象
//Object obj=clazz.newInstance();//此时创建对象是用的Person里的默认空参数构造函数,会报异常,
                              //因为在定义Person时没有空参数构造函数,当我定义了一个空参数构造函数时就好了
/*而现在我想要创建一个带姓名和年龄的对象,该怎么做?
* 首先得先获取它的构造方法,再用这个构造方法进行创建*/
Constructor cons=clazz.getConstructor(String.class,int.class);
Object obj=cons.newInstance("lisi",34);
System.out.println(cons);

第二步,获取Person类中的各种方法,因为我在Person类中分别定义了静态不带参数的方法,非静态不带参数的方法,非静态带参数的方法,分别进行获取。

//反射方法,非静态,有参数的show方法
public static void getShow3()throws Exception
{
Class clazz=Class.forName("GaoXing.Person");

Method method =clazz.getMethod("paramShow",String.class,int.class);
Object obj=clazz.newInstance();
method.invoke(obj, "wangwu",45);---->因为在调用方法时,需要被对象所调用,所以在此之前需要创建一个对象
}
//反射方法,静态,无参数的show方法
public static void getShow2()throws Exception
{

          Class clazz=Class.forName("GaoXing.Person");

Method method =clazz.getMethod("staticShow",null);
method.invoke(null, null);--->因为方法是静态的,所以在调用此方法时,不需要对象来调用,所以是null
}
//反射方法,非静态,无参数的show方法
public static void getShow()throws Exception
{
Class clazz=Class.forName("GaoXing.Person");

Method method =clazz.getMethod("show",null);//--->因为是无参数的方法,所以不需要提供参数列表
Object obj=clazz.newInstance();
method.invoke(obj, null);
}

第三步,获取Person类中的成员变量

public static void getAge()throws Exception
{
//第一步,获取字节码文件
Class clazz=Class.forName("GaoXing.Person");
//每二步,获取方法
Field field=clazz.getDeclaredField("age");----->因为在Person类中的年龄属性是私有的,所以在反射这个方法时要用                                             到getDeclaredField,它可以获取到对象上所有只要声明的变量,它也叫做暴力反射。

//要对非静态的字段操作必须有对象
Object obj=clazz.newInstance();
field.setAccessible(true);-------->当我们获取到私有成员时,虽然我们可以知道有这么个成员,但是我们还不能对其进设置,所以要用这个方法来解除它对我们访问的权限。
field.set(obj, 40);//--->这时会报出异常,是因为age是私有的,不能直接被访问到,所以要用到它的父类,
System.out.println(field.get(obj));

}

总结:反射时我们首先要知道它的类名,然后再根据类名来获取它的字节
99b0
码文件,注意的是一定要把类名写全也就是要把包名也要带上。其次在获取相对应的方法,成员,构造方法时,要注意它们所调用的反射方法参数列表中所要写的也是相对应类型的字节码文件。

----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息