理解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. 入门训练-4. Fibonacci数列

    问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少. 输入格式 输入包含一个整数n ...

  2. 如何简单地利用Bitmap为中介储存图片到数据库中

        这是我的第一篇博文,请大家多多指教!     大概一个月之前,在跟朋友合作开发一个APP的过程中,我们发现到一个问题:图片的存储.因为数据库没有图片这种数据类型,当用户上传的图片需要存储的时候 ...

  3. 终极CRUD-2-用lombok提高开发效率

    目录 1 lom介绍与基本使用 2 lombok 注意点 2.1 lombok自动生成方法可以混合自己写的方法 2.2 尽量不要使用@Data 2.3 属性不要使用基本类型 2.4 小心@ToStri ...

  4. 【Mac】解压文件夹中文乱码

    Mac 用的英文系统,发现下载含中文的文件后,解压为乱码,如图所示: 解决方法: 下载一个解压软件:"The Unarchiver" 安装后设置下,如图: 之后设置压缩文件的默认打 ...

  5. .NET Core on K8S学习实践系列文章索引(Draft版)

    一.关于这个系列 自从去年(2018年)底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发 ...

  6. 【转载】【VSCode】Windows下VSCode编译调试c/c++

    转载自:http://blog.csdn.net/c_duoduo/article/details/51615381 懒得自己配置或自己配置出现不明问题的朋友可以点这里: [VSCode]Window ...

  7. jboss6.1安装配置

     Jboss6.1的用途,配置,使用详解 一..简介: JBoss是全世界开发者共同努力的成果,一个基于J2EE的开放源代码的应用服务器因为JBoss代码遵循LGPL许可,你可以在任何商业应用中免费使 ...

  8. linux集群实施与部署-----Nginx

    ( 1 ) 配置基本环境 //安装虚拟工具 #cd /media/VMware\ Tools/ #cp VMwareTools--.tar.gz/tmp/ #cd /tmp/ #tar-xvzf VM ...

  9. 图解Redis之数据结构篇——压缩列表

    前言     同整数集合一样压缩列表也不是基础数据结构,而是 Redis 自己设计的一种数据存储结构.它有点儿类似数组,通过一片连续的内存空间,来存储数据.不过,它跟数组不同的一点是,它允许存储的数据 ...

  10. kubeproxy源码分析

    kubernetes离线安装包,仅需三步 kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源码解析为主,如果想去了解iptables模式的原理 ...