Java 的反射机制

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

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 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3190 引用 • 8214 回帖 • 1 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 584 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    85 引用 • 165 回帖 • 1 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    110 引用 • 54 回帖 • 1 关注
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    167 引用 • 1520 回帖
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    171 引用 • 512 回帖
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    91 引用 • 751 回帖 • 1 关注
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖 • 2 关注
  • 资讯

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

    55 引用 • 85 回帖
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 50 关注
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    407 引用 • 3578 回帖
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 34 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 15 关注
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    156 引用 • 3792 回帖
  • Hadoop

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

    86 引用 • 122 回帖 • 626 关注
  • WebSocket

    WebSocket 是 HTML5 中定义的一种新协议,它实现了浏览器与服务器之间的全双工通信(full-duplex)。

    48 引用 • 206 回帖 • 317 关注
  • Hibernate

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

    39 引用 • 103 回帖 • 715 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 635 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4601 回帖 • 699 关注
  • CodeMirror
    1 引用 • 2 回帖 • 129 关注
  • ngrok

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

    7 引用 • 63 回帖 • 626 关注
  • 倾城之链
    23 引用 • 66 回帖 • 138 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    313 引用 • 547 回帖
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 63 关注
  • 服务

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

    41 引用 • 24 回帖
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 745 关注