黑马程序员-Java 反射-

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

1.概述

反射技术就是动态加载一个指定的类,并获取该类中的所有的内容。或者动态加载一个 对象,通过反射机制都可以去调用它的每一个方法。简单的说:反射技术可以对一个类进行解剖。

2.基本方法

反射的基本步骤为:
1.获得Class对象,获得指定名称的字码节文件对象。
2.实例化对象,获得对应类的属性、方和构造函数。
3.访问该属性、调用方法、调用构造函数创建对象。
小知识:什么叫字节码?
当源程序中用到类时,首先要从硬盘把这个类的那些二进制代码,一个类编译成class放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来。

3.Class类

所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。作为Java中类文件的一个类,获取类的类一般有三种方式:

String s = "abc";
Class<?> c1 = String.class;// 通过类直接获取
Class<?> c2 = s.getClass();// 通过变量的getClass()方法获取
Class<?> c3 = Class.forName("java.lang.String");// 通过Class的静态方法forName(String)根据类的全名获取

对于上述中的(?)基本数据类型boolean,char,byte,short,int,long,float,double共8个和一个void都有其对应的类,如int.class,注意int.class和Integer.class不是同一个类。对于数组也有其对应的类,如int[].class,int[][].class,类型相同,维数相同的数组类才是同一个类,即int[].class != int[][].class。
Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的。基本数据类型的字节码都可以用与之对应的包装类中的TYPE常量表示。

  • Class类的常用方法:
static Class forName(String className);//返回定字符串名的类或接口的的Class对象。
Class getClass();//返回的是Object运行时的类
Constructor getConstructor(Class<?>... parameterTypes);//返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。
Constructor[] getConstructors();//返回Constructor对象的数组,是所代表的的类中的公共构造方法。
Field getField(String name);//返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。
Field[] getFields();//返回Field对象的数组,表示所代表类中的成员字段。
Method getMethod(String name,Class… parameterTypes);//返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。
Method[] getMehtods();//返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。
boolean isArray();//判定此Class对象是否表示一个数组
boolean isPrimitive();//判断指定的Class对象是否是一个基本类型。
String getName();//以String形式返回此Class对象所表示的实体名称。
String getSuperclass();//返回此Class所表示的类的超类的名称
T newInstance();//创建此Class对象所表示的类的一个新实例。

Class类是没有构造方法的, 因此只能通过方法获取类实例对象。如下这个例子就是利用反射方法构造一个String对象:

import java.lang.reflect.*;
class Demo {
    public static void main(String[] args) throws Exception {
       Constructor con = String.class.getConstructor(StringBuilder.class);// 获取String的一个构造方法
        // 使用newInstance()创建一个String对象
        String str = String.class.newInstance();
    }
}

4. 反射类的构造函数 Constructor

如果指定的类中没有空参数的构造函数,或者要创建的类对象需要通过指定的构造函数进行初始化。这时就不能使用Class类中的newInstance方法了。需要获取这个构造函数——Constructor。Constructor代表某个类的构造方法。

基本方法如下:

Class<T> getDeclaringClass();//返回 Class 对象,该对象表示声明由此 Constructor 对象表示的构造方法的类。
int getModifiers();//返回以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符。
T newInstance(Object... initargs);//使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

下面的例子说明了如何使用java.lang.Class.getConstructor()方法:

import java.lang.reflect.*;

public class ClassDemo {

   public static void main(String[] args) {

     try {
        Class cls[] = new Class[] { String.class };//创建一个String
        Constructor c = String.class.getConstructor(cls);//获得其构造方法 String(string);
        System.out.println(c);//结果为public java.lang.String(java.lang.String)

     }
     catch(Exception e) {
        System.out.println(e);
     } 
   }
} 

上述写法中也可以改为:Class clc = String.class;//创建一个String类
Constructor c = clc.getConstructor(String.class);//获得其构造方法
若改为Constructor c = clc.getConstructor();//则获得String();的构造方法,里面是空参数

5.反射类的属性Field

Field类是描述一个类的成员,一般功能有获取这个成员的值,设置这个成员的值,获取这个成员的数据类型等.基本方法如下:

Field getField(String s);//只能获取公有和父类中公有
Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有
setAccessible(ture);//如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。
set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。
Object get(Object obj);//返回指定对象上Field表示的字段的值。

下面是是一个更改的实例:

import java.lang.reflect.Field;
public class Demo {
    public static void main(String[] args) throws Exception
    {
        Textproperty t = new Textproperty();//建立测试对象t
        System.out.println(t.getPropertyName());//输出修改前的对象t的的属
        setProperty(t,"propertyName","value");//调用方法对属性进行修改
        System.out.println(t.getPropertyName());//输出修改后的对象t的属性值
    }
    public static void setProperty(Object obj, String propertyName, Object value) throws Exception
    {
        //将propertyName通过反射封装成Field对象
        Field f = obj.getClass().getDeclaredField(propertyName);
        //将propertyName的accessible属性设为true
        f.setAccessible(true);
        //将obj中的propertyName设置为value
        f.set(obj, value);
    }

}
class Textproperty//测试类
{
    private String propertyName;//建立用于修改的空属
    public String getPropertyName()
    {
        return propertyName;//获取对象属性的方法
    }
}

输出结果为:null
value

五.反射成员函数的Method

描述某个类中的一个成员方法。调用某个对象身上的方法,要先得到方法,再针对某个对象调用。基本方法如下:

 Method[] getMethods();//只获取公共和父类中的方法。
 Method[] getDeclaredMethods();//获取本类中包含私有。
 Method   getMethod("方法名",参数.class);
 Object invoke(Object obj ,参数);//调用方法`

下面是一个示例:

import java.lang.reflect.*;
class Demo {
    public static void main(String[] args) throws Exception {
        String s = "qwe";// 获取String的类对象
        Class c = String.class;// 获取String类的charAt方法
        Method method = c.getMethod("charAt", int.class);
        // 通过方法的反射获取第1个位置的字符
        char ch = (char)meto k(s,1);      
    System.out.println(ch); //结果为1we

六.总结

1)、需要获得java类的各个组成部分,首先需要获得类的Class对象,获得Class对象的三种方式:
Class.forName(classname) 用于做类加载
obj.getClass() 用于获得对象的类型
类名.class 用于获得指定的类型,传参用

2)、反射类的成员方法:
Class clazz = Person.class;
Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});
method.invoke();

3)、反射类的构造函数:
Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,…})
con.newInstance(params…)

4)、反射类的属性:
Field field = clazz.getField(fieldName);
field.setAccessible(true);
field.setObject(value);
反射一共有三种方式: 根据给定的类名、用于获得对象的类型、明确地获得某个类的Class对象
反射构造方法创建类中,构造函数有四种方式:无参、有参、多个参数、私有构造函数。

下面演示了的反射基本作用,它读取命令行参数指定的类名,然后打印这个类的所有的方法信息。

import java.lang.reflect*;
public class InvokeTester {
    public int add(int param1,int param2){
        return param1+param2;
    }
    public String echo(String message){
        return "hello:"+message;
    }
    public static void main(String[] args)throws Exception{
        /**
         * 采用反射机制创建示例对象和调用方法
         * 1.首先获取对应类的Class对象 2.再调用getMethod方法返回Method类型的方法对象
         * 3.在调用Method类型的方法对象的invoke方法来实现条用Method对象所实际对应的那个方法,
         *   即通过invoke可以实现对目标方法的调用
         * 
         */
        Class<?> classtype =  InvokeTester.class;
        Object invokeTester = classtype.newInstance();
        Method addMethod = classtype.getMethod("add", new Class[]{int.class,int.class});
        Object result = addMethod.invoke(invokeTester, new Object[]{1,2});
        System.out.println((Integer)result);
        Method echoMethod = classtype.getMethod("echo", new Class[]{String.class});
        Object result2 = echoMethod.invoke(invokeTester, new Object[]{"Tom"});
        System.out.println((String)result2);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值