学习要点

  • 反射概念
  • 反射的应用

反射概述

1  反射机制

定义

Java反射机制是指在程序在运行状态中,动态获取信息以及动态调用对象方法的功能。

Java反射的动态性质:运行时生成对象实例、运行期间调用方法、运行时更改属性。

Java程序执行过程

反射执行过程

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

2)  Java反射机制能够知道类的基本结构,这种对Java类结构的探知能力,称为Java类的“自审”。例如开发环境eclipse或者myeclipse中的代码自动提示功能,就是利用了Java的反射机制,对所创建对象的探知和自审。

3)  通过Java反射,可以实现以下功能:

  • 在运行时判断任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判断任意一个类所具有的方法和属性。
  • 在运行时调用任意一个对象的方法。

2  Java反射常用API

ava反射常用核心类位于java.lang.reflect包,常用类:

1)  Class类—可获取类和类的成员信息

2)  Field类—可访问类的属性

3)  Method类—可调用类的方法

4)  Constructor类—可调用类的构造方法

使用反射的基本步骤

1)  导入java.lang.reflect.*

2)  获得需要操作的类的Java.lang.Class对象

3)  调用Class的方法获取Field、Method等对象

4)  使用反射API进行操作 (设置属性﹑调用方法)

反射的应用

1  获取类的信息

Java类加载机制

Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能。

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

获取Class对象

1)  调用对象的getClass( )方法

定义学生信息类

/** 学生信息类 */

public class Student {

   private int sid;// 学号

   private String sname;// 姓名

   private char sgender;// 性别

   private int sage;// 年龄

   //构造函数(略)

   //属性封装(略)

}

定义测试类获得学生信息类的Class对象

Student student=new Student();

Class clazz=student.getClass();

  

2)  调用类的Class属性(推荐使用:类型安全、性能高)

Class clazz = Student.class;

3)        使用Class类的forName()静态方法

Class clazz = Class.forName("com.etc.demo.Student");// 参数是类全名

  

从Class对象获取信息

1)  访问Class对象对应类所包含的构造方法

方法

说明

Constructor getConstructor(Class[] params)

返回指定参数的public构造方法

Constructor[] getConstructors()

返回所有public构造方法

Constructor getDeclaredConstructor(Class[] params)

返回指定参数的构造方法,与访问级别无关

Constructor[] getDeclaredConstructors()

返回所有构造方法,与访问级别无关

示例代码

Constructor constructors[] =

clazz.getDeclaredConstructors();//返回所有构造方法

Constructor constructors[] =

clazz.getConstructors();//返回所有public构造方法

//返回指定参数的构造方法,与访问修饰符无关

Constructor con = clazz.getDeclaredConstructor

(new Class[]{int.class,String.class,char.class,int.class});

//简要输出构造方法信息

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

  

2)  访问Class对象对应类所包含的方法

方法

说明

Method getMethod(String name,Class[] params)

返回方法名为name的指定参数列表的public方法

Method[] getMethods()

返回所有public方法

Method getDeclaredMethod(String name,

Class[] params)

返回方法名为name的指定参数列表的所有方法

Method[] getDeclaredMethods()

返回所有方法

3)  访问Class对象对应类所包含的属性

方法

说明

Field getField(String name)

返回public指定名称为name的属性

Field getFields()

返回全部public属性

Field getDeclaredField(String name)

返回指定名称属性

Field[] getDeclaredFields()

返回全部属性

4)  访问Class对象对应类所包含的注解

方法

说明

<A extends Annotation>A getAnnotation

(Class<A>  annotationClass)

返回该Class对象所表示类上指定类型的注释,若没有,则返回null

Annotation[] getAnnotations()

返回所有注释

Annotation[] getDeclaredAnnotations()

返回直接存在于此元素上的所有注释

5)  访问Class对象对应类的其他信息

方法

说明

Class[] getDeclaredClasses()

返回Class对象对应类的全部内容类

Class[] getDeclaringClass()

返回Class对象对应类的全部外部类

Class[] getInterfaces()

返回Class对象对应类全部实现的接口

int getModifiers()

返回此类或接口的所有修饰符。使用Modifer工具类方法解码返回值获得访问修饰符

Package getPackage()

获得此类的包

String getName()

返回类的名称

String getSimpleName()

返回类的简称

Class getSuperclass()

返回基类Class对象

示例代码

 Class clazz = Student.class;

        System.out.println("------类的字段------------");

        Field fields[] = clazz.getDeclaredFields();

        for (Field field : fields)

            System.out.println(field.getName() + " " + field.getType());

        System.out.println("-------类的方法-----------");

        Method methods[] = clazz.getDeclaredMethods();

        for (Method method : methods)

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

        System.out.println("-------类的构造方法-----------");

        Constructor constructors[] = clazz.getDeclaredConstructors();

        for (Constructor constructor : constructors) {

            System.out.println(constructor);

        }

        System.out.println("--------类所在包、完整名称、父类----------");

        System.out.println(clazz.getPackage().getName());

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

System.out.println(clazz.getSuperclass());

  

2  创建对象

通过反射创建对象有两种形式:

  • 使用Class对象的newInstance()方法创建对象
  • 使用Constructor对象创建对象

使用newInstance()创建对象

要求Class对象对应的类有默认构造方法。

示例代码

Class clazz=Student.class;

Student student=(Student)clazz.newInstance();

student.setSname("张三");

student.setSage(21);

student.sayHello();

  

使用Constructor对象指定构造方法创建对象

示例代码

Class clazz=Student.class;

Constructor constructor=

clazz.getConstructor(int.class,String.class,char.class,int.class);

Student student=(Student) constructor.newInstance(1001,"张三",'男',22);

student.sayHello();

  

3  访问类的属性

使用Field对象可以获取对象的属性。通过Field对象可以对属性进行取值或赋值操作。主要方法如下:

方法

说明

Xxx getXxx(Object obj)

Xxx对应Java的8个基本数据类型,如int。obj为该属性所在的对象。

Object get(Object obj)

获得引用类型属性值。

void setXxx(Object obj,Xxx val)

将obj对象该属性设置为val值。

void set(Object obj,objcet val)

将obj对象该属性设置为val值。针对引用类型。

void setAccessible(bool flag)

对获取到的属性设置访问权限。参数为true,可以对私有属性取值和赋值。

示例代码

/** 人类 */

class Person {

   private String name;// 姓名

   private int age;// 年龄

   /** 重写toString()方法 */

   public String toString() {

       return "my name is" + name + ",age is" + age;

   }

}

/** 测试代码 */

    Person p = new Person();// 创建Person对象

    Class clazz = Person.class;// 获取Person对应的Class对象

    // 获取Person类的name属性,使用getDeclaredField()方法获取各种访问级别的属性

    Field nameField = clazz.getDeclaredField("name");

    // 设置通过反射访问该Field时取消权限检查

    nameField.setAccessible(true);

    // 使用set方法为p对象指定Field设置值

    nameField.set(p, "andy");

    //同理设置age属性

    Field ageField=clazz.getDeclaredField("age");

    ageField.setAccessible(true);

    ageField.setInt(p,21);

    //输出结果

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

4  访问类的方法

使用Method对象可以调用对象的方法。在Method类中包含一个invoke()方法,方法的定义如下:

Object invoke(Object obj,Object… args);

obj:执行该方法的对象

args:执行该方法时传入该方法的参数列表

示例代码

/** 计算器类 */

public class Calculator {

/** 加法 */

public int add(int a, int b) {

     return a + b;

}

/** 减法 */

private int sub(int a, int b) {

     return a - b;

}

}

       /** 测试代码 */

        // 获取Calculator对应的Class对象

        Class clazz = Calculator.class;

        // 创建Calculator对象

        Calculator calculator = new Calculator();

        // add方法调用

        Method methodAdd = clazz.getMethod("add", int.class, int.class);

        int result1 = (int) methodAdd.invoke(calculator, 10, 12);

        System.out.println("10+12=" + result1);

        // sub方法的调用

        Method methodSub = clazz.getMethod("sub", int.class, int.class);// 报错如何处理?

        int result2 = (int) methodSub.invoke(calculator, 13, 4);

   System.out.println("13-4=" + result2);

  

注意:invoke()方法调用对应的方法时,java会检查权限。

解决方案:如果是调用private方法,是用setAccessible()方法设置允许调用。

// sub方法的调用

Method methodSub = clazz.getDeclaredMethod("sub", int.class, int.class);

methodSub.setAccessible(true);

int result2 = (int) methodSub.invoke(calculator, 13, 4);

System.out.println("13-4=" + result2);

  

5  Array类

在java.lang.reflect包下提供了一个Array类。

Java反射技术除了可以在运行时动态地决定要创建什么类型的对象,访问哪些成员变量,方法,还可以动态地创建各种不同类型,不同维度的数组。

动态创建数组的步骤如下:

1)        创建Class对象,通过class属性、forName(String)方法或者getClass()方法指定数组元素的类型。

2)        调用Array.newInstance(Class, length_of_array)动态创建数组。

操作动态数组常用方法

1)        访问动态数组元素的方法和通常有所不同,它的格式如下所示,注意该方法返回的是一个Object对象

    Array.get(arrayObject, index)

2)        为动态数组元素赋值的方法也和通常的不同,它的格式如下所示, 注意最后的一个参数必须是Object类型

      Array.set(arrayObject, index, object)

示例代码:

import java.lang.reflect.Array;

public class Test {

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

       // 创建一个元素类型为String,长度为10的数组

       Object arr = Array.newInstance(String.class, 10);

       // 依次为数组中index为7、8的元素赋值

       Array.set(arr, 7, "China");

       Array.set(arr, 8, "German");

       // 依次取出数组中index为7、8的元素的值

       Object obj1 = Array.get(arr, 7);

       Object obj2 = Array.get(arr, 8);

// 输出元素的值

       System.out.println(obj1.toString() + "  PK  " + obj2.toString());

   }

}

上机练习

需求说明

  • 使用反射修改和查询Student类的姓名属性(public)和年龄属性(private)。
  • 使用反射动态执行Student类输出信息的方法。

JavaSE-22 反射的更多相关文章

  1. Java匹马行天下之JavaSE核心技术——反射机制

    Java反射机制 一.什么是反射? 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及 ...

  2. 转载:JavaSE之反射

    该文章转载自:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html Java反射详解 本篇文章依旧采用小例子来说明,因为我 ...

  3. day 22 反射,双下方法

    反射: 反射:通过字符串去操作对象(类,空间等等)的属性或方法反射的四个方法 hasattr *** getattr *** setattr *** delattr *** # getattr 用法c ...

  4. JavaWeb-JDBC-Mybatis-Junit-Maven-Lombok

    Java与数据库 初识JDBC JDBC是什么? JDBC英文名为:Java Data Base Connectivity(Java数据库连接),官方解释它是Java编程语言和广泛的数据库之间独立于数 ...

  5. java reflect反思总结

    --------------TestBean package lh.demo.bean; public class TestBean {  private String userName;  priv ...

  6. 《JavaScript语言精粹》【PDF】下载

    <JavaScript语言精粹>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382204 内容简介 javascript曾是&q ...

  7. Java匹马行天下之新手学习目录

    Java匹马行天下之新手学习目录 学习路线 [Java匹马行天下——Java学习路线] [Java匹马行天下——开篇学习计划] 基础篇 [Java匹马行天下之学编程的起点——编程常识知多少] [Jav ...

  8. WebServer Project-01-反射

    简介 上网浏览网页,离不开服务器,客户请求页面,服务器响应页面,响应的内容是根据每个web请求来产生动态内容的,其内部即启动多个线程来产生不同内容.这种请求响应的交互,都是基于HTTP协议的. 当然现 ...

  9. (精简)Spring框架的IoC(替代工厂类实现方法)和AOP(定义规则,约定大于配置)

    Spring的核心框架主要包含两个技术,分别用来处理工厂类,以及事务处理和连接管理的. 两大核心概念 1)  IoC:控制反转,在现在的开发中,如果想建立对象并设置属性,是需要先new对象,再通过se ...

  10. java-反射-注解-json-xml

    反射: 框架设计的灵魂 框架:半成品软件.可以再框架的基础上进行软件开发,简化代码 定义:将类的各个组成部分封装为其他对象,这就是反射机制 好处: 可以再程序运行过程中,操作这些对象 可以解耦,提高程 ...

随机推荐

  1. python库学习笔记——爬虫常用的BeautifulSoup的介绍

    1. 开启Beautiful Soup 之旅 在这里先分享官方文档链接,不过内容是有些多,也不够条理,在此本文章做一下整理方便大家参考. 官方文档 2. 创建 Beautiful Soup 对象 首先 ...

  2. 修改 Appdelegate 文件名为添加项目前缀的方法

    本文假设你的项目是 Test, 那么为了给你的 Appdelegate 文件保持按照项目名为前缀 ,就需要对 Appdelegate 文件进行修改前缀名. 技巧分享:将开发中的 Appdelegate ...

  3. oauth X-Frame-Options 跳转授权页面时,302重定向禁用iframe

    因为oauth/authorize响应头包含X-Frame-Options: DENY解决方案:openresty nginx 移除该属性,经测试生效 more_clear_headers X-Fra ...

  4. E201700525-hm

    skeleton n. 骨骼; (建筑物等的) 骨架; 梗概; 骨瘦如柴的人(或动物);adj. 骨骼的; 骨瘦如柴的; 概略的; 基本的; cloud   n. 云; 云状物;  invoke   ...

  5. 洛谷 P3825 [NOI2017]游戏 【2-SAT+状压】

    UOJ和洛谷上能A,bzoj 8ms即WA,现在也不是知道为啥--因为我太弱了 先看数据范围发现d非常小,自然想到了状压. 所以先假装都是只能跑两种车的,这显然就是个2-SAT问题了:对于x场没有hx ...

  6. ibatais.net 连接 mysql 最全配置写法

    1.安装环境: 1.       vs2013 (vs开发工具) 2.       mysql 5.7.10.0 (安装的mysql 数据库版本) https://dev.mysql.com/doc/ ...

  7. centos 7添加快捷键

    转自:http://www.cnblogs.com/flying607/p/5730867.html centos7中不自带启动终端的快捷键,可以自定义添加. 点击右上角的用户名,点击设置,在设置面板 ...

  8. 1.1.1最短路(Floyd、Dijstra、BellmanFord)

    转载自hr_whisper大佬的博客 [ 一.Dijkstra 比较详细的迪杰斯特拉算法讲解传送门 Dijkstra单源最短路算法,即计算从起点出发到每个点的最短路.所以Dijkstra常常作为其他算 ...

  9. 使用HttpClient携带pfx证书调用HTTPS协议的WebService

    调用第三方服务时,厂商提供了一个WSDL文件.调用的地址和一个后缀为pfx的证书文件,通过SOUPUI记载证书是可以正常调用WebService服务,那么如何将该服务转换为代码呢? 咨询了厂商的支持, ...

  10. AFNetworking2.5使用-转

    来自:http://blog.csdn.net/daiyelang/article/details/38434023 官网下载2.5版本:http://afnetworking.com/ 此文章是基于 ...