Java 的反射机制

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

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

    3168 引用 • 8207 回帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    4 引用 • 55 回帖 • 10 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 429 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    129 引用 • 793 回帖 • 1 关注
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 5 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 352 关注
  • 笔记

    好记性不如烂笔头。

    304 引用 • 777 回帖
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    330 引用 • 614 回帖
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 383 回帖 • 5 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 635 关注
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 452 关注
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    261 引用 • 662 回帖
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 89 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    313 引用 • 1667 回帖 • 1 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1083 引用 • 3461 回帖 • 286 关注
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    19 引用 • 23 回帖 • 685 关注
  • Sym

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

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

    523 引用 • 4581 回帖 • 690 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    370 引用 • 1215 回帖 • 582 关注
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    15 引用 • 7 回帖 • 10 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    21 引用 • 140 回帖 • 28 关注
  • Markdown

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

    163 引用 • 1450 回帖
  • 知乎

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

    10 引用 • 66 回帖 • 1 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    198 引用 • 120 回帖
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 153 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    106 引用 • 152 回帖
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 290 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 370 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    10 引用 • 54 回帖 • 126 关注