java程序中的对象在运行时会出现两种类型:编译时类型和运行时类型。例如List list  = new ArrayList()。其中变量list的编译时类型是List,运行时类型是ArrayList。还有更极端的类型,如通过网络通信传递过来一个对象,则这个对象的编译时类型是Object,但程序运行时又需要调用该对象运行时类型的方法。为了解决这种问题,程序需要在运行时发现对象和类的真实信息,为了解决这种问题有两种做法:

  • 第一种是假设在编译和运行时都知道类的具体信息。这种情况下,我们可以先使用instanceof运算符进行判断,再利用强制类型转换将之转换成运行时类型的变量即可;
  • 第二种是编译时根本无法预知该对象和类可能属于哪些类,程序只能依靠运行时信息来发现该对象和类的具体信息,这就必须使用反射。

获得Class对象

每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。Java程序中获得Class对象通常有如下三种方式:

  1. 使用Class类的forName()静态方法。该方法需要传入字符串参数。该字符串参数的值是某个类的全名。
  2. 调用类的class属性获取该类对应的Class对象。
  3. 调用某个对象的getClass()方法

第一种方式和第二种方式都是直接根据类来获取该类的Class对象,相比之下,第二种方式有如下两种优势:

  • 代码更安全,程序在编译阶段就可以检查需要访问的Class对象是否存在;
  • 程序性能更高,因为这种方式无需调用方法,所以性能更好。

也就是说,大部分情况下我们都该使用第二种方式来获取指定类的Class对象。但如果只有一个类名字符串,则只能使用第一种方式。一旦获取一个类对应的Class对象后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了。

获得类的Class对象后,就可以通过Class对象来获取类的构造器、方法、属性、注释、匿名内部类等属性了。

使用Class对象来创建类的对象

通过反射来生对象有两种方式:

  • 使用Class对象的newInstance()方法来创建该Class对应类的实例,这种方式要求该Class对象的对应类有默认构造器,执行newInstance()方法实际上是使用类的默认构造器来创建类的实例。
  • 使用Class对象获取指定的Contructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象的对应类的实例。通过这种方法可以选择使用某个类的指定构造器来创建实例。
package com.zhyea.test;

import java.lang.reflect.Constructor;

/**
* 使用反射创建对象测试类
*
* @author robin
*
*/
public class MyTest {
/**
* 使用默认构造器
*
* @throws Exception
*/
public void test1() throws Exception {
Class<?> clazz = Class.forName("com.zhyea.test.Hello");
System.out.println(clazz.newInstance());
} /**
* 使用指定构造器
*
* @throws Exception
*/
public void test2() throws Exception {
Class<?> clazz = Class.forName("com.zhyea.test.Hello");
Constructor<?> constructor = clazz.getConstructor(String.class);
System.out.println(constructor.newInstance("robin"));
} public static void main(String[] args) throws Exception {
MyTest mt = new MyTest();
mt.test1();
mt.test2();
}
} class Hello { String name; public Hello() {} public Hello(String name) {
this.name = name;
} @Override
public String toString() {
return "Hello " + name + "!";
}
}

使用Class对象调用方法

Class对象可以使用getMethods()方法或者getMethod()获取全部或指定方法。这两个方法返回的是Method对象数组或Method对象。

获得Method对象后,就可以通过Method来调用对应方法。

package com.zhyea.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method; /**
* 使用反射测试类
*
* @author robin
*
*/
public class MyTest {
/**
* 使用默认构造器
*
* @throws Exception
*/
public void test1() throws Exception {
Class<?> clazz = Class.forName("com.zhyea.test.Hello");
Method mtd = clazz.getMethod("sayHello", String.class);
mtd.invoke(clazz.newInstance(), "Robin");
} /**
* 使用指定构造器
*
* @throws Exception
*/
public void test2() throws Exception {
Class<?> clazz = Class.forName("com.zhyea.test.Hello");
Constructor<?> ctr = clazz.getConstructor(String.class);
Method mtd = clazz.getMethod("sayHello", String.class);
mtd.invoke(ctr.newInstance("zhangsan"), "Robin");
} public static void main(String[] args) throws Exception {
MyTest mt = new MyTest();
mt.test1();
mt.test2();
}
} class Hello { String name; public Hello() {} public Hello(String name) {
this.name = name;
} @Override
public String toString() {
if (null != this.name)
return "Hello " + this.name + "!";
else
return "Hello!";
} public void sayHello(String name) {
if (null == this.name) {
this.name = name;
}
System.out.println("Hello " + this.name + "!");
}
}

对于私有方法,也是通过setAccessible方法进行访问,只不过获取Method对象的方法需要做下调整。

package com.zhyea.test;

import java.lang.reflect.Method;

/**
* 使用反射测试类
*
* @author robin
*
*/
public class MyTest { public void test() throws Exception{
Class<?> clazz = Class.forName("com.zhyea.test.Hello");
Method mtd = clazz.getDeclaredMethod("testHello");
mtd.setAccessible(true);
mtd.invoke(clazz.newInstance());
} public static void main(String[] args) throws Exception {
MyTest mt = new MyTest();
mt.test();
}
} class Hello { String name; public Hello() {} private void testHello(){
System.out.println("This is a test for private method");
}
}

使用Class对象访问成员变量

通过Class对象的getFields()方法或getField()方法可以获取该类所包括的全部Field属性或指定Field。Field提供了如下两个方法来访问属性:

getXxx(Object obj):获取obj对象该Field属性值。Xxx对应8个直接类型。引用类型直接使用get即可。

setXxx(Object obj, Xxx val):将obj对象该Field的值设置成为val。Xxx对应8个直接类型。引用类型直接使用get即可。

实例代码如下:

package com.zhyea.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field; /**
* 使用反射测试类
*
* @author robin
*
*/
public class MyTest { public void test() throws Exception{
Class<?> clazz = Class.forName("com.zhyea.test.Hello");
Constructor<?> ctr = clazz.getConstructor(String.class);
Object obj = ctr.newInstance("Robin");
Field nameField = clazz.getDeclaredField("name");
System.out.println(nameField.get(obj) );

nameField.setAccessible(true);
nameField.set(obj, "zhangsan");
System.out.println((Hello)obj);
} public static void main(String[] args) throws Exception {
MyTest mt = new MyTest();
mt.test();
}
} class Hello { String name; public Hello(String name) {
this.name = name;
} public String toString(){
return "Hello " + this.name + "!";
}
}

使用反射来操作数组

在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过使用Array来动态地创建操作数组。

用代码来说明下:

package com.zhyea.test;

import java.lang.reflect.Array;

/**
* 使用反射测试类
*
* @author robin
*
*/
public class ArrayTest { public static void main(String[] args) throws Exception {
Object arr = Array.newInstance(String.class, 6);
Array.set(arr, 0, "Robin");
Array.set(arr, 1, "Tom"); System.out.println(Array.get(arr, 0)); String[] strArr = (String[])arr;
System.out.println(strArr[0]);
System.out.println(strArr[1]);
}
}

java 使用反射的更多相关文章

  1. JAVA的反射理解

    1----------------------------反射的概念----------------------------------------------- JAVA的反射机制是在运行状态中,对 ...

  2. java的反射

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

  3. iOS运行时编程(Runtime Programming)和Java的反射机制对比

    运行时进行编程,类似Java的反射.运行时编程和Java反射的对比如下:   1.相同点   都可以实现的功能:获取类信息.属性设置获取.类的动态加载(NSClassFromString(@“clas ...

  4. Java 类反射机制分析

    Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...

  5. java的反射机制

    一.java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...

  6. Java:反射

    初识Java反射机制: 从上面的描述可以看出Java的反射机制使得Java语言可以在运行时去认识在编译时并不了解的类/对象的信息,并且能够调用相应的方法或修改属性的值.Java反射机制的核心就是允许在 ...

  7. Java中反射机制和Class.forName、实例对象.class(属性)、实例对象getClass()的区别

    一.Java的反射机制   每个Java程序执行前都必须经过编译.加载.连接.和初始化这几个阶段,后三个阶段如下图:   其中

  8. java笔记--反射进阶之总结与详解

    一.反射进阶之动态设置类的私有域 "封装"是Java的三大特性之一,为了能更好保证其封装性,我们往往需要将域设置成私有的, 然后通过提供相对应的set和get方法来操作这个域.但是 ...

  9. java笔记--反射机制之基础总结与详解

    一.反射之实例化Class类的5种方式: java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型). 对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象 ...

  10. Java中反射的三种常用方式

    Java中反射的三种常用方式 package com.xiaohao.test; public class Test{ public static void main(String[] args) t ...

随机推荐

  1. 理解java集合——集合框架 Collection、Map

    1.概述: @white Java集合就像一种容器,可以把多个对象(实际上是对象的引用,但习惯上都称对象)"丢进"该容器中. 2.Java集合大致可以分4类: @white Set ...

  2. Jmeter--正则表达式提取值

    博客首页:http://www.cnblogs.com/fqfanqi/ 设置界面如下: Apply to:应用范围的选择: Field to check:检查的领域,即需要提取内容的地方. 下面是各 ...

  3. gunicorn

    https://blog.csdn.net/jailman/article/details/78496522 gunicorn工作原理 Gunicorn“绿色独角兽”是一个被广泛使用的高性能的Pyth ...

  4. Druid对数据库密码加密的坑

    背景: 在对已有项目搭建本地环境,修改了本地ip端口和数据库帐号密码(使用了明文). 然后项目一直跑不起来,还抛出各种异常,经过分析发现主要错在这里:druid java.lang.IllegalAr ...

  5. python的socket的学习

    一.Socket相关知识 1.socket是什么: socket是应用层与TCP/IP协议族通信的中间软件抽象层,他是一组接口.在设计模式中,Socket其实就是一个门面模式. 它把复杂的TCP/IP ...

  6. python引入同一目录下的py文件

    python引入同一目录下的py文件 注意:python2和python3的包内import语法有区别,下面介绍一下python3的包内import语法 例如在admin.py文件中要引入dealco ...

  7. Linux(7)- Nginx.conf主配置文件、Nginx虚拟主机/访问日志/限制访问IP/错误页面优化、Nginx反向代理、Nginx负载均衡

    一.Nginx.conf主配置文件 Nginx主配置文件conf/nginx.conf是一个纯文本类型的文件,整个配置文件是以区块的形式组织的.一般,每个区块以一对大括号{}来表示开始与结束. 核心模 ...

  8. python 多进程使用Queue通信的例子

    import time from multiprocessing import Process,Queue MSG_QUEUE = Queue(5) def startA(msgQueue): whi ...

  9. python 2.7.11安装pywin32过程中 停止工作问题

    问题描述 由于需要安装pywin32,官网下载了pywin32-220.win32-py2.7.exe.注意:你的pywin32是32位还是64位取决于你的python,而不是你的电脑.CMD上可以查 ...

  10. python连接mongo

    连接mongodb数据库 用到pymongo模块 应该是这样来使用: , 'goods') 然后连接数据库层这么写 def getSpinfo(item,value,depart,comp): res ...