JAVA反射机制及CLASS.FORNAME的作用及含义

本文深入探讨Java反射机制,介绍如何利用反射API获取类信息及动态创建对象。文章讲解Class类的作用,展示不同方式获取Class对象的方法,并给出实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近由于工作上需要,对reflection做了一番了解,以下是学习总结,有不少内容是借鉴的,但已无法找到源文出处,还请原文作者见谅。

 

 

Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class

的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields

和methods的所有信息,并可于运行时改变fields内容或唤起methods。

 

Java为什么能够支持Reflection?答案是Java运行时仍然拥有类型信息,它包含了这个类一切:它有哪些字段、哪些方法,各是何种保护级别等等,还有这个类依赖于哪些类。在Java中,类信息以对象的形式存放,这些对象是一种元对象,它们的类型就是Class。拥有了这些信息,无论是动态创建对象还是调用某些方法都是轻而易举的。在C 中,通过RTTI(运行时类型识别),我们也可以知道类的一些信息,但为什么C 中却没有Reflection,原因是类型信息不完整。RTTI这个名字本身就告诉我们,C 的类型信息是用来进行类型识别的,因此,它也不需要其它额外的信息。并不是C 无法做到这一点,而是C 不希望给用户增加额外的负担。有所得,必然有所失,因此,C 放弃了元对象。关于这一点,C 之父Bjarne Stroustrup在他的《C 语言的设计与演化》的14.2.8节中进行了深入的讨论。

 

 

“Class”class


众所周知Java有个Object class,是所有Java classes的继承根源,其内声明了数个应该在所

有Java class中被改写的methods:hashCode()、equals()、clone()、toString()、

getClass()等。其中getClass()返回一个Class object。

Class class十分特殊。它和一般classes一样继承自Object,其实体用以表达Java程序运行时

的classes和interfaces,也用来表达enum、array、primitive Java types

(boolean, byte, char, short, int, long, float, double)以及关键词void。当一

个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产

生一个Class object。如果您想借由“修改Java标准库源码”来观察Class object的实际生成

时机(例如在Class的constructor内添加一个println()),不能够!因为Class并没有

public constructor。

 

 

 

Class是Reflection故事起源。针对任何您想探勘的class,唯有先为它产生一个Class

object,接下来才能经由后者唤起为数十多个的Reflection APIs。这些APIs将在稍后的探险

活动中一一亮相。

#001 public final

#002 class Class<T> implements java.io.Serializable,

#003 java.lang.reflect.GenericDeclaration,

#004 java.lang.reflect.Type,

#005 java.lang.reflect.AnnotatedElement {

#006 private Class() {}

#007 public String toString() {

#008 return ( isInterface() ? "interface " :

#009 (isPrimitive() ? "" : "class "))

#010 + getName();

#011 }

...

图1:Class class片段。注意它的private empty ctor,意指不允许任何人经由编程方式产生Class object。是的,其object 只能由

JVM 产生。

 

 

“Class” object的取得途径

Java允许我们从多种管道为一个class生成对应的Class object。图2是一份整理。

Class object 诞生管道示例

 

运用getClass()

注:每个class 都有此函数

String str = "abc";

Class c1 = str.getClass();

 

 

运用 Class.getSuperclass()

Button b = new Button();

Class c1 = b.getClass();

Class c2 = c1.getSuperclass();

 

运用static methodClass.forName()

(最常被使用)

Class c1 = Class.forName ("java.lang.

String");

Class c2 = Class.forName ("java.awt.Button");

Class c3 = Class.forName ("java.util.

LinkedList$Entry");

Class c4 = Class.forName ("I");

Class c5 = Class.forName ("[I");

 

运用 .class 语法

Class c1 = String.class;

Class c2 = java.awt.Button.class;

Class c3 = Main.InnerClass.class;

Class c4 = int.class;

Class c5 = int[].class;

 

 

 


 

Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段


Class aClass = Class.forName(xxx.xx.xx);
Object anInstance = aClass.newInstance();


Class.forName("").newInstance()返回的是object

但是创建实例时有个限制,你的class构造函数不能包括参数,而且你需要自己来手工cast实例

 

 

用时:实例:

 

  protected final static String CLASS_TEST = "Test";

 protected final static String CLASS_PROBLEM = "Problem";

 protected final static String CLASS_PARAMETER = "Parameter";

 

 

 

 

 getProblem(vx, vy){

Object      result;

        result = Class.forName(CLASS_PROBLEM).newInstance();

........

 } 

 

 getParameters(){

 

        Object      result;

        result = Class.forName(CLASS_PARAMETER).newInstance();

........

 

 }

 

 

 buildTest(){

 

   String error_msg = (String) invokeMethod(

        Class.forName(CLASS_TEST).newInstance(), 

        "add", 

        new Class[]{

          Class.forName(CLASS_PROBLEM), 

          Class.forName(CLASS_PARAMETER)},

        new Object[]{

          getProblem(vx, vy), 

          getParameters()});

 

 } 

 

 

 

 

 protected Object invokeMethod(Object o, String name, Class[] paramClasses, Object[] paramValues) {

    Method      m;

    Object      result;

 

    result = null;

 

    try {

      m      = o.getClass().getMethod(name, paramClasses);

      result = m.invoke(o, paramValues);

    }

    catch (Exception e) {

      e.printStackTrace();

      result = null;

    }    

    return result;

  }

 

 

 

 

class Test{

public static model train_model(problem prob, parameter param)

}

 

class Problem{

...........

}

 

Parameter{

...............

}

 

 

附:

大家或许有些疑问,jdbc连接数据库时,有的写法是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?


Class.forName(xxx.xx.xx) 返回的是一个类,
.newInstance() 后才创建一个对象

Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段

在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的Driver类的代码都必须类似如下:
public class MyJDBCDriver implements Driver {
static {
DriverManager.registerDriver(new MyJDBCDriver());
}
}

所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值