黑马程序员技术交流社区
标题: 反射的问题 [打印本页]
作者: 史小兵 时间: 2012-9-15 23:08
标题: 反射的问题
感觉张老师讲的反射的那块,有点难懂,谁能给我讲下,最好有例子,
作者: 武庆东 时间: 2012-9-16 07:23
一、基础知识
1.Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。
2.Java程序中各个Java类,它们是属于同一类事物,可以用一个类来描述这类事物,这个类的名字就是Class。Class类描述了类的名字,类的访问属性,类所属于的包名,字段名称的列表、方法名称的列表,等等。反射就是把Java类中的各个成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造汽车,包等信心也用一个个的java类来表示,就像汽车是一个类,汽车中俄发动机,变速箱等等也是一个个的类。表示JAVA类的Class类显然要提供一些列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,他们是Field、Method、Constructor、Package等等。
3.一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。每个java类都是Class的一个实例对象,它们的内容不同,但是,它们的特征相同,比如都有方法,有字段等。
Class的实例对象代表内存中的字节码 :
二、字节码
总结:字节码:.class加载到内存中才可以创建对象 eg: Class s=Date.class//字节码
得到各个字节码对应实例的对象的三种方法:
1、类名.Class 例如:System.class;
2、对象名.Class 例如 new Date().getClass();
3、静态方法Class.forName("类名"); 例如,Class.forName("java.util.Date");
Class.forName()得到字节码的情况:
1、字节码已经加载到java虚拟机中,去得到字节码
2、java虚拟机中还没有生成字节码 用类加载器进行加载,加载的字节码缓冲到虚拟机中
九个预定义Class的实例对象(byte.class char.classshort.class int.class long.class float.class double.class boolean.class和void.class)八个基本数据类型和void类型
在源程序中出现的类型,都有各自的Class实例对象,如int[],void…
isPrimitive();判断是否是基本类型的字节码
int.class和Integer.class不是同一份字节码,Integer.TYPE,TYPE代表包装类对应的基本类的字节码 int.class==Integer.TYPE
数组类型的Class实例对象 用到Class的isArray()
总结:只要在源程序中国出现的类型,都有各自的Class实例对象,例如,int[],void…
构造方法的反射:
思路:class------>constructor-------->new object
Constructor类代表某个类中的一个构造方法
1.得到某个类所有的构造方法
Constructor[] constructors=Class.forName("java.lang.String").getConstructors();
2.得到某一个构造方法
Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
3.创建实例对象:
通常方式:String str=new String("abc");
反射方式:String str=(String)constructor.newInstance(newStringBuffer("abc"));
Constructorconstructor1=String.class.getConstructor(StringBuffer.class);
String str2=(String)constructor1.newInstance(newStringBuffer("abc"));
第一个StringBuffer代表选择哪个构造方法
第二个StringBuffer代表用这个StringBuffer时还要传递一个StringBuffer对象
Class.newInstance()方法:
例子:String obj=(String)Class.forName(“java.lang.String”).newInstance();
1. 该方法内部先得到猫人的构造方法,然后调用该方法创建实例对象。
2. 该方法内部代码,用到了缓存机制来保存默认构造方法的实例对象。
Field成员变量的反射:
Field类代表某个类的中一个成员变量
publicclass ReflectpoiSecond {
public intx;
privateinty;
public ReflectpoiSecond(int x, int y) {
super();
this.x = x;
this.y = y;
}}
--------------------------------------
publicclass ReflectTest {
public static void main(String[] args) throws Exception {
ReflectpoiSecondrs=new ReflectpoiSecond(4, 5);
Field fieldX=rs.getClass().getField("x");//getField提供可见的
Field fieldY=rs.getClass().getDeclaredField("y");//getDeclaredField得到声明过的属性
fieldY.setAccessible(true);//设置访问权限 ---暴力反射
System.out.println(fieldX.get(rs));
System.out.println(fieldY.get(rs));
}}
作者: 黄敏 时间: 2012-9-16 08:43
本帖最后由 黄敏 于 2012-9-16 08:44 编辑
lz 希望你要搞清楚,你看到张老师的反射视频 你只要知道 反射的原理,什么事反射,反射是用来干什么的 在什么时候用到就行了,后面学到框架的时候你就会恍然大悟了
作者: 佟亚鹏 时间: 2012-9-16 12:46
本帖最后由 佟亚鹏 于 2012-9-16 12:53 编辑
楼主理解反射,首先要了解反射的基石Class这个类
Java类用来描述一类事物的共性,而Class类就是描述了一个Java类的相关信息的,Class 类的实例表示正在运行的 Java 应用程序中的类和接口。Class类描述的信息有,类的名字、类的访问属性、类锁属于的包名、字段名称的列表、方法名称的列表等。在程序的运行期间,一旦我们想生成那个类的一个对象,用于执行程序的Java 虚拟机首先就会检查那个类型的Class 对象是否已经载入。如果没有载入,JVM 就会查找同名的.class 文件,并将其载入,一旦那个类型的Class 对象进入内存,就以它为模版来创建那一类型的所有对象。
以java.lang.String这个类来说明,有两种方式可以获得一个Java类的字节码,就是它对应的Class对象
第一种方法是通过类中一个静态的字段class获得 String.class
第二种方法是通过Java类的基类Object所提供的getClass方法 new String().getClass()
下面的这段代码打印的结果是true,表明每个Java类的字节码在程序中只有一份,这也很容易理解,有一份就够了
public static void main(String[] args) {
//通过上述的第一种方法拿到Class对象
Class c1 = String.class;
//通过上述的第二种方法拿到Class对象
Class c2 = new String().getClass();
//比较着两份字节码是否相同
System.out.println(c1 == c2);
}
Java 基本的 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也有自己的 Class 对象 ,这点Java api中Class类的描述中有提到,可以通过类型+.class获得,如int.class、void.class,这九个对象时Java预定义的Class实例对象。数组类型也有他们对象的Class对象,如:int[].class、long.class等。总的来说,只要源程序中出现的类型,都有各自的Class实例对象。
可以通过Class的静态方法forName获得一个Java对象,它的参数是一个Java类的完整名(包名+类名),如果找不到这个类会抛出ClassNotFound这个异常,
public static void main(String[] args) {
try {
//拿到java.lang.String这个类的字节码
Class strCls = Class.forName("java.lang.String");
//通过这份字节码创建一个String的对象
String str = (String) strCls.newInstance();
//打印String对象str的长度
System.out.println(str.length());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
上面这段代码演示了使用Class.ForName获得一个String对象,程序的打印结果为0,表示str不是一个空的引用,否则调用它的length方法就会抛出空指针异常,因此成功的拿到了一个String对象
Class类的常用方法有
public Annotation[] getAnnotations() 返回它所表示的类或接口上存在的所有注释的数组
public ClassLoader getClassLoader() 返回该类的类加载器
public Constructor<T> getConstructor(Class<?>... parameterTypes) 参数为构造函数的类型的Class,返回一个表示类的构造方法的 Constructor 对象
public Field getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。name 参数是一个 String,它指定所需字段的简称
public Method[] getMethods() 返回一个包含某些 Method 对象的数组
public boolean isArray() 判定此 Class 对象是否表示一个数组类
public boolean isInterface() 判定指定的 Class 对象是否表示一个接口类型。
public boolean isPrimitive() 判定指定的 Class 对象是否表示一个基本类型
。。。。。反射技术就是围绕这这些方法进行的。
现在知道了Class类用来是描述Java类的,java类中的,构造方法、包、成员变量、所拥有的方法,Java也都提供了相应的描述对象,分别是Constructor、Package、Field、Method,需要反射字段就先获得这个字段,然后再某个对象上设值,修改值,等等,脑海中有这个过程反射就很容易了解了,给你几个例子
通过反射把某个对象身上的值改掉
- public static void main(String[] args) throws Exception {
- //new出测试的对象
- ReflectPoint p1 = new ReflectPoint(520,909);
- //获得ReflectPoint类的成员变量y
- Field field = ReflectPoint.class.getDeclaredField("x");
- //私有成员默认是不可访问的,要设置为可以访问
- field.setAccessible(true);
- //得到p1对象,字段y的值
- System.out.println("before: " + field.get(p1));
- //把p1对象的x值修改为0
- field.set(p1, 0);
- System.out.println("after: " + field.get(p1));
- }
复制代码 一般的方法调用和反射调用- public static void main(String[] args) throws Exception {
- String str = "黑马程序员训练营";
- Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
- //若要获得str的第二个字符,通常的方式为
- System.out.println(str.charAt(2));
- //通过反射的方式
- System.out.println(charAt.invoke(str, 2));
- }
复制代码 通过这个构造方法获得对象- public static void main(String[] args) throws Exception {
- //获得String类的以一个字符数组,构造出String对象的构造方法
- Constructor c1 = String.class.getConstructor(char[].class);
- char[] chars = {'黑','马','程','序','员','训','练','营'};
- //调用c1的newInstance方法,把chars传递过去,返回的是Object,把它强制转换为String类型
- String str1 = (String)c1.newInstance(chars);
- System.out.println(str1);
- }
复制代码 上面程序的打印结果是:黑马程序员训练营
作者: 冯超 时间: 2012-9-16 16:04
Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造汽车······
PS:怎么构造汽车都出来了啦啦·
作者: 李健_8 时间: 2012-9-17 11:34
简单理解 第一个就是得出InvokeTester的类对象,用来操作这个类对象。这是java的反射机制,反射机制需要深刻理解,一句话两句话说不完的。
第二个通过反射出来的InovkeTester的类对象,调用newInstance()就是调用了InvokeTester没有参数的也是默认的构造函数,也就是初始化了 InvokeTester这个类。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |