`

Java反射

    博客分类:
  • JDK
阅读更多

文章分类:Java编程

Java反射机制是 Java 语言被视为准动态语言的关键性质。 J ava反射机制的核心就是允许在运行时通过 Java Reflection APIs 来取得已知名字的 class 类的相关信息,动态地生成此类,并调用其方法或修改其域(甚至是本身声明为 private 的域或方法)。

也许你使用Java 已经很长时间了,可是几乎不会用到 Java 反射机制。你会嗤之以鼻地告诉我, Java 反射机制没啥用。或许在 J2EE J2SE 等平台, Java 反射机制没啥用(具体我也不了解,不多做评论),但是在 Android 应用开发中,该机制会带给你许多惊喜。

如果熟悉Android ,那么你应该知道, Google 不知出于什么原因,在系统源码中一些类或方法中经常加上“ @hide ”注释标记。它的作用是使这个方法或类在生成 SDK 时不可见,因此由此注释的东西,你在编译期是不可见的。这就出现了一些问题。一些明明可以访问的东西编译期却无法访问了!这使得你的程序有些本来可以完成的功能无法编译通过。

当然,有一种办法是自己去掉Android 源码中的所有“ @hide ”标记,然后重新编译一份自己的 SDK 。另一种办法就是使用 Java 反射机制。当然,你还可以利用反射来访问存在访问限制的方法和修改其域。不过这种使用方法比较特殊,我们在文章的最后单独讨论。

从Class类说起

如果你使用Java ,那么你应该知道 Java 中有一个 Class 类。 Class 类本身表示 Java 对象的类型,我们可以通过一个 Object (子)对象的 getClass 方法取得一个对象的类型,此函数返回的就是一个 Class 类。当然,获得 Class 对象的方法有许多,但是没有一种方法是通过 Class 的构造函数来生成 Class 对象的。

也许你从来没有使用过Class 类,也许你曾以为这是一个没什么用处的东西。不管你以前怎么认为, Class 类是整个 Java 反射机制的源头。一切关于 Java 反射的故事,都从 Class 类开始。

因此,要想使用Java 反射,我们首先得到 Class 类的对象。下表列出了几种得到 Class 类的方法,以供大家参考。

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 method

Class.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;

运用

primitive wrapper classes

的TYPE 语法

Class c1 = Boolean.TYPE;

Class c2 = Byte.TYPE;

Class c3 = Character.TYPE;

Class c4 = Short.TYPE;

Class c5 = Integer.TYPE;

Class c6 = Long.TYPE;

Class c7 = Float.TYPE;

Class c8 = Double.TYPE;

Class c9 = Void.TYPE;

获取一些基本信息

在我们得到一个类的Class 类对象之后, Java 反射机制就可以大施拳脚了。首先让我们来了解下如何获取关于某一个类的一些基本信息。

Java class  内部模块

Java class  内部模块说明

相应之Reflection API,多半为Class methods。

返回值类型(return type)

package

class隶属哪个package

getPackage()

Package

import

class导入哪些classes

无直接对应之API。 可间接获取。

 

modifier

class(或methods, fields)的属性

int getModifiers()

Modifier.toString(int)

Modifier.isInterface(int)

int

String

bool

class name or interface name

class/interface

名称getName()

String

type parameters

参数化类型的名称

getTypeParameters()

TypeVariable <Class>[]

base class

base class(只可能一个)

getSuperClass()

Class

implemented interfaces

实现有哪些interfaces

getInterfaces()

Class[]

inner classes

内部classes

getDeclaredClasses()

Class[]

outer class

如果我们观察的class  本身是inner classes,那么相对它就会有个outer class。

getDeclaringClass()

Class

上表中,列出了一些Java class 内部信息的获取方式。所采用的方法几乎都是调用 Class 对象的成员方法(由此你就可以了解到 Class 类的用处了吧)。当然,表中所列出的信息并不是全部,有很大一部分没有列出,你可以通过查阅 Java 文档得到更全面的了解。另外,下面将重点介绍一下类的构造函数、域和成员方法的获取方式。

类中最重要的三个信息

如果要对一个类的信息重要性进行排名的话,那么这三个信息理应获得前三的名次。它们分别是:构造函数、成员函数、成员变量。

也许你不同意我的排名,没关系。对于Java 反射来说,这三个信息与之前介绍的基本信息相比较而言,有着本质的区别。那就是,之前的信息仅仅是只读的,而这三个信息可以在运行时被调用(构造函数和成员函数)或者被修改(成员变量)。所以,我想无可否认,至少站在 Java 反射机制的立场来说,这三者是最重要的信息。

下面,让我们分别了解一下这三个重要信息的获取方式。另外,我们将在后面的章节,详细介绍他们的调用方式或者修改方式。

构造函数

如果我们将Java 对象视为一个二进制的生活在内存中生命体的话,那么构造函数无疑可以类比为 Java 对象生命体的诞生过程。我们在构造函数调用时为对象分配内存空间,初始化一些属性,于是一个新的生命诞生了。

Java是纯面向对象的语言, Java 中几乎所有的一切都是类的对象,因此可想而知构造函数的重要性。

Java反射机制能够得到构造函数信息实在应该是一件令人惊喜的事情。正因为此,反射机制实质上才拥有了孵化生命的能力。换句话言之,我们可以通过反射机制,动态地创建新的对象。

获取构造函数的方法有以下几个:

Constructor getConstructor(Class[] params) 

Constructor[] getConstructors()

Constructor getDeclaredConstructor(Class[] params) 

Constructor[] getDeclaredConstructors()

我们有两种方式对这四个函数分组。

首先可以由构造函数的确定性进行分类。我们知道,一个类实际上可以拥有很多个构造函数。那么我们获取的构造函数是哪个呢?我们可以根据构造函数的参数标签对构造函数进行明确的区分,因此,如果我们在Java 反射时指定构造函数的参数,那么我们就能确定地返回我们需要的那个“唯一”的构造函数。 getConstructor(Class[] params)  getDeclaredConstructor(Class[] params) 正是这种确定唯一性的方式。但是,如果我们不清楚每个构造函数的参数表,或者我们出于某种目的需要获取所有的构造函数的信息,那么我们就不需要明确指定参数表,而这时返回的就应该是构造函数数组,因为构造函数很可能不止一个。 getConstructors() getDeclaredConstructors() 就是这种方式。

另外,我们还可以通过构造函数的访问权限进行分类。在设计类的时候,我们往往有一些构造函数需要声明为“private ”、“ protect ”或者“ default ”,目的是为了不让外部的类调用此构造函数生成对象。于是,基于访问权限的不同,我们可以将构造函数分为 public 和非 public 两种。

getConstructor(Class[] params)  getConstructors() 仅仅可以获取到public 的构造函数,而 getDeclaredConstructor(Class[] params)  getDeclaredConstructors() 则能获取所有(包括public 和非 public )的构造函数。

成员函数

如果构造函数类比为对象的诞生过程的话,成员函数无疑可以类比为对象的生命行为过程。成员函数的调用执行才是绝大多数对象存在的证据和意义。Java 反射机制允许获取成员函数(或者说成员方法)的信息,也就是说,反射机制能够帮助对象践行生命意义。通俗地说, Java 反射能使对象完成其相应的功能。

和获取构造函数的方法类似,获取成员函数的方法有以下一些:

Method getMethod(String name, Class[] params)

Method[] getMethods()

Method getDeclaredMethod(String name, Class[] params) 

Method[] getDeclaredMethods() 

其中需要注意,String name 参数,需要写入方法名。关于访问权限和确定性的问题,和构造函数基本一致。

成员变量

成员变量,我们经常叫做一个对象的域。从内存的角度来说,构造函数和成员函数都仅仅是Java 对象的行为或过程,而成员变量则是真正构成对象本身的细胞和血肉。简单的说,就是成员变量占用的空间之和几乎就是对象占用的所有内存空间。

获取成员变量的方法与上面两种方法类似,具体如下:

Field getField(String name)

Field[] getFields()

Field getDeclaredField(String name)

Field[] getDeclaredFields()

其中,String name 参数,需要写入变量名。关于访问权限和确定性的问题,与前面两例基本一致。

让动态真正动起来

在本文的一开始就说,Java 反射机制是 Java 语言被视为准动态语言的关键性质。如果 Java 反射仅仅能够得到 Java 类(或对象)运行时的信息,而不能改变其行为和属性,那么它当然算不上“动态”。百度了一把何谓“动态语言”,解释如下: 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。 由此看来,Java 确实不能算作“动态语言”。但是和 C C++ 等纯静态语言相比, Java 语言允许使用者在运行时 加载、探知、使用编译期间完全未知的classes ,所以我们说Java 是“准动态”语言。

细心地读者 可能已经发现,在“类中最重要的三个信息”一节中,我们获取的信息其实都是属于类的,而不是对象。对于类的信息提取,其实并不涉及到对象内存,在程序编译 完成的那一刻起,一切都已经是确定的了。因此,它并不能算“动态”。而如何对对象内存进行操作和访问,才是“动”的真正含义。

说了这么多,关键还在于如何利用反射让Java 真正动起来。下面我将按照创生、行为与属性三个方面来介绍反射机制是如何让 Java 动的。

创生

不知是否本性使然,人类偏爱于思索起源与终结的话题。如果将程序类比于一个二进制的世界的话,那么我们程序员则是这个世界的上帝。我们掌控着这个世界的起源和终结,熟悉世界中一草一木的属性和所有生灵的习性。现在就让我们开始创世纪吧!

在 “构造函数”那一小节中,我们列出了获取构造函数的四种方法。这四种方法的返回值不知是否引起了各位的注意,那就是 Constructor 类。Constructor 就类比于女娲吹给泥人的那一口真气,有了它,一个生命才真正出现。

Constructor 支持泛型,也就是它本身应该是 Constructor <T>。这个类有一个 public 成员函数, newInstance ( Object...  args) ,其中args 为对应的参数。我们正是通过它来实现创生的过程。

行为

行为践行着生命的意义,而众多事物的行为才得以构成整个世界的运转。尽管道家的老子主张“无为而治”,宣扬“ 圣人处无为之事,行不言之教 ”,但那是因为他本身就是 “无”的信仰者(“道”即“无”)。我们是唯物主义的信徒,所以必然要以“有”为价值。那么,在二进制的世界里,我们如何调用Java 对象的行为呢?

同样,我们首先回顾“成员函数”小节中四种方法的返回值。对,那就是 Method 类。此类有一个public 成员函数, Object  invoke ( Object  receiver,  Object...  args) 。我们能很好理解此函数的第二个参数 args ,它代表这个方法所需要接收的参数。也许大家对第一个参数 receiver 还存在疑惑之处。这得从编程语言的发展历程讲起。

如果你关注几种主流编程语言的起源,那么你能有这样的印象:C 从汇编而来, C++ C 而来,而 Java C/C++ 而来。有这样一种印象就足够了。从这样的发展史我们可以看出, C++ Java 这两种面向对象的编程语言都是从面向过程的 C 语言基础上发展而来的。 OOP 是一种思想,它本身与编程语言无关。也就是说,我们用 C 也能写出面向对象的程序,这也是 C++ Java 能够以 C 为基础的根本所在。然而, C 无法实现类似 object.method() 这种表现形式,因为 C 语言的结构体中并不支持函数定义。那么我们用 C 实现 OOP 的时候,如何调用对象的方法呢?

本质上说,object.method() 这种调用方式是为了表明具体 method() 的调用对象。而 invoke ( Object  receiver,  Object...  args) 的第一个参数正是指明调用对象。在C++ 中, object.method() 其实是有隐含参数的,那就是 object 对象的指针, method 原型的第一个参数其实是 this 指针,于是原型为 method(void* this)

这样一溯源,也许你更清楚了 Object  receiver 参数的含义,或许更迷糊了?不管怎样,历史就是如此,只不过我个人能力有限,说不清楚而已。

另外需要注意的是,如果某个方法是Java 类的静态方法,那么 Object  receiver 参数可以传入null ,因为静态方法不从属于对象。

属性

同样是人类,令狐冲和岳不群是如何被区分开的?那是因为他们有着不同的属性。同样,同一个类可以生成多个对象,几个同类型的对象之间如何区分?属性起着决定性的作用。说到这里,想起一个科幻故事。人体瞬移机,作用的根本原理就是人进入A 位置,被完全扫描之后,再在 B 位置重新组成它的细胞、血肉等属性,从而完全创造出另一个一模一样的人。当然,这是唯物主义的极致,它假设了只要一切物质相同,连记忆和灵魂都不会出现偏差,另外还存在伦理的问题,例如 A 位置的人会被销毁掉吗?

尽管这是一个科幻,但是在程序的世界里,我们早已经用上了这类似幻想的技术。Java 中如何远程传递一个对象?我们已经使用上了 Java 对象序列化的接口。不仅如此,利用序列化接口,我们甚至可以将一个生命保存起来,在需要的时候将它复活,这就是对象的持久化。不得不感慨,在程序的世界里,我们就是上帝啊!

对象序列化如此强大,那么它的本质是什么呢?它的工作原理是怎样的呢?简单的说,对象序列化的本质就是属性的序列化。原理就是我们崇尚的唯物主义,如果同一个类的两个对象所有属性值都完全相同,那么我们可以认为这是同一个对象。

说了这么多,只是想说明一件事情,属性对于对象而言是多么的重要。那么如何读写对象中属性的值呢?回顾获取属性信息的方法返回值类型,那是 Field Field 类有两个 public 方法,分别对应读与写,它们是:

Object  get(Object object)

v oid  set(Object object, Object value)

object参数需要传入的对象,原理类似于成员方法需要指明对象一样。如果是静态属性,此值同样可以为 null

分享到:
评论

相关推荐

    java反射 java反射 java反射java反射

    Java反射是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并操作类的对象。在Java中,反射机制提供了强大的能力,包括在运行时检查类的结构、创建对象实例、调用方法以及访问和修改字段值。...

    JAVA反射机制的入门代码

    Java反射机制是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用私有方法...

    java反射,获取所有属性、方法以及List集合类

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建对象、获取类...

    JAVA 反射机制应用

    Java反射机制是Java语言提供的一种强大功能,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类是java.lang.Class,它代表了运行时的类信息。通过Class对象,我们...

    java 反射得到某个方法

    在本文中,我们将深入探讨如何使用Java反射来获取并执行某个特定的方法。 首先,我们需要了解Java反射的基本概念。`java.lang.Class`类是反射的核心,它代表了Java中的每一个类。我们可以通过以下方式获取到一个...

    Java反射性能测试分析

    ### Java反射性能测试分析 #### 引言 Java反射机制是Java编程语言中一个强大的特性,它允许程序在运行时动态地访问、检测和修改类、接口、字段和方法等对象。然而,反射操作通常会引入额外的开销,这在性能敏感的...

    Java反射机制总结

    ### Java反射机制总结 #### 反射的概念与起源 反射的概念最早由Smith于1982年提出,指的是程序能够访问、检测并修改其自身状态或行为的能力。这一概念的提出迅速引起了计算机科学领域的广泛关注,并在之后的研究中...

    Java反射经典实例

    Java反射是Java编程语言中的一个强大特性,它允许运行时的程序访问并操作类、接口、字段和方法等信息,即使这些信息在编译时并未明确知晓。在Java中,反射通常通过`java.lang.Class`类和相关的API来实现。本实例将...

    java反射-英文版反射规范

    ### Java反射机制详解 #### 一、概述 Java反射机制是一种强大的编程技术,它允许运行时检查类的信息并操作对象的内部结构。本篇将基于Sun公司的官方文档《Java™ Core Reflection API and Specification》(1997年...

    反射实例-JAVA反射机制

    ### 反射实例—JAVA反射机制 #### 一、反射概念及原理 反射在计算机科学领域,特别是程序设计中,是指程序有能力访问、检测和修改其自身的结构和行为。这一概念最早由Smith于1982年提出,并迅速应用于各种编程语言...

    java反射.pdf

    ### Java反射机制详解 #### 一、什么是Java反射? Java反射是Java编程语言的一个特性,它允许运行时检查和操作程序结构(类、字段、方法等)。反射的主要用途包括但不限于:动态实例化对象、访问私有成员、调用...

    java 反射 调用私有方法(有参数私有方法)获取私有属性值

    Java反射是Java语言提供的一种强大的动态类型特性,它允许程序在运行时检查类、接口、字段和方法的信息,并且能够动态地创建对象和调用方法。这个能力使得开发者可以突破静态类型的束缚,实现一些在编译时期无法完成...

    java反射源代码

    Java反射是Java编程语言中的一个强大特性,它允许在运行时检查类、接口、字段和方法的信息,并且能够在运行时动态地创建对象和调用方法。这个特性使得Java具有高度的灵活性,尤其在处理框架、插件系统以及元数据驱动...

    java 反射机制例子

    ### Java反射机制详解 #### 一、反射的基本概念与历史背景 反射的概念最早由Smith在1982年提出,其核心思想是程序有能力访问、检测甚至修改自身的状态和行为。这种能力一经提出,迅速成为了计算机科学领域的研究...

    java 反射 报错 no such method exception

    ### Java反射机制与NoSuchMethodException详解 在Java编程中,反射是一种强大的机制,允许程序在运行时检查和修改自身结构和行为。然而,当开发者尝试使用反射调用一个不存在的方法时,便会遇到`java.lang....

    java反射获取所有属性,获取所有get方法,包括子类父类

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建动态代理等。...

    利用java反射将json字符串转成对象.zip

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在给定的“利用java反射将json字符串转成对象”的主题中,我们将深入探讨如何借助反射机制将JSON...

    Java反射机制Demo

    ### Java反射机制详解 #### 一、什么是Java反射机制? Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的...

    北大青鸟java反射机制

    Java反射机制是Java编程语言中的一个强大工具,它允许程序在运行时检查并操作类、接口、字段和方法等对象。在"北大青鸟java反射机制"的学习资料中,我们将会深入探讨这一核心特性。 首先,我们要理解反射的核心概念...

    java反射

    ### Java反射机制详解 #### 一、引言 在Java编程语言中,反射(Reflection)是一种强大的工具,它允许程序在运行时访问类的信息,并能够动态地创建对象、调用方法以及获取字段值等。这种能力对于框架设计、代码...

Global site tag (gtag.js) - Google Analytics