当前课程知识点:JAVA程序设计进阶 > 第八章 反射与代理机制 > 8.1 Java反射机制 > Video
那这一节我们将首先介绍
Java的反射机制reflection
当我们的Java程序在运行过程当中
需要去识别它到底每一个对象
是什么样一个类型
那这种类型信息的识别
我们一般说来有两种办法
第一种办法叫RTTI
英文就叫Run-Time Type Identification
也就是运行时的类型的识别
那第二种办法就是利用Java的反射机制
我们先看一下RTTI
那我们为什么需要RTTI呢
那因为我们在运行过程当中
是需要识别每一个对象
它到底是属于什么类型
我们看这张PPT当中的一个图片
我们有一个类叫shape
也就是这个形状
它里面有方法draw
然后它有三个子类
一个叫circle
一个叫square
一个叫triangle
那假设我们的Java程序当中
有一个数组
要去保存这种shape类型的这种元素
但实际上在我们往里面存
这些元素的时候
存的都是它的底下
具体的子类类型
比如你存一个circle
一个square 或者一个triangle
那当我们从数组当中
把这些元素取出来的时候
那Java虚拟机会自动
把它的这个类型转型回shape
也就是转回它的这个
复类的这个类型
这个就是我们的RTTI
最基本的使用形式
因为在Java当中所有的类型转换
都是在运行的时候进行操作
并且进行正确性的检查的
那对于我们写代码来说
在很多情况下
都尽量可能少的去了解对象的
一种具体的类型
而只是与对象家族中的
一个最通用的表示方式来进行打交道
那在我们这个例子当中
它最通用的表现方式
实际上就是它的这个共同的复类shape
那这样写出来代码会更容易一些
也容易读 而且便于维护
设计也容易实现也容易理解
那我们今天想重点介绍的
实际上是我们的Java反射机制
那什么是Java的反射机制
它指的是在Java的运行过程当中
对于任意一个类
我们都能够知道这个类的
所有属性和方法
然后对任意一个对象
我们都能够调用
这个对象的方法和属性
这种动态获取信息
以及动态调用对象方法的功能
称之为Java语言的反射机制
我们看一下Java当中
有一个类叫Class
大家必须注意
是有一个类叫Class
就跟我们在最早最早
介绍Java最顶上的一个类叫Object
所以我们Java当中
所有的东西都是对象
但是在Java当中
最顶上那个类就叫Object
那个类名注意是以大写字母开头
我们看这一页PPT当中
最右边是我们最常见的这个
Object这个类
那它里面有一些方法
比如说hashCode
也就是说获得我们任意一个
这个Object这个对象的它的哈希值
还有equals
用来比较两个对象
是不是同一个对象
clone就是我们克隆出
我们一个对象
toString那就是把我们的一个对象
转换成字符串
notify那就是通知
和wait等待
那这些方法都是我们这个Object
这个类中的常见的这个方法
那我们再看看左边
那我们有个类就叫Class
注意是一个类
是大写字母C开头的这个Class
这个类也是Java当中的一个基础类
那当我们的Java虚拟机
在运行过程当中
装载这个一个新类的时候
就会在Java的堆当中
创建一个Class这个类的实例
注意是Class这个类
我们大写字母开头的
Class这个类实例
这个实例就代表了这个Class类型
那我们通过这个实例
就可以获取它的类型信息
那这些类中
它既然是一个类
它肯定也有它的一些方法
就和我们在这一页PPT最右边
我们Object这个类有些方法一样
那在我们Class这个类当中
也有一些方法
大家看看我们左边
左下角的这几个方法
第一个方法叫Method
然后是中括号然后get Methods
这个方法大家看也蛮有意思
首先Method是大写字母开头
其实表明它是一个类
大家注意了
在Java当中有一个类
它的名字就叫Method
然后中括号代表它是一个数组
数组
那实际上表示说是
我们这个get Method这个方法
它返回的返回值
是一个Method的数组
那get Method这个方法
到底想干什么呢
实际上它就是要返回
我们这个Class这个类
它的这个实例当中所有的方法
也就是说你通过这个get Method
能够知道某一个这个Class类的实例
它代表的这个对象当中
到底都有哪些方法
好 我们看第二个方法Field
getFields
Field大家注意
Field后面带一个中括号
表示它是一个数组
当然Field
Field的话也是大写字母开头
表示的是Field也是一个类
而这个Field
其实在Java当中
实际上表示的就是
我们一个类的成员变量
就是说我们定义了一个类的话
里面可能包含成员变量
那这个时候我们通过getFields
这个方法我就能知道
我这个类当中都有哪些成员变量
Field有时候在我们中文翻译中
也会翻译成域
好 我们看一下第三个方法
Constructor后面也是一个中括号
表示的是它是一个数组
getDeclaredConstructors
那这个方法就是要获得
我们这个Class类的这个实例
所代表那个类的所有的构造方法
那其实大家看到这个三个方法
getMethod getFields
getDeclaredConstructors
那实际上它就帮助大家
获得了某一个类的
它的所有的方法
它的所有的成员变量
还有它的构造方法
那你取到这些了以后
你用来干啥呢
你可能会需要去调用它
那怎么调用它
我们马上就会介绍到
那我们看看怎么利用Class类
来创建一个实例
那实际上Class类注意它
大家要明白
Class类的这个类型的对象
它是表达了一个类的引用
我们看一下这个第二行的
那个代码Class cls等于
Class.forName Airplane
大家看看首先等号右边是Class
这是一个类的名字
因为是大写字母开头
.forName .forName那应该是
大家能猜出来
这是它的一个static的方法
也就是它是一个静态方法
然后给了一个参数Airplane
实际上Airplane的话
实际上是我们一个类的名字
那这个时候我们等号左边
就是cls这个实例
它实际上是属于这个Class
这个类的一个实例
然后它所代表的是
我们airplane这个类型
所以这一行代码的作用就是这样
那紧接着我怎么能够去
创建出一个airplane
这个类的一个实例呢
再往下大家看看cls.newInstance
我们通过newInstance这个方法
当然注意这个方法
是属于Class这个类的方法
那我们这里是cls这个对象
调用它的newInstance方法
就创建了一个实例
那大家想想那newInstance这个方法
它的返回值是什么
它返回值实际上是一个实例
但这个实例是什么类型的呢
我告诉大家这个实例
是Airplane这个类型的
那在调用newInstance
创建实例过程当中
一般调用的是Airplane
这个类它的默认的构造方法
所以通过这两句代码
我们就可以利用一个字符串的名字
注意一个类字符串
就是我们现在Airplane这个类
它是一个类名
但是它现在是字符串
我们就可以利用这个字符串
来去创建出它的这个一个实例
那我们再往下看一下
这个一个稍微完整的例子
ClassAirplane
public String to String
return in airplane
然后我们这个Airplane这个类
就定义完了
那这些个类当中呢
我们实际上只是重写了
它的toString方法
那在toString里面
我们就是指返回数
我在飞机里面
好 这是一个类Airplane的定义
下面我们看一下
我们怎么利用Class这个类
来去创建Airplan的一个实例
我们往下看
public class createInstance
然后紧接着public static void main
String args throws Exception
然后我们看一下Class c1等于空
我们构造了一个Class
这个类的一个对象叫c1
然后初始值为空
然后Object ap
我们定义了声明了一个Object对象
叫ap
再往下看c1=Class.forName Airplane
这一句我们是创建了一个
这个Class类型的对象
那实际上这个Class类型对象呢
它所表示的这个类的类型
是这个Airplane
然后紧接着把它赋值给我们的c1
也就是说c1它所表示的
是一个Airplane这个类的一个类型
好 紧接着我们打印一下
system.out.printIn c1
大家想想打印c1
它到底会打印什么东西呢
自己琢磨一下
再往下看ap=c1.newInstance
我们利用c1这个对象
然后调用它的newInstance方法
那我们创建了这么一个实例
那这个实例大家想想
那个newInstance这个方法
它返回的这个实例是什么类型呢
当然现在我们直接是把它
这个赋到等号左边的话
ap是Object
紧接着我们往下调用
System.out.printIn ap.to String
就把它打印这个出来
当然ap.toString应该调用哪个方法
因为我们往上看
就是Class Airplane里面
有一个toString方法
那就应该调用这里面的方法
那其实我们做一下对比
我们传统的创建实例的办法
是像这样的
大家看比如我们有Airplaneap
等于new Airplane
因为我们是之前定了一个类
叫Airplane
那我们现在要创建它这个实例
就直接通过new
然后后面跟着它的构造方法
这时候我们就创建出一个实例来了
但是大家看这个例子
在我们这个左边
这个程序代码例子当中
我们是把Airplane这个类名
当做一个字符串
然后通过我们创建Class
这个类的一个对象c1
调用了Class.forName
然后后面跟着这个Airplane这个字符串
我们就创建了这么一个类型的
这个类的对象c1
然后再通过c1的newInstance方法
我们就创建出我们的这一个
这个实例来
然后这个实例的类型
实际上它是属于Airplane的
大家对比一下这两种方式
你会发现利用Class类
来创建实例的话
它会更加灵活更加方便
你只要把这个类
你要想要创建的这个对象的类的名字
当做字符串传进来
在我们这个例子当中
就是Airplane这个类
把它的名字当做字符串传进来
我们就可以创建出这个类的一个对象
那我们看看整个这个程序的运行结果
是什么
运行结果是这样的
打印出第一行class Airplane
那这个打印是因为我们
system.out.printIn c1
那c1的话
它所代表的就是这个类Airplane
这么一个类型
所以打印结果就是Class Airplane
然后第二行打印结果
是因为我们调用了
system.out.print ap.to String
那ap.toString的话又会
调用的这个toString这个方法
就是我们这个PPT上面这个
Class Airplane里面的
这个toString方法
那它的返回值就是return In Airplane
所以通过这个例子
我希望同学能够掌握就是
我可以利用一个类它的名字
这个字符串来去创建出它的实例
那这样会非常灵活
在其他很多地方你用起来的话
会很方便
那我们除了能创建一个类的实例
也就是通过一个字符串
创建一个类的实例以外
我们还能不能调用这个实例的方法呢
对不对
因为我们有时候执行功能的时候
是需要调用方法的
这个在Java的反射机制当中
也给大家提供了这种途径
那有个类叫Method类
Method它这个类本身
有一个invoke方法
那这个invoke方法
对带有指定参数的指定对象
调用这个Method对象
表示的这些 这个方法的话
我们就能够把我们目标对象的
这些方法都执行出来
那我们看一下下面的这个例子
import java.lang.reflect.*
注意了你要想反射
你就得引入这个包
java.lang.reflect.*
好了 我们看一下
这个类Class A
public ClassA
然后它里面定义了一个成员方法
叫public voil add
然后add方法我们有两个参数
一个叫Integer param1
第二个叫Integer param2
然后它里面的方法体是干什么呢
system.out. printIn
param1.intValue+param2.intValue
实际上是把这个两个参数的
首先先转换成它的整数值
整数值了以后再把它相加
然后再把结果打印出来
所以这个数是add方法的功能
那我们再看看ClassA的第二个方法
public void StringAdd
然后它的参数是String abc
然后它的结果是什么呢
system.out.printIn out+abc
那这第二个方法的话
就是把这个输入参数abc
再加上前面加上一个out
就把它打印出来
好 我们再往下看它的主方法
主方法里面try
Method mth=ClassA.class.getMethod
add newClass
这个数组然后Integer.class
然后Integer.class
这一行代码显得比较有意思
实际上它是声明了一个对象叫mth
那mth它是什么类型的对象呢
它是Method
就是方法类型的一个对象
也就是说mth它表示的是
某一个方法
那是哪个方法呢
因为我们都知道
你要想知道方法的话
你得知道它属于哪个类
然后以及具体这个类中的
哪个名字的方法
甚至是它的参数的表示
那这些都是在我们等号右边
都给大家提示了
首先它属于ClassA这个类的方法
那它通过ClassA.class
这个成员变量得到了它的类型
再通过getMethod方法
这个getMethod那就是要获得一个方法
那哪个方法呢
方法名字是add就是我们第一个参数
那方法的参数
它实际上是用一个数组
来表示我们add这个方法的参数的
那这个数组里面new Class
它里面是两个元素
一个是Integer.Class
第二个也是Integer.Class
实际上大家拿这两个Integer Class
和我们上面ClassA这个类里面的
方法add对比一下
也就是我们上面这个程序中第三行
public void add
Integer param1 Integer param2
实际上这个add里面它两个参数
第一个参数是Integer
第二个参数是Integer
那实际上这个里面的表示
在我们主要方法里面
就是Method mth等于
ClassA.class.getMethod
然后add new Class
然后后面跟着Integer.class
Integer class
这个是一个意思的 一个意思
好了
mth这个对象表示的是一个方法
已经说清楚了
这个方法属于类ClassA
然后它的方法的名字叫add
那下面我怎么去执行这个方法
好了 那我要执行这个方法
就通过mth的invoke这个方法
来去执行它了
那实际上我们是想执行
我们ClassA中的add方法
那我们怎么执行呢
大家看看invoke后面有两个
有几个参数
第一个参数是ClassA.class.newInstance
也就是说我ClassA
我通过Class这个它的成员变量
我得到它的类型
然后紧接着我去调用它的newInstance
我就获得了这个ClassA的
这么一个实例
然后得到了这个实例了以后
那我还要给它参数对不对
那我的参数是newInteger1
表示是一个Integer这个类型的
一个对象
然后它的值是1
那紧接着newInteger2
这个是第二个参数
然后这些都给全了以后
我们mth.invoke一执行
那实际上执行的就是我们上面这个类
ClassA当中的add方法
好 我们再往下
Method mth1等于
ClassA.class.getMethod
StringAdd newClass 数组
然后String.class
这是我们另外一个方法对象 叫mth1
那它的类型叫就是Method
然后它想表示的是哪一个方法
实际它想表示的是
我们ClassA这个类中的第二个方法
然后我们第二个方法的名字
叫StringAdd
然后StringAdd这个方法呢
它的参数只有一个
就是一个字符串
参数字符串
那我们声明了mth1了以后
我们当然也想去执行它了
那怎么执行
调用它的invoke方法
mth1.invoke
然后ClassA.class.newInstance
这是我们实例化出ClassA
这个类的一个对象
然后再给它参数是一个字符串
那字符串里面就是--test
好了 我们的这个主方法的话
基本就结束了
因为下面是一个catch Exception
那这个主方法里面
实际上最重要的是构造了两个对象
一个叫mth 一个叫mth1
那这两个对象它所对应的类型
就是Method这么这个类
也就是表示的一个方法
它既然表示了一个方法以后
我们就想执行这个方法
那怎么执行
就通过它的invoke方法的执行
那我们看看它这个执行结果吧
大家能猜得出来吗
到底执行结果是多少
运行结果第一个结果是3
为什么是3
那是因为我们调用ClassA的
第一个方法add的时候
给它传入了两个参数
一个是1 另外一个是2
那在这个add方法里面
就是把这个1和2加起来
然后并打印
所以它的输出结果是3
然后我们第二个输出结果是out--test
那这个结果的话
实际上就是
因为我们Stringadd这个方法的话
最主要就是把 我们输入字符串
在前面加上一个out
所以通过这个例子
是想告诉大家什么一件事情
也就是说通过Method这个类
你是可以表示任意一个类当中的
它的某一个方法的
然后你通过Method类的invoke
就可以去调用你刚才
想表达的那个方法
把它给执行出来
大家看这种执行是不是很灵活
所以这个也是我们
Java反射的一个例子
也就是说我在Java反射当中
我不仅仅可以通过一个类的
字符串的名字
我去创建出这个类的一个实例
我还可以通过Method类的方法invoke
去调用我原来目标类当中的
它的任意一个方法
这样的话是不是非常的灵活
那这一节的内容我们就介绍到这里
-1.0 导学
--Video
-1.1 线程的基本概念
--Video
-1.1 线程的基本概念--作业
-1.2 通过Thread类创建线程
--Video
-1.2 通过Thread类创建线程--作业
-1.3 线程的休眠
--Video
-1.3 线程的休眠--作业
-1.4 Thread类详解
--Video
-1.5 通过Runnable接口创建线程
--Video
-1.5 通过Runnable接口创建线程--作业
-1.6 线程内部的数据共享
--Video
-2.0 导学
--Video
-2.1 线程同步的思路
--Video
-2.2 线程同步的实现方式—Synchronization
--Video
-2.3 线程的等待与唤醒
--Video
-2.4 后台进程
--Video
-2.5 线程的生命周期与死锁
--Video
-2.6 线程的调度
--Video
-3.0 导学
--Video
-3.1 线程安全与线程兼容与对立
--Video
-3.2 线程的安全实现-互斥同步
--Video
-3.3 线程的安全实现-非阻塞同步
--Video
-3.4 线程的安全实现-无同步方案
--Video
-3.5 锁优化
--Video
-4.0 导学
--Video
-4.1 URL对象
--Video
-4.2 URLConnection对象
--Video
-4.3 Get请求与Post请求
--Video
-4.4 Socket通信原理
--Video
-4.5 Socket通信实现
--Video
-5.0 导学
--Video
-5.1 Socket 多客户端通信实现
--Video
-5.2 数据报通信
--Video
-5.3 使用数据报进行广播通信
--Video
-5.4 网络聊天程序
--Video
-6.0 导学
--Video
-6.1 Java虚拟机概念
--Video
-6.2 Java虚拟机内存划分
--Video
-6.3 Java虚拟机类加载机制
--Video
-6.4 判断对象是否存活算法及对象引用
--Video
-6.5 分代垃圾回收
--Video
-6.6 典型的垃圾收集算法
--Video
-6.7典型的垃圾收集器
--Video
-7.0 导学
--Video
-7.1 集合框架与ArrayList
--Video
-7.2 LinkedList
--Video
-7.3 HashMap与HashTable
--Video
-7.4 TreeMap与LinkedHashMap
--Video
-7.5 HashSet
--Video
-8.0 导学
--Video
-8.1 Java反射机制
--Video
-8.2 Java静态代理
--Video
-8.3 Java动态代理
--Video
-8.4 Java 反射扩展-jvm加载类原理
--Video
-8.5 Java进阶课程总结
--Video