Java 的反射机制

本贴最后更新于 2615 天前,其中的信息可能已经水流花落

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

JAVA 反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言,JAVA 有着一个非常突出的动态相关机制:Reflection,用在 Java 身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的 classes。换句话说,Java 程序可以加载一个运行时才得知名称的 class,获悉其完整构造(但不包括 methods 定义),并生成其对象实体、或对其 fields 设值、或唤起其 methods。

Java 反射机制主要提供了以下功能:
1 在运行时判断任意一个对象所属的类;
2 在运行时构造任意一个类的对象;
3 在运行时判断任意一个类所具有的成员变量和方法;
4 在运行时调用任意一个对象的方法;生成动态代理。

***java中反射的三种方法:***

1. 通过 Object 类的 getClass 方法来获取
java.lang.Object 中定义有 getClass 方法:public final Class getClass()
所有 Java 对象都具备这个方法,该方法用于返回调用该方法的对象的所属类关联的 Class 对象,例如:
Date date1 = new Date();
Date date2 = new Date();
Class c1 = date1.getClass();
Class c2 = date2.getClass();
System.out.println(c1.getName());
// java.util.Date
System.out.println(c1 == c2);
// true
上面的代码中,调用 Date 对象 date1 的 getClass 方法将返回用于封装 Date 类信息的 Class 对象。
这里调用了 Class 类的 getName 方法:public String getName(),这个方法的含义很直观,即返回所封装的类的名称。
需要注意的是,代码中的 date1 和 date2 的 getClass 方法返回了相同的 Class 对象(c1==c2 的值为 true)。这是因为,对于相同的类,JVM 只会载入一次,而与该类对应的 Class 对象也只会存在一个,无论该类实例化了多少对象。
另外,需要强调的是,当一个对象被其父类的引用或其实现的接口类型的引用所指向时,getClass 方法返回的是与对象实际所属类关联的 Class 对象。
例如:

List list = new ArrayList();
System.out.println(list.getClass().getName()); // java.util.ArrayList

上面的代码中,语句 list.getClass()方法返回的是 list 所指向对象实际所属类 java.util.ArrayList 对应的 Class 对象而并未 java.util.List 所对应的 Class 对象。有些时候可以通过这个方法了解一个对象的运行时类型,
例如:

HashSet set = new HashSet();
Iterator it = set.iterator();
System.out.println(it.getClass().getName()); //java.util.HashMap$KeyIterator

从代码可以看出,HashSet 的 iterator 方法返回的是实现了 Iterator 接口的 HashMap 内部类(KeyIterator)对象。
因为抽象类和接口不可能实例化对象,因此不能通过 Object 的 getClass 方法获得与抽象类和接口关联的 Class 对象。
2. 使用.class 的方式
使用类名加“.class”的方式即会返回与该类对应的 Class 对象。
例如:

Class clazz = String.class;
System.out.println(clazz.getName()); // java.lang.String

这个方法可以直接获得与指定类关联的 Class 对象,而并不需要有该类的对象存在。
3. 使用 Class.forName 方法
Class 有一个著名的 static 方法 forName:public static Class forName(String className) throws ClassNotFoundException
该方法可以根据字符串参数所指定的类名获取与该类关联的 Class 对象。如果该类还没有被装入,该方法会将该类装入 JVM。
该方法声明抛出 ClassNotFoundException 异常。顾名思义,当该方法无法获取需要装入的类时(例如,在当前类路径中不存在这个类),就会抛出这个异常。
例如,如果当前类路径中存在 Foo 类:

package org.whatisjava.reflect;
public class Foo {
public Foo() {
System.out.println("Foo()");
}
static {
System.out.println("Foo is initialized");
}
}
运行下面的代码:
Class clazz = Class.forName("org.whatisjava.reflect.Foo");
控制台会有如下输出:
Foo is initialized
Class.forName("org.whatisjava.reflect.Foo")首先会将 reflection.Foo 类装入 JVM,并返回与之关联的 Class 对象。JVM 装入 Foo 类后对其进行初始化,调用了其 static 块中的代码。需要注意的是:forName 方法的参数是类的完 整限定名(即包含包名)。
区别于前面两种获取 Class 对象的方法:使用 Class.forName 方法所要获取的与之对应的 Class 对象的类可以通过字符串的方式给定。该方法通常用于在程序运行时根据类名动态的载入该类并获得与之对应的 Class 对象。
通过上面的文章相信你对 java 的反射机制有了一定的认识,同时也对 java 中 Class 类的用法有了比较清晰的理解,在我们实际工作的过程中,我们不断的运用 java 知识来解决实际生活中的问题的时候我们就能对 java 反射机制有一个更深入的理解!

二、代码示例
1.ClassTest.java

[java] view plaincopy
/**

import java.lang.reflect.*;  
public class ClassTest1 {  
    public ClassTest1(){  

    }  
    public static void main(String[] args) throws Exception{  
        ClassTest1 test=new ClassTest1();  
        ClassTest1 test1=test.getClass().newInstance();  
        //test1=test;  
        test.printMessage();  
        test1.printMessage();  
        System.out.println(test.hashCode());  
        System.out.println(test1.hashCode());  

        Method[] method=test1.getClass().getMethods();  

        for(Method m :method){  
            System.out.println(m.getDeclaringClass());  
            System.out.println(m.getName());  
        }  
    }  
    public void printMessage(){  
        System.out.println("Created successful!");  
    }  
} 

运行结果:

[plain] view plaincopy
Created successful!
Created successful!
14576877
12677476
class ClassTest1
printMessage
class ClassTest1
main
class java.lang.Object
wait
class java.lang.Object
wait
class java.lang.Object
wait
class java.lang.Object
hashCode
class java.lang.Object
getClass
class java.lang.Object
equals
class java.lang.Object
toString
class java.lang.Object
notify
class java.lang.Object
notifyAll

2.TestClass.java

[java] view plaincopy

public class TestClass {  
    public static void main(String[] args)  
    {  
        try {  
            // 测试Class.forName()  
            Class testTypeForName = Class.forName("TestClassType");  
            System.out.println("testForName---" + testTypeForName);  
            // 测试类名.class  
            Class testTypeClass = TestClassType.class;  
            System.out.println("testTypeClass---" + testTypeClass);  
            // 测试Object.getClass()  
            TestClassType testGetClass = new TestClassType();  
            System.out.println("testGetClass---" + testGetClass.getClass());  
        } catch (ClassNotFoundException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
}  
class TestClassType {  
    // [构造函数](https://www.baidu.com/s?wd=%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPvuBuh7bmvF9PjIhuHmL0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3Erj03njTkPjn1P10LPH64nHTz)  
    public TestClassType() {  
        System.out.println("----[构造函数](https://www.baidu.com/s?wd=%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPvuBuh7bmvF9PjIhuHmL0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3Erj03njTkPjn1P10LPH64nHTz)---");  
    }  
    // 静态的参数初始化  
    static {  
        System.out.println("---静态的参数初始化---");  
    }  
    // 非静态的参数初始化  
    {  
        System.out.println("----非静态的参数初始化---");  
    }  
}

运行结果:
[plain] view plaincopy
---静态的参数初始化---
testForName---class TestClassType
testTypeClass---class TestClassType
----非静态的参数初始化---
----构造函数---
testGetClass---class TestClassType
分析:根据结果可以发现,三种生成的 Class 对象一样的,并且三种生成 Class 对象只打印一次“静态的参数初始化”。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖 • 1 关注
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 764 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 62 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 624 关注
  • 音乐

    你听到信仰的声音了么?

    60 引用 • 511 回帖 • 1 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    25 引用 • 191 回帖 • 16 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 588 回帖
  • 自由行
    10 关注
  • Hibernate

    Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。

    39 引用 • 103 回帖 • 709 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖 • 2 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 641 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    334 引用 • 323 回帖 • 2 关注
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 72 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 304 关注
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    55 引用 • 85 回帖 • 1 关注
  • 职场

    找到自己的位置,萌新烦恼少。

    127 引用 • 1705 回帖
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖 • 67 关注
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 21 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    209 引用 • 358 回帖 • 2 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 483 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖
  • V2Ray
    1 引用 • 15 回帖 • 1 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 9 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    53 引用 • 40 回帖 • 1 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    86 引用 • 122 回帖 • 625 关注