学习要点

  • 反射概念
  • 反射的应用

反射概述

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. C语言算法

    选择排序法:用第一个数分别和后面的数比较 冒泡排序法:相邻的两个数比较 01.单词首字母大写&统计单词个数 02: 编写一个函数int pieAdd(int n),计算1!+2!+3!+……+ ...

  2. 并不对劲的uoj276. [清华集训2016]汽水

    想要很对劲的讲解,请点击这里 题目大意 有一棵\(n\)(\(n\leq 50000\))个节点的树,有边权 求一条路径使该路径的边权平均值最接近给出的一个数\(k\) 输出边权平均值下取整的整数部分 ...

  3. SPOJ:The Next Palindrome(贪心&思维)

    A positive integer is called a palindrome if its representation in the decimal system is the same wh ...

  4. 如何编写linux下nand flash驱动-2

    [Nand Flash引脚(Pin)的说明] 图3.Nand Flash引脚功能说明 上图是常见的Nand Flash所拥有的引脚(Pin)所对应的功能,简单翻译如下: 1.       I/O0 ~ ...

  5. Java Socket实战之二:多线程通信

    转自:http://developer.51cto.com/art/201202/317544.htm 上一篇文章说到怎样写一个最简单的Java Socket通信,但是在上一篇文章中的例子有一个问题就 ...

  6. JS计算字符串实际长度

    http://www.qttc.net/201207136.html // UTF8字符集实际长度计算 function getStrLeng(str){ var realLength = 0; va ...

  7. NEFU 628 Garden visiting (数论)

    Garden visiting Problem:628  Time Limit:1000ms  Memory Limit:65536K Description There is a very big ...

  8. mybatis基础学习5-一对多和多对多(简写)

    1:建实体类 建mysql表

  9. CCF2016.4 - B题

    思路:创建两个bool数组来模拟下落过程,一个存放面板状态,一个存放下落的格子.检测格子和面板对应位置是否同时为True,如果是则有冲突,不能继续下落,否则增加行号.为了统一处理,我们把面板最下面加一 ...

  10. 【UVA - 101】The Blocks Problem(vector+模拟)

    The Blocks Problem Descriptions:(英语就不说了,直接上翻译吧) 初始时从左到右有n个木块,编号为0~n-1,要求实现下列四种操作: move a onto b: 把a和 ...