黑马程序员-反射机制

——- android培训java培训、期待与您交流! ———-

问题1: Class类是什么?有什么作用?

Class类是所有类的基类,是每一个类放在内存中的字节码。
通过Class类可以知道,每一个类中的所有组成部分。包括类中属性,该类的构造函数,该类所拥有的方法等内容。

问题2:如何获得一个类的Class类的字节码实例对象,三种方法(以Person类为例):

1)Class cls1 = Person.class
2)Class cls2 = person.getClass()
3)Class cls3 = Class.forName(“java.lang.String”)
forName加载有两种,一种是已经存在了,直接加载,另一种是不存在,先加载到虚拟机中在应用。

问题3:Class类有几种基本字节码?

基本字节码共九种,包括8种基本数据类型和Void.class,是否是基本自己码可以用isPrimitive()来判断。用isArray()判断是否是数组。

具体看下面代码实例:

class ReflectTest
{
    public static void main(String args[])
    {
        String str = "abc";
        Class cls1 = String.class;
        Class cls2 = str.getClass();
        Class cls3 = Class.forName("java.lang.String");
        System.out.println("cls1==cls2");//true
        System.out.println("cls1==cls2");//true

        System.out.println("cls1.isPrimitive()");//false
        System.out.println("int.class.isPrimitive()");//true
        System.out.println("int.class==Integer.class");//false
        System.out.println("int.class==Integer.Type");//true
        System.out.println("int[].class.isPrimitive()");//false
        System.out.println("int[].class.isArray()");//true
    }
}

(一)利用反射得到构造方法,并实例化对象

1)正常情况:String str = new String(new StringBuffer(“abc”));
2)利用反射:Constructor con=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
String str = con.newInstance(new StringBuffer(“abc”));
3)String.class类中有一个方法newInstance()是获得无参构造。

示例1如下:
首先定义已知类:ReflectPoint

class ReflectPoint
{
    private int x;//私有属性
    public int y;//公共属性
    public RefletctPoint(int x,int y)//含有两个整型参数的构造方法
    {
        super();
        this.x = x;
        this.y = y;
    }
}

1)获取公共属性y

ReflectPoint rp = new ReflectPoint(3,5);//获得该类的实例对象
Field fiedlY = rp.getClass().getField("y");//通过该类的实例对象获得该类的公共属性y
System.out.println(fieldY.get(rp));//取得该类对应的此实例对象的公共属性y对应的值,结果为5。

2)私有属性获得方式

Field fieldX = rp.getClass().getDeclaredField("x");//通过该类的实例对象获得该类的私有属性x
fieldX.setAccessible(true);//设置该私有属性可以被访问。
System.out.println(fieldX.get(rp));//取得该类对应的此实例对象的私有属性x对应的值,结果为3。

示例2:
利用反射:将任意一个对象中的所有String 类型的成员变量所对应的字符内容中的‘b’改为 ‘a’。
首先定义已知类

class ReflectPoint
{
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "all";
    public String toString()
    {
        return str1+"......"+str2+"......"+str3+"......";
    }
}

封装一个函数进行改写操作

public static void changeStringValue(Object obj) throws Exception
{
    Field[] fields = obj.getClass().getFields();
    for(Field field:fields)
    {
        if(field.getType()==String.class)
        {
            String oldValue = (String)field.get(obj);
            String newValue = oldValue.replace('b','a');
            field.set(obj,newValue);
        }
    }
}

在主函数中调用并验证

{
    ReflectPoint rp = new ReflectPoint();
    changeStringValue(rp);
    System.out.println(rp);
}

运行结果如下:
这里写图片描述
改写成功!

(三)利用反射:调用方法

以java.lang.String类为例,获取它的CharAt()方法

String str = "abc";
Method methodCharAt = String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str1,1));//结果为b

此处invoke()为调用的意思,其中第一个参数为调用的对象,第二个为该方法的参数。如果是静态函数,则第一个参数为null,应书写如下:

System.out.println(methodCharAt.invoke(null,1));

示例3: 用反射提供一个程序,根据用户提供的类名,调用该类的main方法

首先写出已知类ReflectTest:

package com.test;
public class ReflectTest
{
    public static void main(String args[])
    {
        for(String arg:args)
        {
            System.out.println(arg);
        }
    }
}

在另一个程序中调用:

public class ReflectDemo
{
    public static void main(String args[])
    {
        String startingClassName = args[0];
        Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
        mainMethod.invoke(null,(Object)new String[]{"123","345","234"});
        mainMethod.invoke(null,new Object[]{new String[]{"123","345","234"}});
    }
}

程序运行结果如下:
[“123”,”345”,”234”]
“123”
“345”
“234”

此处invoke()方法的第二参数,作为被调用方法的参数传入,其形式为Object数组形成,也可以为Object对象。

附带:分析一下数组与Object类的关系

看如下示例4:

public class ArrayObjectDemo
{
    public static void main(String args[])
    {
        int[] a1 = new int[3];
        int[] a2 = new int[4];
        int[][] a3 = new int[2][3];
        String[] a4 = new String[3];
        System.out.println(a1.getClass()==a2.getClass());//true
        System.out.println(a1.getClass()==a3.getClass());//false
        System.out.println(a1.getClass()==a4.getClass());//false
        System.out.println(a1.getClass.getName());//I
        System.out.println(a1.getClass.getSuperclass().getName());//
        System.out.println(a4.getClass.getSuperclass().getName());

        Object obj1 = a1;
        Object obj2 = a4;
        Object[] obj3 = a3;
        Object[] obj4 = a4;
        Object[] obj5 = a1;//此处编译不通过。
        System.out.println(a1);//
        System.out.println(a4);//
        System.out.println(Arrays.asList(a1));//
        System.out.println(Arrays.asList(a4));//
    }
}

备注:Arrays.asList()这个方法的作用是把数组转化为List集合。

综上例子可以发现:

1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
2)基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用。
3)非基本数据类型的一维数组既可以被当作Object类使用,也可以当作Object[]类型使用

利用反射机制和Array工具类完成对数组的操作:
示例5:打印数组。

封装打印数组的方法如下:

public void printObj(Object obj)
{
    Class cla = obj.getClass();
    if(cla.isArray())
    {
        int len = Array.getLength(obj);
        for(int i=0;i<len;i++)
        {
            System.out.println(Array.get(obj,i));
        }
    }else
    {
        System.out.println(obj);
    }
}

主方法调用并获得结果如下:

String[] a4 = new String[]{"a","b","c"};
printObj(a4);//结果为a,b,c
printObj("abdc");//结果为abcd

综上是说明Class类的基本作用;
作为反射机制,最大的作用在于:

实现框架功能

在许多框架中,在写框架时,还不知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射方式来做。
用例子说明如下:
示例6:新建一个Properties类,新建config.properties文件。

className=java.util.HashSet

该主方法(模拟为框架代码)

public class ReflectTest3
{
    public static void main(String args[])
    {
        InputStream is = new FileInputStream("config.properties");
        Properties props = new Properties();
        props.load(is);
        is.close();

        String className = props.getProperties("className");
        Collection collections = Class.forName(className);

        ReflectPoint pt1 = new ReflectPoint(3,3);
        ReflectPoint pt2 = new ReflectPoint(5,5);
        ReflectPoint pt3 = new ReflectPoint(3,3);

        collections.add(pt1);
        collections.add(pt2);
        collections.add(pt3);
        collections.add(pt1);

        System.out.println(collections.size());  //打印结果为2
    }
}

定义被框架调用的类

class ReflectPoint
{
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "all";
    public String toString()
    {
        return str1+"......"+str2+"......"+str3+"......";
    }
}

以上内容是对反射内容的全部概括,但是也是最基本的内容,多做练习,加深理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值