黑马程序员——JAVA笔记之Java反射

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

反射

反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。
反射的好处:大大的增强了程序的扩展性。
反射就是把java类中的各种成分映射成相应的java类(获取其中的变量,方法,构造方法,修饰符,包等信息)。用相应类的实例对象来表示,是Field、Method、Contructor、Package等等。
Field field;(字段)将字段封装成对象类型Field—–> getField();
Constructor cons;(构造函数)将构造函数封装成了对象类型Constructor——> getConstructor();
Method method;(其他方法)将其他方法封装成了对象类型 Method——–> getMethod();
一、Class类
Java程序中的各个java类属于同一类事物,描述这类事物的java类名就是class。
Class类代表java类,他的各个实例对象对应各个类在内存中的字节码。
字节码获得

1.  Class cls1 = str1.getClass();
2.  Class cls2 = String.class;
3.  Class cls3 = Class.forName("java.lang.String");

九个预定义Class实例对象
1、参看Class.isPrimitive()方法的帮助,是否为基本类型
2、Int.class==Integer.TYPE
3、Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。
数组类型的class实例对象
Class.isArray();
只有是在源程序中出现的类型,都有各自的Class实例对象 如:int[], void

二、Constructor类
得到某个类所有的构造方法:Constructor[] constructors = Class.forName(“java.lang.String”).getConStructors();
得到某个构造方法:Constructor[] constructors = Class.forName(“java.lang.String”).getConStructors(StringBuffer.class);
场景实例对象:
通常方式:String str = new String(new StringBuffer(“abc”));
反射方式:String str = (String)constructor.newInstance(new StringBuffer(“abc”));

Class.newInstance()方法:
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象,用到了缓存机制来保存默认构造方法的实例对象.

三、Field类
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
Array 允许在执行 get 或 set 访问操作期间进行扩展转换,但如果将发生收缩转换,则抛出一个 IllegalArgumentException。

//把换源代码中的”a”换成”b”;
ReflectPoint pt1 = new ReflectPoint(3,5);
changeStringValue(pt1);
System.out.println(pt1);

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



public class ReflectPoint {
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "itcast";
}

四、Method类
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
Method 允许在匹配要调用的实参与底层方法的形参时进行扩展转换;但如果要进行收缩转换,则会抛出 IllegalArgumentException。
Method charAt = Class.forNam(“java.lang.String”).getMethod(“charAt”, int.class);
调用方法:
通常方式:System.out.println(str.charAt());
反射方式:System.out.println(charAt.invoke(str, 1));

用反射的方式调用main
当不知道类的名字,就需要用反射的方式调用main。

String startingClassName = args[0];
        Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
        //mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});//把数组打包成另一个数组,拆包后就是一个数组
        mainMethod.invoke(null, (Object)new String[]{"111","222","333"});//告诉编译器不要拆包。

五、数组的反射
具有相同维数和元素类型的数组属于同一个类型,既具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
Arrays.asList()方法处理int[]和String[]时的差异。Array工具类用于完成对数组的反射操作。

六、反射的作用——实现框架功能
举例说明就是 一个人买的房子 这个房子就是框架,房子调用这个人买的东西(写的对象),这个人要装修房子,买锁……(人写的对象)也就是框架调用用户写的类,用户调用别人写的类(锁,门窗……)。
框架要解决的核心问题是要为各阶层客户提供服务,就需要:

Class.forName(classNameStr).getMethod(methodName).invoke(obj,Class)

因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象了,而要用反射方式来做

类加载器–ClassLoader
类加载器通常用来加载 *.class文件,

七、总结
反射的基本步骤:
1、获得Class对象,就是获取到指定的名称的字节码文件对象。
2、实例化对象,获得类的属性、方法或构造函数。
3、访问属性、调用方法、调用构造函数创建对象。
获取这个Class对象,有三种方式:
1:通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。

//1. 根据给定的类名来获得  用于类加载
String classname = "cn.itcast.reflect.Person";// 来自配置文件
Class clazz = Class.forName(classname);// 此对象代表Person.class

2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。

//2. 如果拿到了对象,不知道是什么类型   用于获得对象的类型
Object obj = new Person();
Class clazz1 = obj.getClass();// 获得对象具体的类型

前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。
3:使用的Class类中的方法,静态的forName方法。
指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。

//3. 如果是明确地获得某个类的Class对象  主要用于传参
Class clazz2 = Person.class;

反射的用法:
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);

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值