[01] 反射的基本概念和常用类

1、什么是反射

在了解反射之前,我们都是如何使用一个Java类的?

  • 已知一个类的类名,以及类中的方法、属性和构造方法等
  • 调用构造方法创建对象
  • 使用对象调用方法或者属性

那么问题来了,如果我们只知道一个类的类名,能否动态得到类的信息,包括其方法和属性?

  • 通过反射

所以反射的概念是:在运行状态中,对任意类都可知道其所有属性和方法,对任意对象都可调用其方法和属性。这种动态获取信息以及动态调用对象方法的功能,称之为Java的反射机制。

如Spring框架只需要通过xml文件描述类的基本信息,就可以利用反射机制动态装配对象。

2、反射的相关类

和反射相关的类主要包括 Class、Constructor、Method、Field等,除了Class,其他的类都位于java.lang.reflect包中。其中最重要的类是Class,可以说,反射的使用都是从Class开始的。

2.1 Class类

2.1.1 Class实例的获取

把一个类封装成为Class类,Class实例主要有三种方式获取:

  • //使用对象名获取
  • String str = "hello";
  • Class clazz = str.getClass();
  • //使用类名获取,在类名加后缀 .class
  • Class clazz = String.class;
  • //使用类名获取,通过Class的静态方法forName()
  • Class clazz = Class.forName("java.lang.String");

2.1.2 Class类的主要方法

Class类中的主要方法有:

  • getMethod:返回类中某个方法的实例
  • getMethods:返回类中所有方法的实例
  • getField:返回类中某个属性的实例
  • getFields:返回类中所有属性的实例
  • getConstructor:返回类中的一个构造方法的实例
  • getXXX:Class中还有若干get方法,获取类的基本信息

需要注意的是,以上涉及的获取Method或Field实例的方法,实际上还有一个类似的方法,不过名字中多个词Declared,如getDeclaredMethods(),区别在于:

  • 包含Declared:它仅获取自身类声明的方法,包括公开的、私有的、保护的等
  • 没有Delcared的普通get方法:会获取某个类所有的公开(public)成员,包括自己定义的和继承下来的

简单示例:

  1. public static void main(String[] args) {
  2. Class clazz_str = String.class;
  3. Method[] methods = clazz_str.getMethods();
  4. for (Method method : methods) {
  5. System.out.println(method.getName());
  6. }
  7. }

2.2 Constructor类

2.2.1 实例的获取

Constructor类的对象是由Class对象获取,Class类中定义了如下方法:

  • Constructor<T> getConstructor(Class... parameterTypes):通过指定参数类型,返回构造方法实例
  • Constructor[] getConstructors():返回该类的所有构造方法实例

这里所说的指定的参数类型,是指实际构造方法的形参。比如有构造方法 public Student(String name),那么需要:

  1. Class stuClazz = Student.class;
  2. Constructor stuCon = stuClazz.getConstructor(String.class);

2.2.2 实例的基本信息获取

该类可以通过getXXX的方法,获取构造方法的基本信息,如:

  • getName:返回构造方法的名字
  • getParameterTypes:返回构造方法的参数类型

2.2.3 创建对象

除了构造方法的基本信息,也可以通过该Constructor的实例创建对象:

  • newInstance(Object... initargs);

示例:

  1. Class stuClazz = Student.class;
  2. Constructor stuCon = stuClazz.getConstructor(String.class);
  3. Student stu = (Student)stuCon.newInstance("zhangsan");

2.3 Method类

2.3.1 Method的获取

Method类的实例由Class对象获取:

  • Method getMethod(String name, Class... parameterTypes):通过指定方法名,参数类型,返回Method实例
  • Method[] getMethods():返回该类中所有方法的Method实例

2.3.2 Method获取基本信息

Method封装了类中的方法,可以动态获取方法的信息,如:

  • getReturnType:获取方法的返回值类型
  • getName:获得方法名
  • getParameterTypes:获得方法参数类型

2.3.3 Method动态调用方法

除了动态获得方法信息,Method类还可以动态调用某个对象的具体方法:

  • invoke(Object obj, Object... args);

示例:

  1. public static void main(String[] args) throws Exception {
  2. Class stuClazz = Student.class;
  3. Constructor stuCon = stuClazz.getConstructor(String.class);
  4. Student student = (Student)stuCon.newInstance("zhangsan");
  5. Method study = stuClazz.getMethod("study");
  6. study.invoke(student);
  7. Method studyWithOne = stuClazz.getMethod("studyWithOne", String.class);
  8. studyWithOne.invoke(student, "lisi");
  9. }

2.4 Field类

2.4.1 Field的获取

获得Field实例,都是通过Class中的方法实现的:

  • public Field getField(String name)
  • 通过指定Field的名字,返回Field实例
  • 注意Field的访问权限

之前提到过,如果单纯地使用getField那么获取到的方法实例都是public的,如果要获取private方法,需要使用诸如getDeclaredField方法:

  1. //如有Student类,有private权限的属性name
  2. Class stuClazz = Student.class;
  3. Field name = stuClazz.getField("name"); // NG,报异常,找不到该方法
  4. Field name = stuClazz.getDeclaredField("name"); // OK

3、反射的重要说明

反射实际上将所有的类成分映射成为对应的的Class对象,这里的Class对象其实可以堪称是一种类型。并不知只有类才能转换成Class对象。

也即是说,如果真的需要(比如某些方法中要求参数是Class类型),像基本的数据类型(boolean、byte、char、short、int、long、float、double)甚至关键字如 void 也可以表示为Class对象(形如 int.class)

比如某些方法,如果你要用反射表示,可能参数可能会写成如 (String.class, int.class) 这种形式,这是sun公司定义的规则,不需要深刻去理解为什么。

例如 getConstructor(Class<?>... parameterTypes):

  1. Class stuClazz = Student.class;
  2. Constructor stuCon = stuClazz.getConstructor(String.class);
时间: 2024-12-29 15:34:24

[01] 反射的基本概念和常用类的相关文章

Java常用类及反射,类加载

1.系统相关类 Java提供了System类和Runtime类来与程序运行的平台进行交互 A.System类代表当前Java程序的运行平台 a. System类是一个final类,该类的所有属性和方法都是静态的.可以不创建对象直接调用 b.属性:in .out .err c.常用方法: currentTimeMillis().exit().getProperties(). gc() B. Runtime类代表Java程序的运行时环境 注意: 应用程序不能创建自己的Runtime实例,但是可以通过

异常处理、常用类、Java集合框架、反射

异常处理: 1.  异常:程序在执行过程中所产生的问题. 异常的三种类:①检查异常:又叫checdked异常或者受检异常.通常是用户错误或者不能被程序员所预见的问题.检查异常需要被解决之后才能通过编译. ②运行时异常:程序在运行过程中可能发生的.可以被程序员所避免的异常类型. ③错误:事实上错误不是异常,但却是用户和程序员无法控制的问题. 2.  异常的控制流程: 异常是被一个方法抛出的对象. (1) 处理异常的三个方法:①捕获这个异常,不让它沿着调用栈继续向下抛. ②捕获这个异常,并继续向下抛

处理异常、常用类、反射、类加载与垃圾回收、java集合框架

异常处理概述 检查异常:检查异常通常是用户错误或者不能被程序员所预见的问题.(cheched) 运行时异常:运行时异常是一个程序在运行过程中可能发生的.可以被程序员避免的异常类型.(Unchecked)RentimeExeption 错误:实际上,错误根本不是异常,但却是用户或程序员所无法控制的问题. 异常是程序在执行过程中所产生的问题.JVM发生了内存溢出等... 异常处理:method()方法有三种 1 捕获这个异常,不让他沿着调用栈继续向下抛出 2 捕获这个异常,并继续向下抛出 3 从而导

JAVA异常处理、常用类、反射、集合

异常 异常:在Java中是指被一个方法抛出的对象. 分类:检查异常.运行时异常.错误 运行时异常(uncheckd):RuntimeException和其子类 检查异常(checkd/搜检异常):指Exception和其子类,且不是RuntimeException的子类:它必须经过处理才会找到 语法: try{ //被保护的代码 }catch(异常的名称 e1){ //捕获块 } 注意:应先捕获特殊再捕获一般异常:try没有出现异常catch将不会执行 异常处理的三种选择: 1)捕获这个异常,不

java进阶之反射:反射基础之如何获取一个类以及如何获取这个类的所有属性和方法(1)

java学习一段时间之后,大家可能经常会听到反射这个词,那么说明java已经学习到一个高一点的层次了.接下来我会一步步和大家一起揭开java高级特性反射的神秘面纱. 首先介绍下类对象这个概念,可能会经常用到这个概念: 类对象:java中有句很经典的话"万事万物皆对象",相信大家都不陌生,这句话告诉了我们java的特征之一,那就是面向对象.java中类的概念我们都很熟悉,既然万事万物皆是对象,那么类是谁的对象呢?<对象的概念:一个类的实例>换句话说,类是谁的实例.如此就有了类

Java基础 —— Java常用类

Java常用类: java.lang包: java.lang.Object类: hashcode()方法:返回一段整型的哈希码,代表地址. toString()方法:返回父类名+"@"+哈希码(一般用于覆盖). equals()方法:返回"=="操作的布尔值(一般用于覆盖). finalize()方法:用于对象的销毁(不受人为控制,由JVM调用,遵从垃圾回收机制). clone()方法:用于对象之间的拷贝(深拷贝). getClass()方法:返回对象的字节码文件对

一大波Java来袭(三)Java常用类

本文简单介绍集中Java常用类 不同种类的工具用于处理不同的工作.比如:厨房中的工具用于烹饪:农场中的工具用于养殖--对于Java的学习中处理不同的工作也要采用不同的工具.如:处理数学函数问题用Math类.针对文件的操作采用File类--这也充分体现了Java面向对象的特点 一.字符串类(重点理解内存模型) (一)String Java.lang.String字符串常量,具有不可变性. (二)StringBuffer Java.lang.StringBuffer字符串可变量,是线程安全的. (三

跟王老师学反射(二):Java类的加载、连接和初始化

跟王老师学反射(二):Java类的加载.连接和初始化 主讲教师:王少华   QQ群号:483773664 学习内容: 了解类的加载.连接和初始化 一.类的生命周期 当我们编写一个java的源文件后,经过编译会生成一个后缀名为class的文件,这种文件叫做字节码文件,只有这种字节码文件才能够在java虚拟机中运行,java类的生命周期就是指一个class文件从加载到卸载的全过程.一个java类的完整的生命周期会经历加载.连接.初始化.使用.和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直

java反射+java泛型,封装BaseDaoUtil类。供应多个不同Dao使用

当项目是ssh框架时,每一个Action会对应一个Service和一个Dao.但是所有的Ation对应的Dao中的方法是相同的,只是要查的表不一样.由于封装的思想,为了提高代码的重用性.可以使用java中的泛型+反射去实现最终的封装,将所有的Dao层的共同部分写一个BaseDaoUtil.而所有的Dao都继承这个类. 思路: ----->(1)反射+泛型 ----->(2)当生成子类对象(UserDao),调用空构造时(new UserDao()),子类的空构造会默认调用父类的空构造器(new