当前位置: 移动技术网 > IT编程>开发语言>Java > Java反射机制详解

Java反射机制详解

2019年07月22日  | 移动技术网IT编程  | 我要评论
本文较为详细的分析了java反射机制。分享给大家供大家参考,具体如下: 一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行

本文较为详细的分析了java反射机制。分享给大家供大家参考,具体如下:

一、预先需要掌握的知识(java虚拟机)

java虚拟机的方法区:

java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。方法区的主要作用是存储被装载的类 的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中。这些信息主要包括:

1、这个类型的全限定名

2、这个类型的直接超类的全限定名

3、这个类型是类类型还是接口类型

4、这个类型的访问修饰符

5、任何直接超接口的全限定名的有序列表

6、该类型的常量池

7、字段信息

8、方法信息

9、除了常量以外的所有类变量

10、一个到class类的引用

等等(读者可以参考《深入java虚拟机》这本书的叙述)

class类:

class类是一个非常重要的java基础类,每当装载一个新的类型的时候,java虚拟机都会在java堆中创建一个对应于新类型的class实例,该实例就代表此类型,通过该class实例我们就可以访问该类型的基本信息。上面说到在方法区中会存储某个被装载类的类型信息,我们就可以通过 class实例来访问这些信息。比如,对于上面说到的信息class中都有对应的方法,如下:

1、getname();这个类型的全限定名

2、getsuperclass();这个类型的直接超类的全限定名

3、isinterface();这个类型是类类型还是接口类型

4、gettypeparamters();这个类型的访问修饰符

5、getinterfaces();任何直接超接口的全限定名的有序列表

6、getfields();字段信息

7、getmethods();方法信息

等等(读者可以自己参看jdk帮助文档,得到更多的信息)

二、java反射详解

反射的概念:所谓的反射就是java语言在运行时拥有一项自观的能力,反射使您的程序代码能够得到装载到jvm中的类的内部信息,允许您执行程序时才得到需要类的内部信息,而不是在编写代码的时候就必须要知道所需类的内部信息,这使反射成为构建灵活的应用的主要工具。

反射的常用类和函数:java反射机制的实现要借助于4个类:class,constructor,field,method;其中class代 表的是类对象,constructor-类的构造器对象,field-类的属性对象,method-类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍class类中针对这三个元素的方法:

1、得到构造器的方法

constructor getconstructor(class[] params) -- 获得使用特殊的参数类型的公共构造函数,

constructor[] getconstructors() -- 获得类的所有公共构造函数

constructor getdeclaredconstructor(class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)

constructor[] getdeclaredconstructors() -- 获得类的所有构造函数(与接入级别无关)

2、获得字段信息的方法

field getfield(string name) -- 获得命名的公共字段

field[] getfields() -- 获得类的所有公共字段

field getdeclaredfield(string name) -- 获得类声明的命名的字段

field[] getdeclaredfields() -- 获得类声明的所有字段
3、获得方法信息的方法

method getmethod(string name, class[] params) -- 使用特定的参数类型,获得命名的公共方法

method[] getmethods() -- 获得类的所有公共方法

method getdeclaredmethod(string name, class[] params) -- 使用特写的参数类型,获得类声明的命名的方法

method[] getdeclaredmethods() -- 获得类声明的所有方法

应用反射的基本步骤:

1、获得你想操作的类的class对象;

方法一:classc=class.forname("java.lang.string") //这种方式获得类的class对象需要 包名.类名

方法二:对于基本数据类型可以用形如class c=int.class或class c=integer.type的语句

方法三:class c=myclass.class

2、调用class中的方法得到你想得到的信息集合,如调用getdeclaredfields()方法得到类的所有属性;

3、处理第2步中得到的信息,然后进行你想做的实际操作。

反射实例:

下面我将针对类的构造器、属性和方法分别举三个例子,向大家演示一下反射的应用过程。

1、构造器

步骤为:通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例

import java.lang.reflect.*; 
public class constructordemo{ 
  public constructordemo(){ } 
  public constructordemo(int a, int b){ 
   system.out.println("a="+a+"b="+b); 
  } 
  public static void main(string args[]){ 
    try { 
      class cls =class.forname("包名.constructordemo"); 
      class partypes[] =new class[2]; partypes[0] = integer.type;  
      partypes[1] =integer.type; 
      constructor ct=cls.getconstructor(partypes); 
      object arglist[] =new object[2]; 
      arglist[0] = newinteger(37); 
      arglist[1] = newinteger(47); 
      object retobj = ct.newinstance(arglist); 
     } catch (throwable e) {
      system.err.println(e);} 
     } 
  } 

2、属性

步骤为:通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值

import java.lang.reflect.*; 
public class fielddemo1{ 
 public double d; 
 public static void main(string args[]){ 
 try { 
  class cls = class.forname("fielddemo1"); 
  field fld = cls.getfield("d"); 
  fielddemo1 fobj = new fielddemo1(); 
  system.out.println("d = " + fobj.d); 
  fld.setdouble(fobj, 12.34); 
  system.out.println("d = " + fobj.d); 
 } catch (throwable e){ 
  system.err.println(e); } 
 } 
} 

3、方法

步骤为:通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法

//通过使用方法的名字调用方法 
import java.lang.reflect.*; 
public class methoddemo1{ 
 public int add(int a, int b){ 
 return a + b; 
 } 
 public static void main(string args[]){ 
  try { 
   class cls =class.forname("methoddemo1"); 
   class partypes[] = new class[2]; 
   partypes[0] = integer.type; 
   partypes[1] = integer.type; 
   method meth = cls.getmethod("add",partypes); 
   methoddemo1 methobj = new methoddemo1(); 
   object arglist[] = new object[2]; 
   arglist[0] = new integer(37); 
   arglist[1] = new integer(47); 
   object retobj= meth.invoke(methobj, arglist); 
   integer retval = (integer)retobj; 
   system.out.println(retval.intvalue()); 
  } catch (throwable e) { 
   system.err.println(e); 
  } 
 } 
}

三、java反射的应用(hibernate)

我们在第二部分中对java反射进行了比较系统的阐述,也举了几个简单的实例,下面我们就来讨论一下java反射的具体应用。前面我们已经知 道,java反射机制提供了一种动态链接程序组件的多功能方法,它允许程序创建和控制任何类的对象(根据安全性限制)之前,无需提前硬编码目标类。这些特 性使得反射特别适用于创建以非常普通的方式与对象协作的库。例如,反射经常在持续存储对象为数据库、xml或其它外部格式的框架中使用。下面我们就已 hibernate框架为例像大家阐述一下反射的重要意义。

hibernate是一个屏蔽了jdbc,实现了orm的java框架,利用该框架我们可以抛弃掉繁琐的sql语句而是利用hibernate中 session类的save()方法直接将某个类的对象存到数据库中,也就是所涉及到sql语句的那些代码hibernate帮我们做了。这时候就出现了 一个问题,hibernate怎样知道他要存的某个对象都有什么属性呢?这些属性都是什么类型呢?如此,它在向数据库中存储该对象属性时的sql语句该怎么构造呢?解决这个问题的利器就是我们的java反射!

下面我们以一个例子来进行阐述,比如我们定义了一个user类,这个user类中有20个属性和这些属性的get和set方法,相应的在数据库中 有一个user表,这个user表中对应着20个字段。假设我们从user表中提取了一条记录,现在需要将这条记录的20个字段的内容分别赋给一个 user对象myuser的20个属性,而hibernate框架在编译的时候并不知道这个user类,他无法直接调用myuser.getxxx或者 myuser.setxxx方法,此时就用到了反射,具体处理过程如下:

1、根据查询条件构造preparedstament语句,该语句返回20个字段的值;

2、hibernate通过读取配置文件得到user类的属性列表list(是一个string数组)以及这些属性的类型;

3、创建myuser所属类的class对象c;c=myuser.getclass();

4、构造一个for循环,循环的次数为list列表的长度;

4.1、读取list[i]的值,然后构造对应该属性的set方法;

4.2、判断list[i]的类型xxx,调用preparedstament语句中的getxxx(i),进而得到i出字段的值;

4.3、将4.2中得到的值作为4.1中得到的set方法的参数,这样就完成了一个字段像一个属性的赋值,如此循环即可;

看到了吧,这就是反射的功劳,如果没有反射很难想象如果完成同样的功能会有多么难!但是反射也有缺点,比如性能比较低、安全性比较复杂等,这里就不在讨论这些东西,感兴趣的读者可以在网上找到答案,有很多的!

希望本文所述对大家java程序设计有所帮助。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网