0% found this document useful (0 votes)
4 views29 pages

Java Note

该文档涵盖了Java编程中的多个重要主题,包括包装类、异常处理、字符串操作、随机数生成、迭代器、集合类的使用、泛型、事件处理、线程等。每个主题提供了基本概念、代码示例和注意事项,旨在帮助读者深入理解Java的核心特性和实现细节。文档结构清晰,便于查阅和学习。

Uploaded by

1079098794
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views29 pages

Java Note

该文档涵盖了Java编程中的多个重要主题,包括包装类、异常处理、字符串操作、随机数生成、迭代器、集合类的使用、泛型、事件处理、线程等。每个主题提供了基本概念、代码示例和注意事项,旨在帮助读者深入理解Java的核心特性和实现细节。文档结构清晰,便于查阅和学习。

Uploaded by

1079098794
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

目录

1. 关于包装类----------------------------------------------------------------1
2. 关于异常类----------------------------------------------------------------1
3. 关于 String 方法----------------------------------------------------------2
4. 关于 Random 方法---------------------------------------------------------3
5. 关于迭代器 Interator-------------------------------------------------3
6. ArrayList 与 Vector 的源码要点----------------------------------3
7. 关于 Map 中的键值对(K,V)问题-------------------------------------4
8. Collections 中 copy 方法的注意事项----------------------------5
9. HashSet 和 TreeSet 注意事项-----------------------------------------5
10. 泛型注意事项-------------------------------------------------------------6
11. 事件处理机制关系图-----------------------------------------------------6
12. 线程相关问题--------------------------------------------------------------6
13. 抽象类与接口的区别----------------------------------------------------10
14. 关于 IO 的注意事项----------------------------------------------------10
15. 关于 TCP 的注意事项--------------------------------------------------12
16. 关于 TCP 的相关指令---------------------------------------------------14
17. 关于 UDP 的注意事项-------------------------------------------------15
18. 关于反射的要点提及--------------------------------------------------16
19. 关于 JDBC 的要点提及------------------------------------------------19
20. 关于正则表达式的要点提及----------------------------------------22
21. 关于数据库连接池原理-----------------------------------------------24
22. 关于父类与子类的向上转型的注意事项------------------------24

作者:蒋智康

1
Note
1. 关于包装类>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(1)Integer
Integer in1=new Integer(1);
Integer in2=new Integer(1);
[Link](in1==in2);
像这样,输出的结果为 false,应为这里 new 了两个包装类,所以属于不同的地址
Integer in1=128;
Integer in2=128;
[Link](in1==in2);
像这样,输出的结果为 false,这里的值为 128,由于其值范围是-128~127
由于底层方法: public static Integer valueOf(int i) {
if (i >= [Link] && i <= [Link])
return [Link][i + (-[Link])];
return new Integer(i);
这里直接跳过了 if 语句,进入了第二个 return,所以又进行了 new 地址,从而由于地址不对而报 false.
(2) String
Person p1=new Person();
[Link]="aa";
Person p2=new Person();
[Link]="aa";
//p1 和 p2 都指向的堆
[Link]([Link]([Link]));//true 比较的是内容
[Link]([Link]==[Link]);//true 最终都指向同一个常量池
[Link]([Link]=="aa");//true 这里"aa"指向的是常量池

Person p3=new Person("aa");


Person p4=new Person("aa");
[Link]([Link](b));//false ,这里比较的是地址,除非.name
[Link](p3==p4);//false 这里的 p3 和 p4 是在两个不同的堆中,地址不相同,返
回 false
2. 关于异常类>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(1) throw 与 throws 的区别
throws 是一种异常处理的一种方式,位置:方法声明处;后面跟的是:异常类型
throw 是手动生成异常对象的关键字,位置:方法体中;后面跟的是:异常对象
int num=100;
if(!(num>=1&&num<=10)) {
throw new NumException("异常");
}
//自定义异常,这里继承的是运行异常,因为如果继承编译异常的话,还没运行就会进报错
class NumException extends RuntimeException{ //这里继承的运行时异常
public NumException(String string) {
super(string);}}
try {

1
String str="1234a";
int num2=[Link](str);
[Link]("result="+num2);
} catch (NumberFormatException e) {
//[Link]();
[Link]("异常信息:"+[Link]());
}finally {
[Link]("代码运行完毕!");
}
}
//finally,不管运行时包不报错,最终都会运行到 finally 中

3. 关于 String 方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(1) StringBuffer 类
StringBuffer 与 String 的区别:
String:保存的是字符串常量,里面的值不能更改,更新即更新地址,效率较低,复用率高
StringBuffer: 保存的是字符串常量,里面的值可以更改,更新即更新内容,效率较高
例:String s=”a”; //创建了一个字符串
s+=”b”; //实际上原来的”a” 字符串对象已经丢弃了,现在又产生了一个字符串,也就是 s+”b”=>”ab” 如果多次进行这些
改变串内容的操作,会导致大量副本字符串对象存留在内存中。
StringBuilder、StringBuffer 与 String 的选择:
1.如果字符串存在大量的修改操作,一般使用 StringBuffer 或 StringBuilder
2.如果字符串存在大量的修改操作,并在单线程时,使用 StringBuffer
3.如果字符串存在大量的修改操作,并在多线程时,使用 StringBuilder(线程不安全)
4.如果字符串存在很少的修改操作,被多个对象的引用,使用 String,比如配置信息等
串行化:对象的寿命通常随着生成该对象的程序的终止而终止。
对象通过写出描述自己状态的数值来记录自己,这个过程叫串行化.
int lastIndexOf(String/int ch) 返回指定字符在此字符串中最后一次出现处的索引。
int indexOf(String/int str) 返回指定子字符串在此字符串中第一次出现处的索引。
StringBuffer insert(int offset, char c) 将 char 参数的字符串表示形式插入此序列中。
例 1: 给每三个数字后面赋一个逗号分隔
String sale="123456789.98";
StringBuffer sb = new StringBuffer(sale); //使其串行化

for(int res=[Link](".")-3;res>0;res-=3) {//往前挪三位


sb = [Link](res, ",");
}
[Link](sb);
输出结果:123,456,789.98

例 2:输入形式为:xi jin ping 人名,以 ping,xi.J 的形式打印出来,J 为中间单词的首字母


String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。
static String format(Locale l, String format, Object... args)

2
使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
public static void setname(String name) {
String[] res = [Link](" "); //进行分隔
if ([Link] != 3) {
[Link]("格式错误");
return;
}
//进行格式化
name=[Link]("%s,%s.
%c",res[2],res[0],res[1].toUpperCase().charAt(0);
[Link](name);
}

4. 关于 Random 方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
若要获取一个 a~b 之间的一个随机数,则:
int num=(int)([Link]()*(b-a+1)+a);

5. 关于迭代器 Interator>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
boolean hasNext() 如果仍有元素可以迭代,则返回 true。
E next() 返回迭代的下一个元素。
Collection co = new ArrayList(); //向上转型
[Link](new Person("张三"));
[Link](new Person("李四"));
Iterator it = [Link](); //这里启用迭代器
while ([Link]()) {
next 部分源码(用 Object 类型原因):
Object[]elementData=[Link];
Object obj = [Link]();
[Link]("result=" + obj);
}
如果还想进行从头遍历的话,应该重置启用迭代器,因为之前迭代器的指针指向最后一个
重启迭代器:it = [Link](); 然后再进行遍历即可

6. ArrayList 与 Vector 的源码要点(ArrayList 线程不安全效率高,Vector 线程安全效率低)


[Link] 源码:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
int newLength = [Link](minGrowth, prefGrowth) + oldLength; //这里进行
扩容
if (newLength - MAX_ARRAY_LENGTH <= 0) {
return newLength;
}
return hugeLength(oldLength, minGrowth);
}

(1) 当创建 ArrayList 对象时,如果使用的是无参构造器,则初始 elementDate 容量为 0,第一次添加,则扩容

3
elementDate 为 10;如需要再次扩容,则扩容 elementDate 为 1.5 倍
(2) 如果使用的是指定大小的构造器,则初始 elementDate 容量为指定大小,如果需要扩容,则直接扩容 elementDate
为 1.5 倍.
[Link] 源码:
int oldCapacity = [Link];
int newCapacity = [Link](oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
capacityIncrement > 0 ? capacityIncrement : oldCapacity//这里进
行扩容
/* preferred growth */);
return elementData = [Link](elementData,
newCapacity);
(1) 当创建 Vector 对象时,如果使用的是无参构造器,默认 elementDate 容量为 10,
满后,按 2 被扩容;如果指定大小,则每次直接按 2 倍扩容.

7. 关于 Map 中的键值对(K,V)问题>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

(1)Key 的值不能重复(包括 null),Value 的值可以存在多个


源码:
if (e != null) { // existing mapping for key 当存在重复的键时
V oldValue = [Link];
if (!onlyIfAbsent || oldValue == null)
[Link] = value; //这里进行了值交换
afterNodeAccess(e);
return oldValue;
}

(2) 用迭代器的方式遍历 Map 集合


迭代器的优点:1.迭代器可以不了解集合内部的数据结构,就可以直接进行遍历
2.不暴露内部的数据,可以直接进行外部遍历
3.使用性强,基本所有的集合都能使用
例:使用 HashMap 添加三个员工对象,要求:键:员工 id 值:员工对象
并遍历显示工资>18000 的员工(员工类:姓名,工资,员工 id)
Map m=new HashMap();
[Link](1,new Employee("张三",10000,1));
[Link](2,new Employee("李四",20000,2));
[Link](3,new Employee("王五",30000,3));

第一种遍历:
Set key=[Link]();
for(Object k:key) {
Employee res=(Employee)[Link](k);
if([Link]()>18000)
[Link](k+"-"+[Link](k));}

4
第二种遍历:
Set<[Link]<K,V>> entrySet()返回此映射中包含的映射关系的 Set 视图。
public static interface [Link]<K,V>映射项(键-值对)。
Set entry=[Link](); //获取 K-V
Iterator it = [Link]();
while([Link]()) {
[Link] en=([Link])[Link](); //转换为 [Link] 型
Employee emp=(Employee)[Link](); //调用 Entry 类中的 getValue 方法
if([Link]()>18000) {
[Link](emp);
}
}
8. Collections 中 copy 方法的注意事项>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ArrayList arr = new ArrayList();
[Link]("a");
[Link]("l");
ArrayList arr1=new ArrayList();
[Link](arr1, arr); //这样的话会直接抛异常
源码:
//这里是先进行大小的比较,若原来的长度大于目标长度,则抛出越界异常
public static <T> void copy(List<? super T> dest, List<? extends T>
src) {
int srcSize = [Link]();
if (srcSize > [Link]())
throw new IndexOutOfBoundsException("Source does not
fit in dest");
解决方法: 将原来目标复制地点 arr1 初始化内存

9. 关于 HashSet 与 TreeSet>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
HashSet 与 TreeSet 分别的如何去重的:
(1) HashSet 去重机制:调用源码中的 hashCode()+equals()快捷键,对哈希值进行运算,得出一个索引值
即为要存放在哈希表中的位置号,如果该位置上没有其它元素,则直接存放,若有,则进行 equals 判断,不相同则加入,相同则不加入.
(2) TreeSet 去重机制:如果你传入了一个 Comparator 匿名对象,就使用 compare 去重,如果方法返回 0,
则认为相同,不添加;如果你没有传入一个 Comparator 匿名对象,则以你添加的 Comparable 接口的 compateTo 方
法进行去重。
TreeSet:
TreeSet tree=new TreeSet();
[Link](new per());
class per{}
以上代码会报异常,因为源码中继承了 Comparator 接口,但是未实现 Comparator 接口
源码:
Comparable<? super K> k = (Comparable<? super K>) key;
即把 per 转成 Comparator 类型
这时,就会报一个 [Link] 类型转换异常

5
解决方法:
在 per 类中,实现 Comparable 接口
class per implements Comparable{
@Override
public int compareTo(Object o) { //这里根据实际情况改写,默认是只返回一个值
return 0;
}}

10. 泛型注意事项>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
已知:CC 继承了 BB,BB 继承了 AA
ArrayList<Object> List1 = new ArrayList<>();
ArrayList<String> List2 = new ArrayList<>();
ArrayList<AA> List3 = new ArrayList<>();
ArrayList<BB> List4 = new ArrayList<>();
ArrayList<CC> List5 = new ArrayList<>();
如果调用 printCollection1 方法,则只有 List3,List4,List5 正确
如果调用 printCollection2 方法,则只有 List1,List3 正确(其中 List2 与 List3 没有关系)
// ? extends AA 表示 上限,可以接收 AA 类或者 AA 类的子类
public static void printCollection1(List<? extends AA> node) {
for (Object res : node) {
[Link](res);
}
}
// ? super 子类类名 AA:支持 AA 类以及 AA 类的父类,不限于直接父类
public static void printCollection2(List<? super AA> node) {
for (Object res : node) {
[Link](res);
}
}

11. 事件处理机制关系图>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

用户
事件
事件源
操作 事件监听者
事件处理方法

12. 线程相关问题>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(1) 当编译器中的线程代码运行时,可以在控制台中输入 jconsole ,来监控线程的执行情况。
(2) 线程的执行为 start 而不是 run 的原因
start 方法最终会执行其中的 run 方法,如果直接调用 run 方法来运行线程,则会没有真正的执行一个线程,而是一个串行化的
过程

6
当调用 start 方法时运行结果: 当调用重写 Thread 中的 run 方法时的运行结果为:
主线程 0 小猫喵喵喵!
小猫喵喵喵! 小猫喵喵喵!
主线程 1 小猫喵喵喵!
小猫喵喵喵! 小猫喵喵喵!
主线程 2 小猫喵喵喵!
小猫喵喵喵! 小猫喵喵喵!

简单来说,如果直接调用 run 方法的话,就不存在子线程之说,线程之间会一个一个的按照前后代码执行的顺序进行单独性的执行


start 源码: 可以看出,在 start 中,其实真正启动线程的为 start0 方法
public synchronized void start() {
boolean started = false;
try {
start0(); // 调用的这个
started = true;

返回对当前正在执行的线程对象的引用的名称: [Link]().getName()

(3)interrupt 中断非终止
void interrupt() 中断线程

例:
(这里定义每 10s 就运行 10 次输出语句,主线程输入五次后,也就是 5s,子线程被强制调用)
子线程:
for(int i=0;i<=9;i++){
[Link]("特朗普" + (++res)+[Link]().getName());
try {
[Link](10000);
} catch (InterruptedException e) {
// throw new RuntimeException(e);
[Link]([Link]().getName() + "休息被中断了");} }
主线程:
Thread thread=new Thread(new Dog());
[Link]();
for(int i=0;i<=4;i++){
[Link]("主线程"+(++mai)
+[Link]().getName());
[Link](1000);}
[Link](); //上面进行 5 秒后中断子线程的休息,使子线程继续调用

7
(4)线程的状态分析

一开始进入 NEW 至今尚未启动的线程的状态,因为刚刚进行创建;又因为这里调用了 start 方法,然后进入到


RUNNABLE 可运行线程的线程状态。然后就调用到了 sleep 进行了 TIMED_WAITING 具有指
定等待时间的某一等待线程的线程状态。最后,进程运行条件结束,所以为 TERMINATED 已终止线程的线程状
态。

8
9
(5) 线程中关于互斥锁的问题
同步方法如果没有使用 static 修饰(在代码块上写):默认对象为 this(要求是同一个对象)

如果方法使用 static 修饰,默认锁对象(在代码块上写):当前类.class

!!!注意事项!!!
若类继承的是 Thread 方法时,如果这时调用的是 synchronized(this)方法,且为多个线程时,这时就不再会像继承了 Runnable 接
口一样,将会导致”锁失效” 的现象

因为它会调用多个不同的对象,而不是同一个对象 运行结果

这时最好使用 Runnable 接口,可以多个线程对应同一个对象,如图所示:


运行结果

10
13. 抽象类与接口的区别>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
组成方面:
(1) 抽象类可以有构造方法,而接口不能有构造方法。
(2) 抽象类可以有普通成员变量,而接口中没有普通的成员变量。
(3) 抽象类可以有普通方法,而接口中没有普通方法等
访问修饰权限方面:
(4) 抽象类中抽象方法访问类型可以是 public/protected,但接口中的抽象方法只能是 public 类型的,并且默认为
public abstract 类型。
(5) 抽象类中的静态成员变量访问类型可以任意,但接口中定义的变量只能是 public static final 类型。
设计层面:
(6) 抽象类是对事物的抽象,描述的是一类抽象的概念,而接口的对共同行为的抽象
(7) 抽象类的一种模板式设计,若 A 为抽象类,B 和 C 都继承于 A,且他们的公共方法需要改动时,则改动时只需改动 A 即可。
(8) 接口类是一种辐射式设计,若接口进行了变更,则所有实现这个接口的类都必须进行相应的变更。

14. 关于 IO 流注意事项>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
输出流 是将数据从 编译器 -----> 文件
输入流 是将数据从 文件 -------> 编译器

(1) 在使用 Writer 的子类方法 时,一定要将其刷新 flush,不然会导致输入文件的数据丢失。

(2) 在使用 BufferedReader 或 BufferedWriter 字符流方法时,不要去操作二进制文件(声音,视频等) ,以免造成文件的损坏。

(3) 像 BufferedWriter( ) /BufferedReader( ) /BufferedInputStream( ) /BufferedOutputStream( )


这样,后面括号中传入的类型为 Writer /InputStream 等类型,其下包含着众多子类,所以括号中可以传入属于它们的任意子类进
行相关的操作。

(4) 序列化与反序列化:
序列化:在保存数据时,保存其数据的值和数据类型(静态 static 类不能进行序列化, 因为序列化保存的是对象的状态,
而 static 变量是属于类的状态)
反序列化:在恢复数据时,恢复数据的值和数据类型

这里使用 ObjectOutputStream 来进行序列化操作

如果需要序列化某个对象时,要实现接口 Serializable

这里使用 ObjectInputStream( ), 来进行反序列化操作

11
运行结果:

(5) 对文件中数字等进行单独操作

主函数

//Scanner useDelimiter(String pattern)将此扫描器的分隔模式设置为从指定 String 构造的模式。


其中,”[^0123456789.]+” 匹配所有非数字字符序列

这里将指定输入的字符串内容传入

实现函数

这里的 useDelimiter 方法:一般


Scanner 跳过所有流开头的空白符,然后进行信息检查,直到遇到后面的空白符为止,例:is good,结果会输出 is,因为有空白符,这时调
用该方法,将分隔符号修改为“回车”,或者其他字符,这样就可以将含有空白符的数据输出。

(6) 解决乱码相关问题 (转换流)


一开始,从文件中输出的内容是这样的,当时它的编码格式为 GBK

12
解决方法:
//InputStreamReader / OutputStreamWriter 是字节流通向字符流的桥梁

编这里运用 InputStreamReader 方法,先将字节流包装(转换)成字符流,最后再转为 BufferedReader,其中,将它的编码改为了


UTF-8,进而解决了之前的乱码问题。

输出结果:

这里运用 OutputStreamWriter ,可以将目标文件改为指定的编码并进行写入

15. 关于 TCP 的注意事项>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

(1) 关于客户端与服务器传输信息问题
在传输信息的过程中,当前面进行了 [Link]()时,应该在输出流后面添加结束标记
不然服务器与客户端都会造成停顿,等待消息,不会结束。
voi shutdownOutput()
d 禁用此套接字的输出流。
如图所示:

(2) 关于网络上传文件

13
程序/客户端 程序/服务器
文件数据/字节

Socket 数据通道 Socket


文件对应的字节数组
文件数据/字节

由于图片为二进制形式, 某个目录图片
磁盘上的图片
所以以字节数组的形式
进行存储

里面的具体转换方法在"D:\eclipse\[Link]" 中已实现

客户端:

这里就是将需要传入的文件转换成字节数组,然后打入到字节输出通道
(然后传入到服务端的 Socket 中)

服务器:

14
(1)这里拿到客户端打过来的数据,传入到字节数组中
(2)然后锁定需要传输新文件的位置,将之前存入的文件字节数组传入即可。

16. 关于 TCP 的相关指令>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

(1) netstat 指令
① netstat -an 可以查看当前主机网络的情况,包括端口监听情况和网连接情况
② Netstat -an|more 可以分页显示
说明:
(1) Listening 表示某个端口在监听
(2) 如果有一个外部程序(客户端)连接到该窗口,就会显示一条连接信息
(3) 可以输入 ctrl + c 退出指令

17. 关于 UDP 的注意事项>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

15
由于这里是 UDP,不存在服务器与客户端之说,只有接收端与发送端

这里的

既可以表示接收端,同时也可以表示发送端(即发送端等于接收端,接收端也等于输入端)

这里为发送端:

(1)添加 Socket 接口数据


(2)通过字节数组传输内容
(3)锁定相关端口,调用 Socket 中 send 方法进行传输

这里为接收端:

(1)创建一个足够大的字节数组,通过 Packet 方法,构造一个数据包

(2)这里写入一个 receive 进行类似于 TCP 中的 accept ,进行阻塞等待

16
(3)这里进行拆包操作,将其 数据长度 和 数据缓冲区 取出来,进行相应的输出

18. 关于反射的要点提及>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

(1)对于某个类的 Class 对象,在内存中只有一份,因为类只加载一份,无论你 new 多少个对象,其 hashCode 都是一样的(前提是为


相同的类)
equals 与 HashCode 的区别: 其中,equals() 相等的两个对象它们的 HashCode() 一定 相等;而 HashCode 相等的两
个对象,它们的 equals() 不一定相等

例:

运行结果:

(2)关于 静态加载 和 动态加载


静态加载:编译时加载相关的类,如果没有则进行报错,依赖性太强

这里还未曾输入就已经报错

17
动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不报错,降低了依赖性

这里将之前的 Dog 类注解,可见,虽然不存在该反射对象,但编译时并


没有报错。

(3)关于类加载(面试)

连接 Linking

验证 Verification
字节码文件
Java 运 加载
(二进制形式) 初始化
[Link] 行 Loading Initialization
准备 Preparation

Javac 编译 解析 Resolution

java 源码
[Link]

加载阶段: 将类的 class 文件读入内存,并为之创建一个 [Link] 对象,


此过程由类加载器完成。
连接阶段: 将类的二进制数据合并到 JRE 中,其中:
(1)验证部分:对文件进行安全的校验,比如文件格式,字节码是否正确之类
(2)准备部分:对静态变量分配内存,并且进行默认初始化(如 int,默认为 0)
(3)解析部分:虚拟机把常量池中的符号进行引用,替换为直接引用
初始化阶段:JVM 负责对类进行初始化,这里主要是指静态成员
初始化

18
(1) 到初始化阶段,才真正开始定义 java 程序代码,此阶段是执行 <clinit>() 方法的过程

(2) <clinit>() 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句包,并进行


合并。

(3) 虚拟机会保证一个类的 <clinit>() 方法在多线程环境中被正确的加锁、同步,如果多个线程去初始化一个类,那么只会有一个线程去执行这


个类的 <clinit>() 方法 ,而其他线程都需要进行阻塞等待,直到活动线程执行 <clinit>() 方法完毕

(4)关于反射的暴破操作及相关事项

(1)解决访问私有方法的问题

Declared 的意思是 公开声明的,所有方法得以访问,比如

(2)当用 Field 方法进行成员变量访问时,只有当成员方法为静态时,才可以用 null 代替

(5)相关反射
类访问方法的一般用法

19
传统方法:对象 . 方法() 反射机制:方法 . 某某调用(对象)

一开始,需获取该访问类的地址:
这里,如果使用 类 . class 的方法,由于在编译阶段就要检查是否有相关的类,所以缺乏灵活性
而调用 forName ( ) 方法时,在运行阶段才会进行相关类的检查,若没有则触发异常
所以一般调用以下方法:

构造方法:Constructor 赋值时,一般通过 newInstance(值...)进行赋值操作


成员方法:Method 赋值时,一般通过 invoke(Object obj,Object...值) 进行赋值操作
成员变量:Field 赋值时,一般通过 set(Object obj,Object...值) 进行赋值操作

(6)用反射创建文件

19. 关于 JDBC 的要点提及>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

(1)善于利用 Properties 进行编写

这里利用 Properties 语句进行连接,更具


有灵活性,同时将相关内容写入到文件中,方便更

这里为写入文件中的内容:

(2)(2)Statement 与
PrepareStatement 的执行 sql
时的用法区别

20
首先先进行建立连接:

(1)在 select 查找 方面

(2)在 dml (insert , update ,delete)增 删 改 方面(不需要使用 ResultSet 方法)

这里一般用 PrepareStatement ,以消除注入问题

(3)JDBC 关于事务回滚的操作

事务定义:是用户定义的一个操作系统序列,这些操作要么全部执行,要么全部不执行, 是一个不可切分的工作单元。

由于每条单独的语句都是一个事务,每条语句后都隐含着一个
commit (默认);所以,这里首先将其设为不自动提交事务模式

回滚定义:
// void rollback()
//即在事务运行过程中当某一原子操作发生异常时,事务不能继续运行
//系统将事务已完成的操作全部撤销,将数据回滚到事务开始的状态。

21
由于在修改 sql 语句间发生了异常,所
以这里要进行回滚操作。

Mysql 相关表中原数据: 没有回滚的 进行了回滚的 (发生异常时) (发生异常


时)

(4)JDBC 关于批处理

传统的批量处理:

此处理方式效率低,编译的次数多,运行的次数多

批处理:批处理往往与 PreparedStatement 一起搭配使用,可以减少编译的次数,又减少了运行次数,效率大大的提高。

在此之前,要在 url 语句中添加相应的条件信息:?rewriteBatchedStatements=true

addBatch();添加需要批量处理的
sql 语句或参数

executeBatch(); 执行批量处理
语句
clearBatch(); 清空批处
理包的语句

22
20. 关于正则表达式的要点提及>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

(1)关于 Pattern 与 Matcher 方法

这里运用 Pattern 方法进行正则表达式的接收操作,用


Matcher 方法进行原文本的匹配工作

同时,这里的 (?i) 表示所在位置右侧的表达式开启忽略大小写模


用这个方式去匹配字符时,一般 index 中开头以 ^ 开头,结尾


以 $ 结尾,这样可以锁定具体的格式。

(2)关于分组操作
这里表示为分组操作:

这里的 0 是默认输出全部,1、2 则是输出以上进行分组的对应匹


配值

运行结果:

(3)关于 Matcher 中的 matches 方法

输出结果:

这里可以看出,当用 matcher 方法时


是进行内容筛查,而 matches 是对整
体的一种匹配(boolean)

(4)关于分组、捕获、反向引用

23
(1)分组、捕获
这里是找出所有连续两位相同的数字 这里是找出所有连续的五位相同的数字

这里的\\1 表示将(\\d)所代表的数字 这里的表示将(\\d)所代表的数字引用反向引用一次


一次,然后再接着引用四次

运行结果: 运行结果:

例:匹配若干个个位与千位相同、十位与百位相同的数,如:5225,1551

答案:(\\d)(\\d)\\2\\1,这里\\2 的意思是在此位置,将第二个(\\d)所匹配到的数字再引用一次,而\\1 的意思是将第一个(\\


d)所匹配的数值引用到当前位置上来。

!!!!!!!!!!!!!!!!!注意!!!!!!!!!!!!!!!!!!

如果正则表达式发生了变化,需要在当前语句下面重置一下
不然还停留在原来的正则表达式中,导致结果输出错误

(2)反向引用

结巴去重案例:
这里的 $1 表示的是将 (.)\\1+ 中重复出现的
数字中的第一个被分组的(.)获取到,以将所有重复的
字中替换成重复字中第一个被分组的字。

输出结果:

21. 关于数据库连接池原理

JAVA 程序
24 连接池
1. 从连接池取出连接
连接 1
2. 使用连接,操作 mysql
3. 连接放回连接池
(连接可以复用) 连接 2
等待队列
等待队列的作用:若连接池中有连接,则直接拿过来用;若连接池中没有连接,则等待其 它 JAVA 程序使用完 ”放回去”
后,再拿过来用。
这里的”放回去”是指:程序用完后,断开与其的连接,但是连接的本身还在,给下次需要使 用的程序使用。

(1)Apache 阿帕奇连接数据库的相关事项

进行阿帕奇的连接时,要与 Druid 德鲁伊工具类配合使用

在进行资源关闭时,不需要
将 ResultSet 与
Statement 类进
行关闭

源码:

这里 query() 方法中的底层进行了关闭

返回多行多列 sql

返回单行多列 sql

返回单行单列 sql
(2)BasicDAO 的示意图

TestDAO
1. 根据业务需求,使用对应的 DAO
BasiscDAO 2. 体现出各司其职,清晰业务

1. 将各个 DAO 共同操作,放到这里


25
2. 简化代码,提高维护性与可读性
ActorDAO 还有其他各种不同的表
完成对 Actor 表的增删改查 分别完成其对应的功能与相关操作......
还有部分特有的操作

这里定义 BasicDAO 方法时,使之


调用泛型,以承接需要相关功能的 Mysql

同时,方法中,一般与德鲁伊工具 这里存放着各种表,如
Actor 表
类相辅相成,以提高效率

这里如果要使表 ActorDAO 实现 DAO 功能,则继承 BasicDAO


中的方法,并使泛型变为 Actor 类

22. 关于父类与子类的向上转型的注意事项

26
(1) 向上 转型的对象
不能访问子 类新增的成
员变量
(2) 如果 子类重写了
父类的实例 方法,则上
转型调用时 一定调用了
子类重写的 实例方法
(通常)

(3) 如果 子类重写了
父类的静态 方法,那么
子类上转型对象不能调用子类重写的静态方法,只能调用父类的静态方法(注意!!!!!!!!!!!)

27
28

You might also like