黑马程序员--反射

来源:互联网 发布:汉邦尚品 知乎 编辑:程序博客网 时间:2024/06/02 05:14

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------




反射是什么?
反射就是把java类中的各种成分映射成相应的java类。例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也要一个个java类来表示。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,他们是Field,Method,Contructor,Package等等。

 

那么,如何获得一个类的Class对象呢?

获得javaClass对象的方法有三种,此处便拿String类作为示例:

String str = new String();

//类名.class

Class clazz1 = String.class;

//对象.class

Class clazz2 = str.getClass();

//Class类中的静态方法:forName(类名);

Class clazz3 = Class.forName("java.lang.String");

如果要加载的字节码已经被加载过,那么会直接返回那一份的字节码,如果没有加载过,那么jvm会把加载进来的字节码缓存起来。

 

在java中还有九个预定义实例对象:为八个基本类型和void

int double boolean sort char byte longfloat ,void

 

可以通过方法Class.isPrimitive()来判断是否为基本数据类型。

 

判断是否为数组:Class.isArray();

 

总之,只要在源程序中出现的类型都有各自的class实例对象,例如,int[],void

 

在比较字节码的时候用“==”胜过 equals(),因为比较的是两个Class对象用==来比较更加的合理。

 

Constructor类:

Constructor类代表某个类中的一个构造方法;

得到某个类的所有构造方法:

Constructor[] constructors =Class.forName("java.lang,String").getConstructors();

 

得到某一个构造方法:

Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);

 

创建实例对象:

通常方式:String str =

         newString(new StringBuffer("abc"));

反射方式:String str =

         (String)constructor.newInstance(newStringBuffer("abc");

 

Class.newInstance()方法

例子:String obj =(String) Class.forName(“java.lang.String”).newInstance();

该方法先获得默认的构造方法,然后用该构造方法来创建实例化对象。

该方法内部的代码是怎么写的呢?

         用到了缓存机制来保存默认的构造方法的实例对象。

实例:

package com.itheima;

 

import java.lang.reflect.Constructor;

 

public class ConstructorTest {

    public static void main(String[] args) {

       try {

           Constructor con = Class.forName("java.lang.String").getConstructor(new StringBuilder().getClass());

           String str = (String)con.newInstance(new StringBuilder("abc"));

           System.out.println(str);

       } catch (Exceptione) {

           // TODO Auto-generatedcatch block

           e.printStackTrace();

       }

    }

}

 

 

Field类:

Filed实例对象值代表类字节码中的一个变量,并不代表某一个对象里面的变量本身具体的值。我们需要调用Field类中的get(Object obj)方法。

Field类中的常用方法:

//获取所有public的Field对象。

getFields();

//非public成员获取Field对象(包括public)。

getDeclaredFields();

//暴力访问:

setAccessible(boolean flag);

//将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

set(Object obj,Object value);

//返回指定对象上此 Field 表示的字段的值。

get(Object obj)
//返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

getType();

 

Filed对象的使用:

Package com.itheima;

 

import java.lang.reflect.Field;

 

 

public class ChangeStringTest {

    public static void changeStringValue(Objectobj){

       //获得所有Field对象。

       Field[] fields = obj.getClass().getDeclaredFields();

       //取出Field集合中的元素。

       for (Fieldfield : fields) {

           //判断field类型是否为String,因为比较的是字节码文件 所有用==胜过equals();

           if(field.getType()==String.class){

              try {

                  //暴力访问。

                  field.setAccessible(true);

                  //使用一个字符串记录下field对象中String类型的值.

                  String oldValue = (String)field.get(obj);

                  //使用一个新字符串将旧字符串中的b替代为a

                  String newValue =oldValue.replace('b','a');

                  //newValue的值设置进obj中。

                  field.set(obj,newValue);

              } catch (IllegalArgumentExceptione) {

                  // TODO Auto-generatedcatch block

                  e.printStackTrace();

              } catch (IllegalAccessExceptione) {

                  // TODO Auto-generatedcatch block

                  e.printStackTrace();

              }

           }

       }

    }

    public static void main(String[] args) {

      

       Test test = new Test();

       changeStringValue(test);

       System.out.println(test);

 

    }

}

class Test{

    public Stringstr1 = "ball";

    public Stringstr2 = "basketball";

    public Stringstr3 = "itcast";

    private Stringstr4 = "byebye";

    private Stringstr5 = "hellow";

    public Test() {

       // TODO Auto-generatedconstructor stub

    }

    @Override

    public String toString() {

       return"Test[str1=" + str1 +",str2=" + str2 +",str3=" + str3

              + ",str4=" + str4 + ",str5=" + str5 + "]";

    }

   

}

 

Method类

Method类代表某个类中的一个成员方法。

得到类中的某一个方法:

Method charAt =

    Class.forName("java.lang.String").getMethod("charAt",int.class);

 java.lang.reflect.Method.invoke(Object obj,Object... args)

调用方法:

通常方式:System.out.println(str.charAt(1));

反射方式:System.out.println(charAt.invoke(str,1));

    如果,传递给Method方法invoke为null,这意味着什么呢?

        Method对象对应的是一个静态方法。

实例:

package com.itheima;

 

import java.lang.reflect.Method;

 

public class MethodDemo {

    public static void main(String[] args) {

       try {

           String str = "itheima";

           //通常方式。

           System.out.println(str.charAt(3));

           //反射方式

           Method charAt =

                  Class.forName("java.lang.String").getMethod("charAt",int.class);

           System.out.println(charAt.invoke(str, 3));

      

           Method mainMethod = MethodTest.class.getMethod("main", String[].class);

          

           //因为传给MethodTestmain方法为静态 所以传递给Method对象的invoke()方法的参数为null

           //在给main方法传递参数的时候需要给String[]进行打包,使其不被解包。

           //方法一:

           mainMethod.invoke(null, (Object)new String[]{"abc","def","xyz"});

           //方法二:

           mainMethod.invoke(null,new Object[]{new String[]{"abc","def","xyz"}});

       } catch (Exceptione) {

           // TODO Auto-generatedcatch block

           e.printStackTrace();

       }

    }

}

class MethodTest{

    public static void main(String[] args) {

       for (Stringarg : args) {

           System.out.println(arg);

       }

    }

}

0 0
原创粉丝点击