欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java反射简易教程

程序员文章站 2024-04-01 22:02:28
关于java反射,我们需要弄懂以下几个问题: 反射是什么?反射有什么用?怎么用反射? 下面我们来一一进行讲解: 一、反射是什么? reflection的意思是“反射...

关于java反射,我们需要弄懂以下几个问题:

反射是什么?反射有什么用?怎么用反射?

下面我们来一一进行讲解:

一、反射是什么?

reflection的意思是“反射、映象、倒影”,用在java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性及方法;对于任何一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象的方法的功能称为java的反射机制。

1.自省(introspection)vs.反射(reflection)

反射经常和自省弄混,为了区别,我们先看看两者的详细定义:

自省(introspection):

introspectionistheabilityofaprogramtoexaminethetypeorpropertiesof

anobjectatruntime.

反射(reflection):

reflectionistheabilityofaprogramtoexamineandmodifythestructure

andbehaviorofanobjectatruntime.

从上述定义,我们可以看出,自省是反射的子集。部分语言支持自省,但是不支持反射,比如c++。

2.自省示例vs.反射示例

自省示例:instanceof操作符用于判断一个对象是否属于一个特定的类。

if(obj instanceof dog) {
  dog d = (dog)obj;
  d.bark();
}

反射实例: class.forname()方法返回了一个具体类/接口的对象,当然参数需要指定为特定的类名。

// with reflection
class <!--?--> c = class.forname("classpath.and.classname");
object dog = c.newinstance();
 
method m = c.getdeclaredmethod("bark", new class<!--?-->[0]);
m.invoke(dog);

二、 为什么需要反射?

java反射在框架开发中尤为重要。有些情况下,我们要使用的类在运行时才会确定,这个时候我们不能在编译期就使用它,因此只能通过反射的形式来使用在运行时才存在的类(该类符合某种特定的规范,例如jdbc),这是反射用得比较多的场景。

编译时我们对于类的内部信息不可知,必须得到运行时才能获取类的具体信息。比如orm框架,在运行时才能够获取类中的各个属性,然后通过反射的形式获取其属性名和值,存入数据库。

反射机制提供的功能:

在运行时判断任意一个对象所属的类; 在运行时构造任意一个类的对象; 在运行时判断任意一个类所具有的成员变量和方法; 在运行时调用任意一个对象的方法。通过反射甚至可以调用到private的方法; 在运行时修改构造函数,变量和方法的访问权限。

解耦

假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译

在对类的调用和实例化的时候,通过在配置文件中配置相应的类名,在程序中读取类名,然后通过反射技术在程序中加载和实例化,如常见的数据库驱动程序类,为了达到不依赖特定数据库驱动类,将用到的数据库驱动类名放到配置文件中(常用的有xml文件、properties文件和文本文件),然后在程序中加载驱动,来实现对数据库的解耦,也就是说只要修改配置文件,就可以方便地更改数据库类型。

例如, spring使用如下的bean配置:

<bean class="com.programcreek.foo" id="someid">
<property name="somefield" value="somevalue">
</property></bean>

当spring在处理时,会使用class.forname(string),同时参数为"com.xxx.foo"用于实例化这个class。同时,使用反射设置去用于设置特定的值。

这种机制同样也用于servlet的web应用:

<code><code><code><code><code><code><servlet>
<servlet name="">someservlet 
<servlet>com.programcreek.whyreflectionservlet</servlet>
<servlet data-filtered="filtered"></servlet></servlet></servlet></code></code></code></code></code></code>

三、反射api

java反射相关类

java反射所需要的类并不多,主要有java.lang.class类java.lang.reflect包中的field、constructor、method、array类,简单说明如下所示:

class类:class类的实例表示正在运行的java应用程序中的类和接口。field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和field类不同,field类封装了反射类的属性,而constructor类则封装了反射类的构造方法。method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。这个类不难理解,它是用来封装反射类方法的一个类。array类:提供了动态创建数组和访问数组的静态方法。该类中的所有方法都是静态方法。

class

类是程序的一部分,每个类都有一个class对象。换言之,每当编写并且编译了一个新类,就会产生一个class对象。

class没有公共构造方法。class对象是在加载类时由java虚拟机以及通过调用类加载器中的defineclass方法自动构造的,因此不能显式地声明一个class对象

class是reflection的起源。要想操纵;类的属性和方法,都必须从获取classobject开始。

class的方法

getname():获得类的完整名字。getfields():获得类的public类型的属性。getdeclaredfields():获得类的所有属性。getmethods():获得类的public类型的方法。getdeclaredmethods():获得类的所有方法。getmethod(stringname,class[]parametertypes):获得类的特定方法,name参数指定方法的名字,–parametertypes参数指定方法的参数类型。getconstrutors():获得类的public类型的构造方法。getconstrutor(class[]parametertypes):获得类的特定构造方法,parametertypes参数指定构造方法的参数类型。newinstance():通过类的不带参数的构造方法创建这个类的一个对象。

constructor

获得类的构造方法

constructorgetconstructor(class[]params)–获得使用特殊的参数类型的公共构造函数constructor[]getconstructors()–获得类的所有公共构造函数constructorgetdeclaredconstructor(class[]params)–获得使用特定参数类型的构造函数(与接入级别无关)constructor[]getdeclaredconstructors()–获得类的所有构造函数(与接入级别无关)

field

获取类定义变量

fieldgetfield(stringname)–获得命名的公共字段field[]getfields()–获得类的所有公共字段fieldgetdeclaredfield(stringname)–获得类声明的命名的字段field[]getdeclaredfields()–获得类声明的所有字段

method

获取类定义方法

methodgetmethod(stringname,class[]params)–使用特定的参数类型,获得命名的公共方法method[]getmethods()–获得类的所有公共方法methodgetdeclaredmethod(stringname,class[]params)–使用特写的参数类型,获得类声明的命名的方法method[]getdeclaredmethods()–获得类声明的所有方法

四、反射怎么用?

上一章我们讲解了java反射api,那么这一章我们将用一些代码实例来展示如何使用这些反射api。

example1:从对象中获取类名

package com.longluo.java.interview.reflection;
 
public class reflectionhelloworld {
 
  public static void main(string[] args) {
    foo f = new foo();
    system.out.println(f.getclass().getname());
  }
}
 
class foo {
  public void print() {
    system.out.println("abc");
  }
}

输出:

com.longluo.java.interview.reflection.foo

example 2: 调用未知对象的方法

想象我们不知道一个对象的类型,但是通过反射,我们可以使用这个对象并且找到这个对象是否有个方法名叫print并且调用它,如下所示:

package com.longluo.java.interview.reflection;
 
import java.lang.reflect.method;
 
public class reflectionhelloworld {
 
  /*
   * public static void main(string[] args) { foo f = new foo();
   * system.out.println(f.getclass().getname()); }
   */
 
  public static void main(string[] args) {
    foo f = new foo();
    method method;
    try {
      method = f.getclass().getmethod("print", new class<!--?-->[0]);
      method.invoke(f);
    } catch (exception e) {
      e.printstacktrace();
    }
  }
 
}
 
class foo {
  public void print() {
    system.out.println("abc");
  }
}

输出:

abc

example 3: 从class实例创建对象

package com.longluo.java.interview.reflection;
 
import java.lang.reflect.method;
 
public class reflectionhelloworld {
 
  public static void main(string[] args) {
    // create instance of "class"
 
    class<!--?--> c = null;
 
    try {
      c = class.forname("com.longluo.java.interview.reflection.foo");
 
    } catch (exception e) {
      e.printstacktrace();
    }
 
    // create instance of "foo"
    foo f = null;
    try {
      f = (foo) c.newinstance();
    } catch (exception e) {
      e.printstacktrace();
    }
    f.print();
  }
 
}
 
class foo {
  public void print() {
    system.out.println("abc");
  }
}

example 4: 获取构造器并创建实例

package com.longluo.java.interview.reflection;
import java.lang.reflect.constructor;
public class reflectionhelloworld4 {
  public static void main(string[] args) {
    // create instance of "class"
    class<!--?--> c = null;
    try {
      c = class.forname("com.longluo.java.interview.reflection.foo4");
    } catch (exception e) {
      e.printstacktrace();
    }
    // create instance of "foo"
    foo4 f1 = null;
    foo4 f2 = null;
    // get all constructors
    constructor<!--?--> cons[] = c.getconstructors();
    try {
      f1 = (foo4) cons[0].newinstance();
      f2 = (foo4) cons[1].newinstance("abc");
    } catch (exception e) {
      e.printstacktrace();
    }
    f1.print();
    f2.print();
  }
}
class foo4 {
  string s;
  public foo4() {
  }
  public foo4(string s) {
    this.s = s;
  }
  public void print() {
    system.out.println(s);
  }
}

输出:

null
abc

另外,你可以使用class实例并获取实现的接口,父类,声明的方法等。

example 5: 通过反射修改数组大小

package com.longluo.java.interview.reflection;
import java.lang.reflect.array;
public class reflectionhelloworld5 {
  public static void main(string[] args) {
    int[] intarray = { 1, 2, 3, 4, 5 };
    int[] newintarray = (int[]) changearraysize(intarray, 10);
    print(newintarray);
    string[] atr = { "a", "b", "c", "d", "e" };
    string[] str1 = (string[]) changearraysize(atr, 10);
    print(str1);
  }
  // change array size
  public static object changearraysize(object obj, int len) {
    class<!--?--> arr = obj.getclass().getcomponenttype();
    object newarray = array.newinstance(arr, len);
    // do array copy
    int co = array.getlength(obj);
    system.arraycopy(obj, 0, newarray, 0, co);
    return newarray;
  }
  // print
  public static void print(object obj) {
    class<!--?--> c = obj.getclass();
    if (!c.isarray()) {
      return;
    }
    system.out.println("\narray length:" + array.getlength(obj));
    for (int i = 0; i < array.getlength(obj); i++) {
      system.out.print(array.get(obj, i) + " ");
    }
  }
}

输出:

array length:10
1 2 3 4 5 0 0 0 0 0
array length:10
a b c d e null null null null null

五、 总结

本文只是对java反射很小的内容进行了讲解,大家有兴趣了解更多信息可以从网络查找资料。

以上就是本文关于java反射简易教程的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:关于java反射机制 你需要知道的事情java的rtti和反射机制代码分析等,有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!