反射

正常情况下,我们必须知道一个类的完整路径后才可以实例化对象,但是在Java也可以通过一个对象来找到其所在类的信息,这其实就是Class的功能。

可以看到此时的所有操作都是反着来,这就是反射。

package reflect;

class X{

}

public class GetClassDemo01 {

public static void main(String[] args) {

X x=new X();

System.out.println(x.getClass().getName());

}

}

Class

Class本身表示一个类的本身,通过Class可以完整的得到一个类的完整结构,包括此类中的方法定义、属性定义等。

此类在jdk中文档中没有发现任何构造方法,所以此类的构造方法是被私有化了。

实例化Class 类对象的三种方式

♥ 第一种:通过forName()方法

♥ 第二种: 通过类class

♥ 第三种:通过对象.getClass()

package reflect;

class X{

}

public class GetClassDemo01 {

public static void main(String[] args) {

Class <?> c1=null;

Class <?> c2=null;

Class <?> c3=null;

try {

//通过第一种方式实例化Class对象,这种方法也是最常用的一种形式

c1=Class.forName("reflect.X");

//通过Object类中的放过实例化Class对象

c2=new X().getClass();

//通过类.cass实例化Class

c3=X.class;

System.out.println("类名称:" + c1.getName() );

System.out.println("类名称:" + c2.getName() );

System.out.println("类名称:" + c3.getName() );

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

一旦可以实例化Class对象之后就可以进行反射的进一步操作了。

Class的使用

Class主要是反射的源头,不光可以取得对象所在类的信息,也可以直接通过Class类的方法进行对象的实例化对象操作,使用关键字new为对象实例化,如果现在已经实例化好Class对象,则可以通过Class类提供的newInstance()方法实例化对象。

package reflect;

class Person{

private String name;

private int age;

@Override

public String toString(){//为了操作方便,复写toString放过

return "姓名:"+this.name+",年龄"+this.age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

public class InstanceDemo01 {

public static void main(String[] args) {

Class<?> c=null;

try {

c=Class.forName("reflect.Person");

Person per=null;

per=(Person) c.newInstance();//实例化对象

per.setName("月芽之上");

per.setAge(24);

System.out.println(per.toString());

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IllegalAccessException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

通过以上的代码可以发现,即使不适用 new关键字对象也可以进行实例化操作,这也就是反射的作用。但是我们也发现在使用以上操作的时候有一点需要注意,就是所操作的类中必须有午餐构造函数,否则无法进行实例化!

为了解决这一问题,我们需要明确的指明要调用的方法,并传递参数,(实际开发中一般会有午无参构造)。步骤如下:

❤ 1、通过Class类中的getConstructors()取得本类中的全部构造方法。

❤ 2、向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数

❤ 3、之后通过Constructor实例化对象

在Construction类中存在一个方法:

public T newInstance(Object... initargs)

throws InstantiationException,

IllegalAccessException,

IllegalArgumentException,

InvocationTargetException

传递参数初始化,以进行对象的实例化操作。

Constru中常用方法:

调用带参数的构造方法示例

package reflect;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

class Person{

private String name;

private int age;

public Person(String name,int age){//定义一个有两个参数的构造函数,此时当前类不再存在无参构造

this.name=name;

this.age=age;

}

@Override

public String toString(){//为了操作方便,复写toString放过

return "姓名:"+this.name+",年龄"+this.age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

public class InstanceDemo01 {

public static void main(String[] args) {

Class<?> c=null;

try {

c=Class.forName("reflect.Person");

Constructor<?> cons[]=null;

cons=c.getConstructors();

Person per=null;

per=(Person) cons[0].newInstance("月芽之上",24);//实例化对象

System.out.println(per.toString());

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

}

通过反射获取类的结构

在实际开发中,上面介绍的程序就是反射用的最多的情况,当然反射机制所提供的功能远不止这些,还可以通过反射获取一个类的完整结构,那么这是就要使用到java.lang.reflect保重的一些几个类。

❤ 1、Constructor :表示类中的构造方法

❤ 2、Filed :表示类中的属性

❤ 3、Method :表示类中的方法

这三个类都是AccessibleObject的子类

package reflect.construction;

interface China{

String NATIONAL="China";//定义全局变量

String AUTHOR="月芽之上";//定义全局变量

void sayChina();

String sayHello(String name,int age);

}

public class Person implements China {

private String name;

private int age;

Person(){//无参构造

}

Person(String name){//设置name

this.name=name;

}

Person(String name,int age){//设置name

this.name=name;

this.age=age;

}

@Override

public void sayChina() {

System.out.println("作者:"+AUTHOR+",国籍"+NATIONAL);

}

@Override

public String sayHello(String name, int age) {

return name+",你好,我今年"+ age+"岁了!";

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

取得类所实现的全部接口

要取得一个类所实现的接口,则必须使用Class类中的getInterfaces()方法。此方法定义如下:

public Class<?>[] getInterfaces()

方法的返回值是一个class类的对象数组,之后就可以直接利用Class类中的getName()方法输出即可、

public class GetInterfaceDemo {

public static void main(String[] args) {

Class<?> c1=null;

try {

c1=Class.forName("reflect.construction.Person");

Class<?> c[]=c1.getInterfaces();

for(int i=0;i<c.length;i++){

System.out.println(c[i].getName());

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

}

取得该类所继承的父类

一个类可与有多个实现,但是却只能有一个直接父类,所以想要取得一个类的父类,可以使用Class类中的getSuperclass()方法。

public Class<? super T> getSuperclass()

此方法返回的是Class实例,和之前取得接口一样,可以通过getName(0方法取得名次

public class GetSuperClassDemo {

public static void main(String[] args) {

Class<?> c1 = null;

try {

c1 = Class.forName("reflect.construction.Person");

Class<?> c = c1.getSuperclass();

System.out.println(c.getName());

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

}

取得全部构造函数

import java.lang.reflect.Constructor;

public class GetConstructorDemo {

public static void main(String[] args) {

Class<?> c1=null;

try {

c1=Class.forName("reflect.construction.Person");//实例化Class对象

Constructor<?>[] cons=c1.getConstructors();//得到全部构造方法

for(int i=0;i<cons.length;i++){

System.out.println(cons[i]);//打印所以构造方法

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

}

取得类中的方法

要取出一个类中的全部方法,可以使用Class类中的getDeclaredMethods()方法,此方法返回的是一个Method类的对象数组。而想取得方法的具体信息例如:方法参数、抛出的异常等等,就必须依靠Mehod类。

public Method getDeclaredMethod(String name, Class<?>... parameterTypes)                    取出本类的全部方法

throws NoSuchMethodException,SecurityException

public Method[] getMethods()                                                                  取得全部方法

throws SecurityException

public class GetMethodDemo {

public static void main(String[] args) throws ClassNotFoundException {

Class<?> c1=null;

c1=Class.forName("reflect.construction.Person");

Method m[]=c1.getMethods();

for(int i=0;i<m.length;i++){

System.out.println(m[i]);

}

}

}

取出类中的属性:

依赖的方法:

public Field[] getFields()  throws SecurityException

public Field[] getDeclaredFields()  throws SecurityException

public class GetFiledDemo {

public static void main(String[] args) throws ClassNotFoundException {

Class<?> c1=null;

c1=Class.forName("reflect.construction.Person");

Field f[]=c1.getFields();

for(int i=0;i<f.length;i++)

{

System.out.println(f[i]);

}

}

}

通过反射调用类中的方法

在正常情况下一个类对象产生后就可以直接调用类中的方法了.如果要调用的话肯定必须清楚的指定调用的方法名是什么,之后通过Class 中的getMethod()方法。

public Method getMethod(String name, Class<?>... parameterTypes)

throws NoSuchMethodException, SecurityException

该方法得到的Method对象,之后通过此Method对象来执行方法,但是在调用的时候因为会涉及到参数的问题,所以通过getMehod()取得的时候需要要设置好对应的参数类型。

比如调用Person中sayChina()方法,因为该方法中没有任何参数,所以只需要调用Method 中invoke()方法。

public Object invoke(Object obj,Object... args)
throws IllegalAccessException,IllegalArgumentException,InvocationTargetException

执行的时候需要还需要传递参数进去, 而且需要实例化对象。

public class InvokeSayChinaDemo {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {

Class<?> c1=null;

c1=Class.forName("reflect.construction.Person");//实例化Class对象

Method met=c1.getMethod("sayChina");//找到sayChina()方法

met.invoke(c1.newInstance());//调用方法

}

}

调用有参数的方法

public class InvokeSayChinaDemo {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {

Class<?> c1=null;

c1=Class.forName("reflect.construction.Person");//实例化Class对象

Method met=c1.getMethod("sayHello",String.class,int.class);//找到sayHello()方法

String returnValue=(String) met.invoke(c1.newInstance(),"李占祥",24);//调用方法

System.out.println(returnValue);

}

二十六、Java--------反射的更多相关文章

  1. Java学习笔记二十六:Java多态中的引用类型转换

    Java多态中的引用类型转换 引用类型转换: 1.向上类型转换(隐式/自动类型转换),是小类型到大类型的转换: 2.向下类型转换(强制类型转换),是大类型到小类型的转换: 3.instanceof运算 ...

  2. JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片

    JAVA之旅(二十六)--装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片 一.装饰设计模式 其实我们自定义re ...

  3. 二十六、Jcreator使用初步

    摘自http://blog.csdn.net/liujun13579/article/details/7751464 二十六.Jcreator使用初步 Jcreator是一个小巧灵活的Java开发工具 ...

  4. Java进阶(二十五)Java连接mysql数据库(底层实现)

    Java进阶(二十五)Java连接mysql数据库(底层实现) 前言 很长时间没有系统的使用java做项目了.现在需要使用java完成一个实验,其中涉及到java连接数据库.让自己来写,记忆中已无从搜 ...

  5. 二十六. Python基础(26)--类的内置特殊属性和方法

    二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...

  6. 二十六个月Android学习工作总结【转】

    原文:二十六个月Android学习工作总结 1.客户端的功能逻辑不难,UI界面也不难,但写UI花的时间是写功能逻辑的两倍.     2.写代码前的思考过程非常重要,即使在简单的功能,也需要在本子上把该 ...

  7. Bootstrap <基础二十六>进度条

    Bootstrap 进度条.在本教程中,你将看到如何使用 Bootstrap 创建加载.重定向或动作状态的进度条. Bootstrap 进度条使用 CSS3 过渡和动画来获得该效果.Internet ...

  8. Web 前端开发人员和设计师必读精华文章【系列二十六】

    <Web 前端开发精华文章推荐>2014年第5期(总第26期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  9. 二十六:Struts2 和 spring整合

    二十六:Struts2 和 spring整合 将项目名称为day29_02_struts2Spring下的scr目录下的Struts.xml文件拷贝到新项目的scr目录下 在新项目的WebRoot-- ...

  10. WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[扩展篇]

    原文:WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[扩展篇] 通过<实现篇>对WSDL元素和终结点三要素的之间的匹配关系的介绍,我们知道了WSDL的Binding ...

随机推荐

  1. js的三种继承方式及其优缺点

    [转] 第一种,prototype的方式: //父类 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = ' ...

  2. 《将博客搬至CSDN》

    http://www.cnblogs.com/duenyang  两个博客一起用,大家也可以去我CSDN博看查看.

  3. C# 禁止修改已装箱了的值类型的字段值,但是可以通过接口的方式实现

    C# 默认是不能修改已装箱了的值类型中字段的值,但是可以通过 值类型实现指定的接口来改变 首先定义一个接口 interface IChange { void Change(int a, int b); ...

  4. H TC並沒有成為下一個摩托羅拉或諾基亞。

    關於2014年第四季度,H T C在三季度財報說明中提到,“年度旗艦H T CO ne(M 8)與中端機型H T C D esire系列在競爭日趨激烈的智能手機市場保持穩定的銷售,市占率有所提升,延續 ...

  5. 第一章-第五题(你所在的学校有计算机科学专业和软件工程专业么?相关专业的教学计划和毕业出路有什么不同?阅读有关软件工程和计算机科学的区别的文章,谈谈你的看法。)--By 侯伟婷

    我所在的本科学校和研究生学校都有计算机科学专业和软件工程专业.具体的教学计划无从得到,所以此情况无从对比,但是我从本科教务处网站找到了计算机科学专业和软件工程专业有关专业方面的课程,现列表如下. 表格 ...

  6. 数据库使用数据泵迁移遇到LOB字段

    impdp system/Clic1234 attach=SYS_IMPORT_ILEARN_TRA desc ILEARN_TRA.NOTIFI_TACTIC desc ILEARN_TRA.MSG ...

  7. MySQL 5.6 记录 SQL 语句与慢查询

    环境: MySQL 如果需要记录 MySQL 的查询语句,需要在配置文件(Linux 下为 my.cnf,Windows 下为 my.ini)中添加配置: general_log = ON gener ...

  8. Air 压力测试

    VersionCode:{311} VersionName:{3.1.1} Force:{yes} Supply:{no} ToolsBlack:{yes}

  9. vim操作

    2.vi的基本操作 a) 进入vi    在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面: $ vi myfile 不过有一点要特别注意,就是您进入vi之后,是处于「命令行模式(comm ...

  10. selenium webdriver自动化测试

    selenium家族介绍           Selenium IDE:Selenium IDE是嵌入到Firefox浏览器中的一个插件,实现简单的浏览器操作的录制与回放功能.   Selenium ...