您的位置:首页 > 编程语言 > Java开发

Reflect----Java反射基础总结

2015-09-23 20:23 381 查看
------- android培训java培训、期待与您交流! ----------

Reflect—————java反射基础

1定义:java程序运行状态时,对于任意一个类,都能够知道这个类的所有属性和方法(包括私有),对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态类型信息及动态调用对象方法的功能叫做java反射机制;

2理解:

1以前都是在编译期间玩类和对象,现在转到运行期间来玩类和对象;因为java程序在运行时由类加载器将.class文件       加载到内存中(方法区),并为其创建与之对应的Class对象,而我们要通过这个Class对象来使用反射功能;

2Class对象(字节码文件对象):

2.1他将类型信息用自己的数据所描述,即,这个对象也有构造其,成员变量和成员方法,而且这些分别又被封装成为对象,这些对象对应的就是被加载类的字段,构造器,方法;

2.2从上面的分析来看,我们操作字节码文件对象就可以获取到一个类的所有信息,并可以用这些功能来创建对象,改变属性,所以操作步骤为:

2.21:获取字节码文件对象

2.22:用字节码文件对象获取的被加载类字段,构造器,方法的封装类型(Constructor,Filed,Method)

2.23:再通过以上三个类来判断,操作这个被加载类

3产生Class对象的时机,即加载器合适加载这个类:

    1,当使用new关键字创建对象时      2调用类中的静态属性,或者为其赋值(final)以及调用静态方法

    3,使用反射创建某个类或借口
        4初始化某个类的子类

    5,使用java.exw来运行某个主类(tomcat,批量处理文件)

3.2获得一个类的字节码文件对象的方式:

1类型.class;   2 Object.getClass();   3Class.forName("全路径");

4类加载的组成以及工作原理:

4.1根类加载器     --Bootstarp  classloader   ---负责加载jdk核心文类     ----->   jdk/jre/lib/rt.jar

4.2扩展类加载器 --Extension classloader    ---负责加载jdk核心文类     ----->   jdl/jre/lib.ext

4.3系统类加载器 --System     classloader    ---负责加载jdk核心文类     ----->   java 命令指定的.class文件(我们自定义的)

4.4执行步骤:加载(创建Class对象),连接(验证,准备,解析一些准备动作),初始化

5代码演示

package com.itheima.reflect;
/**
* 被反射操作的类
*/
public class Room {
private String roomName;
private float  price;
private int roomNum;
private boolean isUse;
public Room() {

}
private Room(String roomName, float price) {
this.roomName = roomName;
this.price = price;
}
@Override
public String toString() {
return "Room["+roomName+price+"]";
}

//这个教室有多少个人
private void printHotWater(int x){
System.out.println("这个教室有"+x+"个人");
}
//getter and setter
为了不占屏幕,此处省略了代码

}
5.2
package com.itheima.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectBase {

public static void main(String[] args) throws Exception {
//被操作的字节码对象
Class<?> clazz = Class.forName("com.itheima.reflect.Room");
/**
* 构造器
* */
// 获得指定参数列表的构造器
Constructor<?> con = clazz.getDeclaredConstructor(String.class,float.class);
//获得访问权限,通过私有构造方法构造出一个Room对象
con.setAccessible(true);
Object room= con.newInstance("深圳",56f);

System.out.println(room);
/**
* 方法
* */
//调用set方法,改变一个字段的值,param1:方法名,param2:这个方法指定的参数列表的参数类型
Method method=clazz.getDeclaredMethod("setRoomName", String.class);
method.invoke(room, "你好,黑马");
System.out.println(method.toGenericString());
/**
* 字段
* */
//再次反射得到这个改变字段的值,并检验
Field changeFiled=clazz.getDeclaredField("roomName");
changeFiled.setAccessible(true);
//反向读取,反向理解,这个对象的这个方法
Object value=changeFiled.get(room);
//校验
System.out.println(value);

}
}

5.3运行结果

Room[深圳56.0]
public void com.itheima.reflect.Room.setRoomName(java.lang.String)
你好,黑马

6练习:向ArrayList<Integer>添加一个String对象;

<span style="font-family:SimHei;font-size:12px;">/**
* 分析:1泛型只是给编译器使用的一个安全机制,实际源代码中添加的是Object类型的元素
*       要想添加泛型外的元素必须考虑从运行期下手
* 	 2通过反射获取到ArrayList添加元素的方法,并执行那个方法
*/
public class ArrayListTest {
public static void main(String[] args) throws Exception {
ArrayList<Integer> intArr=new ArrayList<>();
//获取字节码文件对象
Class clazz=intArr.getClass();
//获取添加元素的方法
Method m=clazz.getMethod("add",Object.class);
//操作add方法,放入值
m.invoke(intArr, "哈哈,我是字符串");
//校验
System.out.println(intArr.toString());
}
}</span>


运行结果:
      [哈哈,我是字符串]
总结:

1形象理解,如果说在编译阶段,基类是Object的话,那么在运行阶段,基类就是Class字节码文件对象;

2反射带来的好处我还么有再身一步的去学习,但是有用过spring这个框架,工厂设计模式,反射的功能实现,我们只需要操作配置文件就可以了;还需要好好努力学习啊
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: