理解Java反射机制

  转载请注明出处,谢谢!

一、Java反射简介

  • 什么是反射?

  Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对学习框架技术有很大的帮助。

  首先,我们先区分下编译和运行:编译时刻加载类是静态加载类、运行时刻加载类是动态加载类

  大家都知道,要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载。Java类如果不被Java虚拟机加载,是不能正常运行的。现在我们运行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类的已经被加载了。

  Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。

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

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

  • Java反射有什么作用?

  假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。

  Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。

  • 得到反射的三种方法?

  类.class;
  对象.getClass();
  Class.forName("类的全称"),不仅表示了,类的类类型,还代表了动态加载类

  • 一个类里都有什么?

  类名、类修饰符、包信息、父类、实现的接口、属性、方法、构造器(构造方法)、注解多部分组成。

  • 属性有几部分组成?

  修饰符、类型、属性名、属性值四部分组成。

  • 方法有几部分组成?

  修饰符、返回类型、方法名、参数列表、方法体、返回值

  • 构造器几部分组成?

  修饰符、构造器名称(类名)、参数列表、方法体

二、Class类简介

  • java.lang.Class类介绍

要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。 

  Class类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(booleanbytecharshortintlongfloatdouble)和关键字void也表示为Class对象。

  Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。

  在面向对象的世界里,万事万物皆对象。(java语言中,静态的成员、普通数据类型除外)

  那么类是不是对象呢?类是(哪个类的对象呢?)谁的对象呢?

  类是对象,类是java.lang.Class类的实例对象

  • java.lang.Class类的API介绍

方法摘要
<U> Class<? extends U>
asSubclass(Class<U> clazz)
          强制转换该 Class 对象,以表示指定的 class 对象所表示的类的一个子类。
 T cast(Object obj)

          将一个对象强制转换成此 Class 对象所表示的类或接口。
 boolean desiredAssertionStatus()

          如果要在调用此方法时将要初始化该类,则返回将分配给该类的断言状态。
static Class<?> forName(String className)

          返回与带有给定字符串名的类或接口相关联的 Class 对象。
static Class<?> forName(String name,
boolean initialize, ClassLoader loader)


          使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。
<A extends Annotation>

A
getAnnotation(Class<A> annotationClass)

          如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
 Annotation[] getAnnotations()

          返回此元素上存在的所有注释。
 String getCanonicalName()

          返回 Java Language Specification 中所定义的底层类的规范化名称。
 Class<?>[] getClasses()

          返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class
对象所表示的类的成员的所有公共类和接口。
 ClassLoader getClassLoader()

          返回该类的类加载器。
 Class<?> getComponentType()

          返回表示数组组件类型的 Class
 Constructor<T> getConstructor(Class<?>... parameterTypes)

          返回一个 Constructor 对象,它反映此 Class
对象所表示的类的指定公共构造方法。
 Constructor<?>[] getConstructors()

          返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class
对象所表示的类的所有公共构造方法。
 Annotation[] getDeclaredAnnotations()

          返回直接存在于此元素上的所有注释。
 Class<?>[] getDeclaredClasses()

          返回 Class 对象的一个数组,这些对象反映声明为此 Class
对象所表示的类的成员的所有类和接口。
 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

          返回一个 Constructor 对象,该对象反映此 Class
对象所表示的类或接口的指定构造方法。
 Constructor<?>[] getDeclaredConstructors()

          返回 Constructor 对象的一个数组,这些对象反映此 Class
对象表示的类声明的所有构造方法。
 Field getDeclaredField(String name)

          返回一个 Field 对象,该对象反映此 Class
对象所表示的类或接口的指定已声明字段。
 Field[] getDeclaredFields()

          返回 Field 对象的一个数组,这些对象反映此 Class
对象所表示的类或接口所声明的所有字段。
 Method getDeclaredMethod(String name, Class<?>... parameterTypes)

          返回一个 Method 对象,该对象反映此 Class
对象所表示的类或接口的指定已声明方法。
 Method[] getDeclaredMethods()

          返回 Method 对象的一个数组,这些对象反映此 Class
对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
 Class<?> getDeclaringClass()

          如果此 Class 对象所表示的类或接口是另一个类的成员,则返回的 Class
对象表示该对象的声明类。
 Class<?> getEnclosingClass()

          返回底层类的立即封闭类。
 Constructor<?> getEnclosingConstructor()

          如果该 Class 对象表示构造方法中的一个本地或匿名类,则返回 Constructor
对象,它表示底层类的立即封闭构造方法。
 Method getEnclosingMethod()

          如果此 Class 对象表示某一方法中的一个本地或匿名类,则返回 Method
对象,它表示底层类的立即封闭方法。
 T[] getEnumConstants()

          如果此 Class 对象不表示枚举类型,则返回枚举类的元素或 null。
 Field getField(String name)

          返回一个 Field 对象,它反映此 Class
对象所表示的类或接口的指定公共成员字段。
 Field[] getFields()

          返回一个包含某些 Field 对象的数组,这些对象反映此 Class
对象所表示的类或接口的所有可访问公共字段。
 Type[] getGenericInterfaces()

          返回表示某些接口的 Type,这些接口由此对象所表示的类或接口直接实现。
 Type getGenericSuperclass()

          返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的
Type
 Class<?>[] getInterfaces()

          确定此对象所表示的类或接口实现的接口。
 Method getMethod(String name, Class<?>... parameterTypes)

          返回一个 Method 对象,它反映此 Class
对象所表示的类或接口的指定公共成员方法。
 Method[] getMethods()

          返回一个包含某些 Method 对象的数组,这些对象反映此 Class
对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
 int getModifiers()

          返回此类或接口以整数编码的 Java 语言修饰符。
 String getName()

          以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或
void)名称。
 Package getPackage()

          获取此类的包。
 ProtectionDomain getProtectionDomain()

          返回该类的 ProtectionDomain
 URL getResource(String name)

          查找带有给定名称的资源。
 InputStream getResourceAsStream(String name)

          查找具有给定名称的资源。
 Object[] getSigners()

          获取此类的标记。
 String getSimpleName()

          返回源代码中给出的底层类的简称。
 Class<? super T> getSuperclass()

          返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的
Class
 TypeVariable<Class<T>>[] getTypeParameters()

          按声明顺序返回 TypeVariable 对象的一个数组,这些对象表示用此
GenericDeclaration 对象所表示的常规声明来声明的类型变量。
 boolean isAnnotation()

          如果此 Class 对象表示一个注释类型则返回 true。
 boolean isAnnotationPresent(Class<? extends
Annotation> annotationClass)


          如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
 boolean isAnonymousClass()

          当且仅当底层类是匿名类时返回 true
 boolean isArray()

          判定此 Class 对象是否表示一个数组类。
 boolean isAssignableFrom(Class<?> cls)

          判定此 Class 对象所表示的类或接口与指定的 Class
参数所表示的类或接口是否相同,或是否是其超类或超接口。
 boolean isEnum()

          当且仅当该类声明为源代码中的枚举时返回 true。
 boolean isInstance(Object obj)

          判定指定的 Object 是否与此 Class
所表示的对象赋值兼容。
 boolean isInterface()

          判定指定的 Class 对象是否表示一个接口类型。
 boolean isLocalClass()

          当且仅当底层类是本地类时返回 true
 boolean isMemberClass()

          当且仅当底层类是成员类时返回 true
 boolean isPrimitive()

          判定指定的 Class 对象是否表示一个基本类型。
 boolean isSynthetic()

          如果此类是复合类,则返回 true,否则 false
 T newInstance()

          创建此 Class 对象所表示的类的一个新实例。
 String toString()

          将对象转换为字符串。

三、示例分析

  • Class类的使用

 package me.reflect;

 /**
* Class类的使用
* @author Administrator
*
*/
public class ClassDemo1 {
public static void main(String[] args) {
// Foo的实例对象如何表示
Foo foo1 = new Foo();// foo1就表示出来了.
// Foo这个类 也是一个实例对象,Class类的实例对象,如何表示呢
// 任何一个类都是Class的实例对象,这个实例对象有三种表示方式 // 第一种表示方式--->实际在告诉我们任何一个类都有一个隐含的静态成员变量class
Class c1 = Foo.class; // 第二中表达方式 已经知道该类的对象通过getClass方法
Class c2 = foo1.getClass(); /*
* 官网 c1 ,c2 表示了Foo类的类类型(class type) 万事万物皆对象, 类也是对象,是Class类的实例对象
* 这个对象我们称为该类的类类型
*
*/
// 不管c1 or c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象
System.out.println(c1 == c2); // 第三种表达方式
Class c3 = null;
try {
c3 = Class.forName("com.imooc.reflect.Foo");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(c2 == c3); // 我们完全可以通过类的类类型创建该类的对象实例---->通过c1 or c2 or c3创建Foo的实例对象
try {
Foo foo = (Foo) c1.newInstance();// 需要有无参数的构造方法
foo.print();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} class Foo { void print() {
System.out.println("foo");
}
}

view code

  • 方法的反射

 public static void printClassMethodMessage(Object obj) {
// 要获取类的信息 首先要获取类的类类型
Class c = obj.getClass();// 传递的是哪个子类的对象 c就是该子类的类类型
// 获取类的名称
System.out.println("类的名称是:" + c.getName());
/**
* Method类,方法对象 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有的public的函数,包括父类继承而来的
* getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
*/
Method[] ms = c.getMethods();// c.getDeclaredMethods()
for (int i = 0; i < ms.length; i++) {
// 得到方法的返回值类型的类类型
Class returnType = ms[i].getReturnType();
System.out.print(returnType.getName() + " ");
// 得到方法的名称
System.out.print(ms[i].getName() + "(");
// 获取参数类型--->得到的是参数列表的类型的类类型
Class[] paramTypes = ms[i].getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
  • 成员变量的反射

 public static void printFieldMessage(Object obj) {
Class c = obj.getClass();
/**
* 成员变量也是对象 java.lang.reflect.Field Field类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
*/
// Field[] fs = c.getFields();
Field[] fs = c.getDeclaredFields();
for (Field field : fs) {
// 得到成员变量的类型的类类型
Class fieldType = field.getType();
String typeName = fieldType.getName();
// 得到成员变量的名称
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName);
}
}
  • 构造函数的反射

 public static void printConMessage(Object obj) {
Class c = obj.getClass();
/*
* 构造函数也是对象 java.lang.Constructor中封装了构造函数的信息
* getConstructors获取所有的public的构造函数 getDeclaredConstructors得到所有的构造函数
*/
// Constructor[] cs = c.getConstructors();
Constructor[] cs = c.getDeclaredConstructors();
for (Constructor constructor : cs) {
System.out.print(constructor.getName() + "(");
// 获取构造函数的参数列表--->得到的是参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
  • Java类加载机制

 package me.reflect.dynamic;

 public interface OfficeAble {

     public void start();
} package me.reflect.dynamic; public class Word implements OfficeAble { public void start() {
System.out.print("word start.....");
}
} package me.reflect.dynamic; public class Excel implements OfficeAble{ @Override
public void start() {
System.out.print("Excel start....");
} } package me.reflect.dynamic; /**
* Java动态加载类测试类
* @author Administrator
*
*/
public class Office { public static void main(String[] args) {
//new创建对象是静态加载类,在编译的时刻就需要加载所有可能使用到的类
//通过动态加载类可以解决该问题
if("Word".equals(args[0])) {
Word w = new Word();
w.start();
}
if("Excel".equals(args[0])) {
Excel e = new Excel();
e.start();
}
}
} package me.reflect.dynamic; public class OfficeBetter { public static void main(String[] args) {
try {
//动态加载类,在运行时刻加载类
Class c = Class.forName(args[0]);
//通过类类型创建该类对象
OfficeAble oa = (OfficeAble) c.newInstance();
oa.start();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}

参考文章:

  http://blog.csdn.net/misswwg/article/details/51659812

  http://blog.csdn.net/qq_35685189/article/details/52182198

理解Java反射机制的更多相关文章

  1. Java复习总结——详细理解Java反射机制

    反射是什么 反射的作用用一句简单的话来讲就是可以对代码进行操作的代码,这个特性经常在被用于创建JavaBean中,通常造轮子的人会用到这个特性,而应用程序员用到这个特性的场景则较少. 能够分析类能力的 ...

  2. Java知识总结:Java反射机制(用实例理解)

    概念理解: 反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来 实现对自己行为的描述( self-representation )和检测( examination) ,并能 ...

  3. java反射机制 + Method.invoke解释 getMethod + 反射理解

    功能: 通过读取另一个Dll去创建一个控件(Form,Button,TextBox,DataGridView),然后对当中一些属性进行检查. 创建控件的大致流程是,Assembly->Modul ...

  4. (转)JAVA反射机制理解

    JAVA反射机制: 通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们. 理论的东东太多也没 ...

  5. JAVA反射机制及理解

    JAVA反射 往往当我们面对一项新的知识时,我们往往需要知道三个方面,它是什么,它能做什么,它比原有知识强在哪里,我们该怎么使用它.当你能够解决这些问题时,便意味着你已经对这项知识入门了. 首先: 反 ...

  6. Java反射机制的浅显理解(这篇文章还没写好,留个草稿给自己看的)

    目前只是有一个大概的理解,先把自己感觉容易立即的概念放这里,等以后结合实际工作理解深刻了再来补充. 一.什么是Java反射机制?(多种定义) 1. JAVA反射机制是在运行状态中,对于任意一个类,都能 ...

  7. java反射机制的进一步理解

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

  8. java反射机制的粗略理解

    java反射机制: 涉及的对象:Class, Object, 函数:Class类:[forName(String className):static:getClass():public],Object ...

  9. Java反射机制专题

    ·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方 ...

随机推荐

  1. 聊聊HTML5中的Web Notification桌面通知

    有的时候我们会在桌面右下角看到这样的提示: 这种桌面提示是HTML5新增的 Web Push Notifications 技术. Web Notifications 技术使页面可以发出通知,通知将被显 ...

  2. 一文彻底搞懂Java中的环境变量

    一文搞懂Java环境变量 记得刚接触Java,第一件事就是配环境变量,作为一个初学者,只知道环境变量怎样配,在加上各种IDE使我们能方便的开发,而忽略了其本质的东西,只知其然不知其所以然,随着不断的深 ...

  3. spark 源码分析之七--Spark RPC剖析之RpcEndPoint和RpcEndPointRef剖析

    RpcEndpoint 文档对RpcEndpoint的解释:An end point for the RPC that defines what functions to trigger given ...

  4. 或许是你应该了解的一些 ASP.NET Core Web API 使用小技巧

    一.前言 在目前的软件开发的潮流中,不管是前后端分离还是服务化改造,后端更多的是通过构建 API 接口服务从而为 web.app.desktop 等各种客户端提供业务支持,如何构建一个符合规范.容易理 ...

  5. C语言编程入门之--第三章编写第一个C语言程序

    第三章 编写第一个C语言程序 导读:一般学一门计算机语言的第一堂上机课(“上机”顾名思义,上了计算机),就是往屏幕输出“hello world”,本章也不例外. 1.1 Hello,World! 这一 ...

  6. 从后端到前端之Vue(五)小试路由

    一开始我还以为vue的路由只能用在工程化的项目里面呢,然后研究了一下才发现,在脚本化里面也是可以用的.其实呢不管在哪里用,把原理研究明白就对了. 一. 官网demo 这里不得不吐槽一下官网,写的不清不 ...

  7. python 的几种数据类型

    列表  列表是 Python  的主力数据类型.当提到 " 列表 " 时,您脑海中可 能会闪现" 必须进一步声明大小的数组,只能包含同一类对象 "  等想法.千 ...

  8. Struts2 中Struts.xml结果页面配置

    结果页面的配置: 红色的比较常用 

  9. linux杂货铺

    vmware虚拟机克隆后网卡不能使用 解决方法如下 cat /etc/udev/rules.d/70-persistent-net.rules1.将eth0这行注释掉或者删除,这里记载的还是克隆系统时 ...

  10. Apache之——多虚拟主机多站点配置的两种实现方案

    Apache中配置多主机多站点,可以通过两种方式实现: 将同一个域名的不同端口映射到不同的虚拟主机,不同端口映射到不同的站点: 将同一个端口映射成不同的域名,不同的域名映射到不同的站点. 我们只需要修 ...