n 内部类:定义在一个类内部的类,就称为内部类java
u 内部类分为3种mysql
² 成员内部类:至关于成员变量程序员
² 局部内部类:定义在方法内部的,至关于局部变量(极少用到,了解便可)面试
² 匿名内部类:(经常使用)算法
Iterator it = new Iterator() {//直接定义类,并同时建立该类对象sql @Override数据库 publicboolean hasNext() {编程 returnfalse;数组 }安全 @Override public Object next() { returnnull; } @Override publicvoid remove() {
} }; |
u 使用要点:
² 内部类的构造方法不能够在其余类里直接调用!
² 内部类若是有静态成员变量,那么内部类也必须是静态的!
² 非静态内部类Car.Engine en = new Car().new Engine();
或者能够这样写:
Car c = new Car();
Car.Engine en = c.new Engine();
² 静态内部类 Car.Engine en = new Car.Engine();
² 外部类在使用内部类的时候,能够直接实例化 Engine en = new Engine();
n 抽象类: 使用abstract关键字修饰的类,称之为抽象类
u 使用要点:
² 有抽象方法的类只能定义成抽象类(要使用abstract修饰)
² 抽象类不能实例化,不能生成对象
² 能够定义构造方法但不能够调用
² 抽象类只能被继承
² 继承抽象类的子类必须实现抽象类的抽象方法
u 抽象类的意义:
² 使一个类更加具备模板意义,强制规定了子类的行为
² 把设计工做和具体的代码实现工做作了分离
n 接口: 类的模板,用来作设计或规范,比抽象类更抽象
u 飞机、篮球、子弹、石头,这些事物之间有什么共同点?是否能用继承体现他们的关系?
n 这些事物之间没有特别明显的共同属性,也很难抽象出父类(很难概括为一个类别),可是它们都具备一些相同的行为能力:那就是飞行
u 所以这里咱们再也不使用抽象类,而使用接口来体现它们的关系,抽象出它们的共同行为
publicinterface Flyable{ //接口中的方法都是抽象的,没有实现 publicabstractvoid fly(); }
class Plane implements/*实现*/ Flyable { @Override publicvoid fly() {
} }
class Stone implements Flyable { @Override publicvoid fly() {
} }
class Bullet implements Flyable{ @Override publicvoid fly() {
} }
|
n 接口的特色:
u 接口中的方法所有都是抽象的,不能有方法实现代码!
² 接口中的方法,默承认以省略public 和 abstract关键字,系统会自动加上
u 对于实现了接口的类,必须实现接口中的全部抽象方法。
u 接口中的属性,所有都是静态常量。
² 默承认以省略final关键字,系统会自动加上
u 接口是能够多继承的!好比接口A能够同时继承接口B和接口C
n 经常使用类:
u 基本数据类型的包装类
u byteàByte、booleanà Boolean、char à Character、
shortà Short、intà Integer、longà Long、
floatà Float、doubleà Double
n String类和StringBuffer类
u 掌握String类和StringBuffer的区别
u StringBuffer是带缓冲的可变长度字符串,若是一个字符串在内存中频繁的被修改,为了可以提升性能,这时咱们就会考虑使用StringBuffer来存储字符串内容。
u StringBuffer类同时也给咱们提供了不少实用处理字符串的方法
//计算字符串长度 publicsynchronizedint length() //把字符串两边空格去掉再计算长度 publicsynchronizedvoid trimToSize() //得到指定下标位置上的一个字符 publicsynchronizedchar charAt(int index) //设置指定下标位置上的字符,将字符内容更改成ch的值 publicsynchronizedvoid setCharAt(int index, char ch) //向字符串末尾追加内容 publicsynchronized StringBuffer append(String str) //截取字符串的一部分,从指定下标开始,到指定下标结束 publicsynchronized String substring(int start, int end) //计算指定内容在整个字符串中出现的下标位置 publicint indexOf(String str) //反转逆序整个字符串 publicsynchronized StringBuffer reverse() ...... |
u
//计算a的绝对值 publicstaticint abs(int a) publicstaticint abs(float a) ...... //计算a和b的最大值 publicstaticint max(int a, int b) publicstaticint max(double a, double b) ...... //计算a和b的最小值 publicstaticint min(int a, int b) //生产一个0至1的随机小数 publicstaticdouble random() ...... |
Math类
u System类
字段摘要 |
|
static PrintStream |
err “标准”错误输出流。 |
static InputStream |
in “标准”输入流。 |
static PrintStream |
out “标准”输出流。 |
方法摘要 |
|
static long |
currentTimeMillis() |
static void |
exit(int status) |
static void |
gc() |
static String |
|
static int |
identityHashCode(Object x) |
static long |
nanoTime() |
n 集合类: 一组数据的集合,相似于数组,功能比数组强大
u 集合的特色
² 集合的长度是可变的
² 集合中存储的元素都是对象
² 全部的List集合类都实现了一个叫作Collection的接口
u List集合类的结构图:
u 掌握接口List和Set集合有什么不一样
² List接口和Set接口都继承了Collection接口
² 接口定义了不一样集合类的做用以及存储数据的方式
² 其中Set全部集合中的数据对象都是没有顺序且不可重复的
² 其中Vector集合是线程安全的
u 掌握ArrayList和LinkedList的区别
² ArrayList是简单的顺序结构,而LinkedList是链表结构,两者各有优缺点。顺序结构因为有下标的存在访问元素时速度比较快!但插入或删除元素会使得整个集合的元素都须要挪动,因此插入删除效率比较低!
² 链表结构因为采用了指针(也叫引用)连接对象,例如:
a对象保存了一个b对象的引用,b对象保存了一个c对象的引用,这时对象a、b、c就构成了一个链表结构
a |
b |
c |
a |
b |
c |
d |
当插入元素d时,不须要挪动元素,而只须要修改指针(引用)便可
所以链表结构在作插入删除操做时,速度较快,但因为没有下标,访问元素时,必须从第一个元素开始,挨个查找下一个元素,因此效率是比较低的!
结论:ArrayList访问效率高,插入删除效率低
LinkedList访问效率低,插入删除效率高
u 掌握Collection和Collections有什么不一样
Collection是一个接口,规定了全部集合的方法,至关于全部集合的一个总规范
Collections是一个类,里面提供了各类操做集合的工具方法
u Collections类的sort方法
要求集合中全部元素对象都必须实现了Comparable接口
u Collection的父接口Iterable
这个接口规定了全部实现Collection接口的集合,都必需要有一个itrerator()方法,这个方法返回一个Iterator(迭代器)类型的对象
u Map集合类
u
key |
value |
key
|
value
|
key
|
value
|
Map集合的特色
² 以Entry(键值对)的方式来存储对象
² Map集合的结构
² 没有顺序
key
|
value
|
u HashMap和HashTable区别
² HashMap和HashTable都实现了Map接口,但不一样的是,HashTable是一个线程安全的Collection
² HashMap容许将null做为一个entry(键值对)的key或者value,而Hashtable不容许null。
u 泛型: 类型检查,防止出现类型转换错误,而且减小了手动类型转换的次数
ArrayList<Int> list = new ArrayList<Int>(); list.add(new Int(45)); list.add(new Int(99)); list.add(new Int(22)); Collections.<Int>sort(list);
Collections.<Int>sort(list, new Comparator<Object>() { @Override publicint compare(Object o1, Object o2) { return 0; } });
print(list);
privatevoid print(Collection<? extends Object> list) { for(Object o : list) {
} }
class Int implements Comparable<Object>{ intvalue; public Int(int value) { this.value = value; }
@Override publicint compareTo(Object o) { if(o instanceof Int) { Int i = (Int)o; if(this.value > i.value) { return 10; } elseif(this.value == i.value) { return 0; } } return -10; }
public String toString() { returnthis.value+""; } } |
声明类型 |
声明类型 |
u HashMap的深度解析
² 在使用集合时,JAVA规范中要求,凡是要存入集合中的元素,都要重写对象的equals方法,请问这是为何?(面试题)
key-value
|
key-value
|
key-value
|
key-value
|
key-value |
在解答整个问题以前,要先了解HashMap 的存储结构
第1、查看源码咱们能够得知HashMap本质仍然是一个数组
第2、在使用put方法存放每个Entry(键值对)的时候,HashMap会根据key(键)的hashcode值进行计算,得出一个下标,而后将其存放到相应的数组位置上。
关于hashcode()方法,因为是一个本地方法,因此咱们没法知道它是如何实现的,但无论怎样,至少咱们知道,key-value的存放位置是跟key 的hashcode值有关。
那么当两个key的hashcode值同样时,键值对又该如何存放呢?
咱们再查看一下源代码,会发如今HashMap当中有一个内部类Entry
对于每个Entry,实际上它自己是一个链表结构的,它的next属性保存另一个对象的引用。JAVA为何要这样设计呢?
原来,在存放Entry 的时候,当一个Entry的key的hash码相同,则在数组的同一个位置上,则会以链表的形式存储
key-value |
key-value
|
key-value
|
key-value
|
key-value
|
key-value
|
当key的hash码同样时,会存放到数组的 同一位置,并以链表形式存储
key-value
|
在获取元素的时候,HashMap一样会去计算传入key的hash码,首先定位到数组的位置上,而后利用传入key的equals方法来比较链表上的每个key,比较结果相同时,才会将value值取出来。
若是没有重写equals方法,那会形成什么严重后果呢?
每一个对象都有本身的hashcode值,经过hashcode()方法得到,因为没有重写equls方法,定位到数组的位置后,key的比较没法相等,所以就没法把数据取出来!
从这里咱们也能够看出,当使用HashMap存储数据时,为了可以进一步的提升HashMap的效率,咱们但愿数组的每个位置上元素都不要重复,不然每次获取元素时,都要对链表上的每个key进行equals比较,而链表的访问效率是比较低的,因此链表的长度越小越好。
这也就提出了一个新的问题?如何才能使得元素在数组上存放的时候,位置不冲突?说白了,怎么能把这些元素分的越散越好?这就要从新去考虑咱们的散列算法(hash算法)。
关于HashMap 更多的信息,因为篇幅有限再也不作更多介绍,有兴趣自行百度。
u 迭代器
next() |
next() |
def
|
abc |
一个带游标的数组
next()方法会返回游标的下一个元素“abc”同时 游标会向后移动一个位置
游标 |
再次调用next()方法返回“def”
hasNext()返回是否还有下一个元素可访问
迭代器中的remove方法删除迭代器刚刚返回的 元素,而且不能同时调用两次!
使用迭代器进行for循环
for(Iterator it = list.iterator(); it.hasNext();) { Student stu = (Student)it.next();
} 固然也能够加上泛型,省去类型转换的麻烦 for(Iterator<Student> it = list.iterator(); it.hasNext();) { Student stu = it.next();
}
|
n 异常处理: java中提供了一种处理程序错误的机制,叫作异常处理
u 考虑这样一个问题,当咱们打算写这样一个程序,将D:/a.txt 复制到E:/a.txt
if(D:/a.txt这个文件存在) { if(E盘剩余空间足够复制a.txt文件) { if(文件读取一半时出现错误,好比a.txt被修改或删除了) { 中止复制工做,提示复制失败 } else { if(若是E:/a.txt文件不存在) { 在E盘下新建a.txt文件 } copy("D:/a.txt","E:/a.txt");//执行复制动做 } } else { 提示E盘剩余空间不足 } } else { 提示a.txt文件不存在 }
|
咱们的代码会这样写:
能够看到,咱们真正复制文件的代码只有黑色字体部分的少许代码
而大部分代码逻辑在作条件判断,目的就是为了程序出错时,
能够作出一些相应的处理,并能给出一些错误的提示信息
程序员在写代码的时候,要考虑的错误处理比功能处理还要多,这显然有些本末倒置了,为了可以在写程序时,考虑问题更专一于程序的功能,而不是错误处理,所以JAVA设计出了异常处理机制。
因此,利用异常处理机制咱们能够把程序修改为下面的样子:
try { if(若是E:/a.txt文件不存在) { 在E盘下新建a.txt文件 } copy("D:/a.txt","E:/a.txt");//执行复制动做
} catch (发现文件不存在) { 提示a.txt文件不存在 } catch (发现E盘剩余空间不够) { 提示E盘剩余空间不足 } catch (文件复制一半时出现错误) { 中止复制工做,提示复制失败 } |
这里指明出现了什么样的异常情况 |
JAVA容许咱们以这种方法来判断异常的发生 这样咱们就能够把全部的异常情况集中起来作处理了!
|
在这里程序员能够专一于文件复制功能的实现,而暂时先不去关心错误如何处理
|
u Exception类的继承结构
Throwable |
Error |
Exception
|
RuntimeExcepton
|
RuntimeException,叫作运行时异常,因为这种异常编译阶段一般难以检查出来,这类异常也称为不检查异常(unchecked)编译器不会强制要求程序人员作try-catch的异常处理 例如: //下标越界异常 //空指针异常 //类型转换异常 //算术异常 |
若干子类...... |
除运行时异常之外的其它异常类,在编译期间会检查出来的异常,咱们称之为检查异常,对于这类异常,在程序员写代码的时候,若是使用了有可能产生这类异常的方法,则编译器会强制要求程序人员必须try-catch处理异常 例如: //类找不到异常 //IO流使用异常 //数据库交互异常 //算术异常 |
其它子类...... |
对于ERROR这个类咱们没必要太关心,由于ERROR表明了非程序代码的错误,例如虚拟机内存不足而致使的程序终止,程序员不须要对这类错误作任何处理。
在JAVA的世界中,一切都是对象,因此毫无例外的,异常的产生也是以对象的形式存在,例如当发生数组下标越界的异常时,程序会自动生成一个IndexOutOfBoundsException类的实例对象, 并把这个对象以 throw的形式抛出!
在任何的程序设计语言中,都会有意外错误的状况发生,在一个小的程序中,能够用比较简单的方法处理异常,可是在一个大的系统中,每个方法都要有处理异常情况的代码,这样必然使得程序变得很是复杂和庞大。因此,JAVA才设计出了这样的办法:
当一个方法内出现错误时,错误不在方法内作处理,而是发出一个错误信息,把它传给调用的人,例如:方法1()----> 方法2()----> 方法3()
若是方法3()里出现了任何错误,因为方法3的逻辑代码已经很是复杂,所以方法3不想对任何错误作处理,那么它发出一条消息给调用它的方法2,假设方法2也比较复杂,为了减小本身的工做量,它也能够不作处理,而把这个错误消息再一次发送给调用它的方法1,若是方法1仍然不作处理继续把消息向上发送,最终就由虚拟机来接管了。
虚拟机是全部代码的执行者,所以它处理错误的方式比较粗暴!把错误的消息打印出来以后,就直接把程序终止了。
固然若是不想让某个错误影响到整个系统的运行,在方法内应该拦截这个错误消息,而且能够作出相应的错误处理。
固然,若是你犯懒的话,拦截了消息,不作处理也是能够的。例如:
try{ inta = 3/0; } catch (Exception e) { //不作任何处理 } //不影响下面代码执行 ...... ......
|
在JAVA中,错误消息都是以对象的形式自动向上级抛出的,固然你也能够定义本身的消息类型,手动抛出去。在JAVA中这种错误消息咱们称之为“异常”,若是一个异常在被抛出时没有任何捕获的动做,抛给上级后,上级也不作处理,最终就会抛给虚拟机,虚拟机不论错误的大小,一概都会打印错误信息并终止程序。
n 数据库复习(MySQL)
u 视图
² 建立一个虚拟表,虚拟表的数据由指定的select语句查询而得。
² 因为该表实际中没有数据,只是一个概念表,因此称之为视图
² 视图能够大大的简化查询语句,使得sql语句变得相对简单,例如在分布式系统中,程序的执行效率每每还会受到服务器之间的网速的影响。
所以,减小服务器之间通讯时的数据包大小,就变得尤其重要了。
服务器 |
远程数据库 |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX巨复杂的sql语句 |
发送到数据库时间: 0.04秒 |
使用视图以后
远程数据库 |
服务器 |
select * from view_a |
发送到数据库时间: 0.01秒 |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 事先在数据库里定义好的视图 |
这种好处,只有大数据量,高并发时,才会体现的出来
它跟存储过程有着一样的好处。
u 存储过程
² 它让咱们以编程的方式来定义一系列SQL语句
² 在存储过程中,咱们能够定义变量,运算。能够接受参数,能够返回结果,与自定义函数相似
² 而它的执行效率要高于使用JDBC操做数据库,因此不少时候,若是程序对操做数据库的执行速度要求很高的话,就应该尽可能多的使用存储过程来代替大量的JDBC代码。
l 练习:使用存储过程作分页查询
u 索引
² select * from student where city = 'beijing' and age = ......
u 事务
² 事务的隔离级别:
l Read Uncommitted(读取未提交内容)脏读
l Read Committed(读取提交内容)
l Repeatable Read(可重读)
可重复读隔离级别是最严格的隔离级别。在该隔离级别下,一个事务的影响彻底与其余并发事务隔离,脏读、不可重复的读、幻像读现象都不会发生。当使用可重复读隔离级别时,在事务执行期间会锁定该事务以任何方式引用的全部行。所以,若是在同一个事务中发出同一个SELECT语句两次或更屡次,那么产生的结果数据集老是相同的。所以,使用可重复读隔离级别的事务能够屡次检索同一行集,并对它们执行任意操做,直到提交或回滚操做终止该事务。可是,在事务存在期间,不容许其余事务的执行影响到这个事务正在访问的任何行。为了确保这种行为不会发生,锁定该事务所引用的每一行-- 而不是仅锁定被实际检索或修改的那些行。所以,若是一个事务扫描了1000行,但只检索10行,那么它所扫描的1000行(而不只是被检索的10行)都会被锁定。
l Serializable(可串行化)
u mysql 的存储引擎
² MyIsam 查询效率比较高,但不支持事务
² InnoDB 支持事务,查询效率略低,默认以聚簇索引方式存储
nJDBC(Java Data Base Connectivity)
u JDBC是一种技术规范,定义了链接数据库的方式。
Oracle |
JAVA |
Mysql |
SQLServer |
JAVA链接不一样的数据库,方法确定是不同的,每一个数据库都提供了本身特有的函数方法,所以须要使用不一样的JAVA-API来实现链接数据库。
例如链接Mysql的方法叫 connectMysql() 链接Oracle的方法叫connectOracle()
可是,这样作的话须要程序员去记住每一种方法的原理和特色以及使用方式。显然很是的麻烦
为了能让链接数据库变的更简单,JAVA定义了一个规范,规范中声明:
JAVA自己不提供任何链接数据库的代码,全部数据库企业本身来提供一套链接本身数据库的JAVA代码。可是!这套JAVA代码必需要遵循必定的规范,例如:全部的类都应该叫什么名字,每一个类应该有什么方法。当全部的API都遵循了这个规范,达到了统一。程序人员在使用JAVA代码链接不一样的数据库时,才能变得简单和易用。
所以JAVA自己提供了这样一套接口类和一些相关的辅助类,而没有任何链接数据库的代码实现,实现类都由数据库厂商本身来提供。
咱们把这些实现代码也称之为驱动程序
这样,当咱们再次使用JDBC链接数据库时,就变得简单多了
Oracle |
SQLServer |
JAVA |
Oracle提供的驱动程序 |
Mysql提供的驱动程序 |
SQLServer提供的驱动程序 |
JDBC接口 |
JAVA声明的规范 |
Mysql |
调用同一个方法,使用不一样的驱动,就能够链接不一样的数据库,这样用起来是否是感受爽多了呢? JDBC就像是一个万能转换器同样,帮咱们把不一样的实现代码屏蔽掉了,咱们只须要了解一个使用接口就能够了,这里再一次体现出了封装的思想!
u JDBC编程的步骤:
² 加载驱动 xxx.jar
² 实例化驱动类并注册给DriverMananger
Driver d = new com.mysql.jdbc.Driver(); DriverManager.registerDriver(d); |
² 自动注册驱动对象,这是推荐的写法
|
² 得到数据库链接(三个参数:一、数据库链接字符串 二、用户名 三、密码)
Connection conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "root", "root"); |
² 建立执行语句对象
Statement stmt = conn.createStatement(); |
² 执行SQL语句得到结果集对象
ResultSet rs = stmt.executeQuery("select * from student"); |
² 遍历并展现结果集
while(rs.next()) {
} |
² 关闭全部数据库链接资源
rs.close(); stmt.close(); conn.close(); |
u JDBC的异常处理
u 事务
conn.setAutoCommit(false); //关闭事务的自动提交 conn.commit();//手动提交 conn.rollback();//catch到异常时,事务进行回滚 |
u 批量处理
Statement stmt = null; stmt = conn.createStatement(); stmt.addBatch("insert into student values(null,'测试888',20)"); stmt.addBatch("update student set age = 199 where name = 'lisi'"); stmt.addBatch("update student set age = 204 where name = '测试52'"); int[] rscount = stmt.executeBatch(); for (int i = 0; i < rscount.length; i++) {
} stmt.close(); conn.close();
|
u PreparedStatement
预编译所带来的好处是巨大的,它不只提升了SQL语句的执行效率,还有效的防止了SQL注入
u JDBC调用存储过程
n 文件IO流java提供的一套读写文件的API
u 首先认识一下File类
² 这个类位于java.io包中
² 它是一个文件和目录路径名的抽象表示形式。
² 将文件读取到内存当中,或者在指定目录生成文件,都须要借助File类
u 什么是流?
数据源A |
数据源B
|
数据源(数据源能够是一个文件,也能够是内存里的一个数据块等)A传输数据到数据源B。须要在两个数据源之间创建一个管道,如同流水通常,数据从数据源A经过管道流入数据源B。这个创建出来的管道,咱们称之为流。数据从一个地方流向另外一个地方的时候,都须要用到流
u 从流的功能来划分:节点流 和 处理流
u 从流的方向上来划分:输入流 和 输出流
u 从流读取数据的大小上来划分:字节流 和 字符流
u 四大抽象类:InputStream(字节输入流)、OutputStream(字节输出流)、Reader(字符输入流)、Writer(字符输出流)
² FileInputStream、FileOutputStream
² 读写文件的输入和输出字节流
² FileReader、FileWriter
² 读写文件的输入和输出字符流
² BufferedInputStream、BufferedOutputStream
² 带缓冲的字符输入、输出流,是普通字节流的一种包装流,将它套接在普通字节流之上来使用。例如:
FileInputStream fis=newFileInputStream();
BufferedInputStream bis = newBufferedInputStream(fis);
fis字节输入流 |
带缓冲的字节输入流 |
² BufferedReader、BufferedWriter
² 带缓冲的字符流同理
² DataInputStream、DataOutputStream
² 数据处理流,容许以平台无关的方式将基本数据类型写入到磁盘中。
² ObjectInputStream、ObjectOutputStream
² 对象流可以将对象直接存储到磁盘中
² 对象的存储也称之为对象的序列化(串行化)要想实现对象的序列化,该对象的类必须实现Serializable接口
n 反射机制(重点!)
execute("System.out.println('sdfasdf')");
java全部的代码都是编译好以后才能执行的。没有动态执行语句的功能,所以它还称不上是一种动态语言。为了弥补这一缺陷,JAVA设计了反射这一律念
利用反射机制,JAVA在运行期间能够加载一个编译期间未知的class,获取它的构造,生成对象,给属性设值、调用其方法。而不须要将代码写死。
更直白的说: 即便我不知道类的名字,也能够动态加载这个类,并生成这个类的对象,并调用它的方法,而在个人代码当中并不会出现以下的语句:
Student stu = new Student();
stu.study();
所以至关于我作到了动态的执行代码的效果!
n 动态代理(重点!)
它的重要性没法形容,应用之广也是咱们不能想象的
它从根本上解决了面向切面编程的难点。让咱们能够拦截任意的方法
这里介绍的是JDK动态代理,它要求委托对象的类必须实现接口
除此之外还有Cglib的动态代理,是不须要实现接口的
代理对象proxy 方法a () 方法b (args...) 方法c (args...)
自定义的处理器 Handler |
委托对象atm 方法a () 方法b (args...) 方法c (args...)
|
MyHandler //利用反射机制执行请求的方法 invoke(proxy,method,args)
ATM atm |
JDK的动态代理要求委托对象的类必须实现一个接口,在生成代理对象时,会利用该接口来动态生成一个代理对象,它与委托对象有着如出一辙的方法,同时须要咱们自定义一个执行处理器(InvocationHandler)
在代理对象接收到方法调用的请求时,会执行处理器的invoke方法,这样的话,咱们只要在处理器invoke方法先后加上本身想要的代码,就能够作到方法的拦截了。
了解更多详情请登陆超人学院网站http://www.crxy.cn或者每周日晚八点半相约免费公开课 https://ke.qq.com/course/53102#term_id=100145289 具体详情请联系QQ2435014406