A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 史小兵 中级黑马   /  2012-9-15 23:08  /  1515 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

感觉张老师讲的反射的那块,有点难懂,谁能给我讲下,最好有例子,

评分

参与人数 1技术分 +1 收起 理由
田建 + 1 新手鼓励!

查看全部评分

5 个回复

倒序浏览

一、基础知识  
    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));
   }}


评分

参与人数 1技术分 +1 收起 理由
田建 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 黄敏 于 2012-9-16 08:44 编辑

lz  希望你要搞清楚,你看到张老师的反射视频  你只要知道 反射的原理,什么事反射,反射是用来干什么的  在什么时候用到就行了,后面学到框架的时候你就会恍然大悟了
回复 使用道具 举报
本帖最后由 佟亚鹏 于 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,需要反射字段就先获得这个字段,然后再某个对象上设值,修改值,等等,脑海中有这个过程反射就很容易了解了,给你几个例子

通过反射把某个对象身上的值改掉

  1. public static void main(String[] args) throws Exception {  
  2.   //new出测试的对象
  3.   ReflectPoint p1 = new ReflectPoint(520,909);
  4.   //获得ReflectPoint类的成员变量y
  5.   Field field = ReflectPoint.class.getDeclaredField("x");
  6.   //私有成员默认是不可访问的,要设置为可以访问
  7.   field.setAccessible(true);
  8.   //得到p1对象,字段y的值
  9.   System.out.println("before: " + field.get(p1));
  10.   //把p1对象的x值修改为0
  11.   field.set(p1, 0);
  12.   System.out.println("after: " + field.get(p1));
  13. }
复制代码
一般的方法调用和反射调用
  1. public static void main(String[] args) throws Exception {  
  2.   String str = "黑马程序员训练营";
  3.   Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
  4.   //若要获得str的第二个字符,通常的方式为
  5.   System.out.println(str.charAt(2));
  6.   //通过反射的方式
  7.   System.out.println(charAt.invoke(str, 2));
  8. }
复制代码
通过这个构造方法获得对象
  1. public static void main(String[] args) throws Exception {  
  2.   //获得String类的以一个字符数组,构造出String对象的构造方法
  3.   Constructor c1 = String.class.getConstructor(char[].class);
  4.   char[] chars = {'黑','马','程','序','员','训','练','营'};
  5.   //调用c1的newInstance方法,把chars传递过去,返回的是Object,把它强制转换为String类型
  6.   String str1 = (String)c1.newInstance(chars);
  7.   System.out.println(str1);
  8. }
复制代码
上面程序的打印结果是:黑马程序员训练营


评分

参与人数 1技术分 +1 收起 理由
刘芮铭 + 1 赞一个!

查看全部评分

回复 使用道具 举报
Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造汽车······
  PS:怎么构造汽车都出来了啦啦·
回复 使用道具 举报
简单理解 第一个就是得出InvokeTester的类对象,用来操作这个类对象。这是java的反射机制,反射机制需要深刻理解,一句话两句话说不完的。
第二个通过反射出来的InovkeTester的类对象,调用newInstance()就是调用了InvokeTester没有参数的也是默认的构造函数,也就是初始化了 InvokeTester这个类。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马