黑马程序员13_反射机制

 反射


 

知识点一:反射机制概述

  • 反射的引入:

Object obj = new Student();

 若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:

 1、若编译和运行类型都知道,使用 instanceof判断后,强转

 2、编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的真实信息,这时就必须使用反射了。

 3、要是想得到对象真正的类型,就得使用反射。

    简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。

  • 反射机制的优点与缺点:  

为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,静态编译:在编译时确定类型,绑定对象,即通过。动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。

它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

Class类

Class类概述:

     Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。而Java程序中的各个Java类,虽然内容不同,但是,它们的特征相同,譬如,都有方法,有字段,有父类,有包。因此它们也属于同一类事物,可以用Class类来描述这类事物, Class类描述了类的名字,类的访问属性,类所属于的包名,字段名称的列表、方法名称的列表,等等。

2、字节码只被装载一次,而它构造的实例对象的构造方法被调用了多次。用如下代码更进一步说明Class的实例是什么?是一份字节码,一个类在虚拟机中通常只有一份字节码。

3、加载了字节码,并调用了其getMethods之类的方法,但是没有看到类的静态代码块被执行,只有在第一个实例对象被创建时,这个静态代码才会被执行。准确的说,静态代码块不是在类加载时被调用的,而是第一个实例对象被创建时才执行的。


 

知识点一:获得Class类对象,即一个具体java类(Person)的字节码

每个类被加载器加载后,系统会为该类生成对应的Class对象,通过Class对象可以访问到JVM中的这个类。

  • 3种方式:

1、类名.class,如:Person.class

2、使用Class类的Class.forName(String className)静态方法,className表示全限定名.如String的全限定名:java.lang.String;

3、调用某个对象的getClass()方法。如,Person p = new Person(),p.getClass()


 

知识点二:通过字节码获得对象、构造函数、方法、属性、主函数、类加载器

  • 1、通过字节码获得构造方法:

步骤:

1、得到某个类所有的构造方法:

例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

2、得到某一个构造方法(获得方法时要用到类型,由参数确定具体的一个类型):

例子:  Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

 

  • 2、通过类的字节码获得该类的实例对象:

思想:先得到类所需的一个构造函数字节码,再运用字节码newInstance()方法传入参数,new出一个对象实例

步骤:

1、得到某一个构造方法:

Constructor constructor =  Class.forName(“java.lang.String”).getConstructor(StringBuffe r.class);

2、运用得到的构造函数创建实例对象:

 String str = (String)constructor.newInstance(new StringBuffer("abc"));

 

  • 3、通过类的字节码获得该类的一个方法并应用

思想:先得到类的方法字节码,再运用字节码.get()方法传入对象,执行该对象的方法

步骤:

1、得到类中的某一个方法:

例子:Method charAt = Class.forName"java.lang.String").getMethod("charAt", int.class);

2、调用方法(invoke):

通常方式:str.charAt(1)

反射方式: charAt.invoke(str, 1) 

如果传递给Method对象的方法的第一个参数为null,说明该Method对象对应的是一个静态方法。

 

  • 4、通过类的字节码获得该类的属性

思想:先得到属性Filed字节码,再运用get()方法传入对象得到该对象的属性值

步骤:

 

1、类属性的字节码:

2、获得具体对象的public属性值(属性调用对象):

3、获得具体对象的private属性值(属性调用对象):

例子:

class ReflectPoint
    {	private int x ;
    	public int y ;
    	public point(int x,int y)
    	{
    		this.x = x;
    		this.y = y;
    	}
    }
    类属性的字节码:
    例子:
    ReflectPoint point = new ReflectPoint(1,7);
	Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
    System.out.println(y);//输出public int point.y,也就是说的是类point的属性y
    获得具体对象的public属性值(属性调用对象):
    System.out.println(y.get(point));//输出的是7
    获得具体对象的private属性值(属性调用对象):
    Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
    //编译报错,不能访问私有属性
    正确做法:
	Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
	x.setAccessible(true);
	System.out.println(x.get(point));

  

  

  • 5、通过类的字节码获得该类的主方法并调用

思想:先得到主属性的字节码,再运用Invoke()方法传入字符串数组参数调用

步骤:

1、得到得到主属性的字节码

Method mMain = clazz.getMethod("main", String[].class);

2、调用

mMain.invoke(null,new Object[]{new String[]{"aaa","bbb"}});

 

posted @ 2014-03-16 00:06  让痛苦变成美好的回忆  阅读(151)  评论(0编辑  收藏  举报