Friedy's blog Friedy's blog
首页
  • 《Vue》笔记
  • 《JavaScript教程》笔记
  • 小程序笔记
  • 《CSS》笔记
  • 《HTML》笔记
  • 《Java》笔记
  • 《SpringBoot》笔记
  • 《SpringCloud》笔记
  • 机器学习笔记
  • 深度学习知识点总结
  • 大模型学习笔记
  • 面试经验
  • 友情链接
关于
  • 网站
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Friedy

全栈攻城狮
首页
  • 《Vue》笔记
  • 《JavaScript教程》笔记
  • 小程序笔记
  • 《CSS》笔记
  • 《HTML》笔记
  • 《Java》笔记
  • 《SpringBoot》笔记
  • 《SpringCloud》笔记
  • 机器学习笔记
  • 深度学习知识点总结
  • 大模型学习笔记
  • 面试经验
  • 友情链接
关于
  • 网站
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础
  • 技巧
  • 进阶
    • 集合
      • Collection
      • 迭代器
      • List
      • LinkedList
      • Map
      • 哈希表的数据结构
      • TreeSet
      • Collections
    • 泛型
      • 泛型通配符
    • 静态导入
    • 可变参数
    • 枚举
    • 异常
      • 异常继承体系图
      • 处理异常的两种方式
      • 自定义异常
      • final、finally、finalize
      • 异常注意事项
    • IO 流
      • IO 流的释义
      • IO 流的分类
      • 文件专属流
      • 转换流
      • 缓冲流
      • 数据流
      • 标准输出流
      • 序列化与反序列化
      • File 类
  • 高级
  • 《Java》笔记
friedy37
2024-06-09
目录

进阶

# 集合

数组和集合类同是容器,区别在于:1、数组虽然也可以存储对象(对象数组),但长度是固定的,集合长度是可变的;2、数组可存储基本数据类型,但集合只能存储对象的内存地址(引用),且集合可存储不同类型的对象

集合继承体系图:

  • ArrayList:底层数据结构是动态数组,默认初始化容量为 10(底层先创建了一个长度为 0 的数组,当添加第一个元素的时候,初始化容量为 10),自动扩容(扩容到原容量的 1.5 倍),支持随机访问,查询快,增删慢,非同步,线程不安全,效率高
  • Vector:底层数据结构是动态数组,查询快,增删慢,同步,线程安全,效率低
  • LinkedList:底层数据结构是双向链表,不支持随机访问,查询慢,增删快,非同步,线程不安全,效率高

# Collection

  • Collection 中的常用功能(以下功能的结果遵循谁调用这个方法谁就改变)
1、添加功能
boolean add(Object obj);//添加一个元素
boolean addAll(Collection c);//添加一个集合的元素

2、删除功能
void clear();//移除所有元素
boolean remove(Object o);//移除一个元素
boolean removeAll(Collection c);//移除一个集合的元素,只要有一个元素被移除就返回true

3、判断功能
boolean contains(Object o);//判断集合中是否包含指定元素
boolean containsAll(Collection c);//判断集合中是否包含指定的集合元素,只有包含所有元素才叫包含,才返回true
boolean isEmpty();//判断集合是否为空

4、长度功能
int size();//这里获取的是元素的实际个数,不是集合的容量

5、交集功能
/*
	设有两个集合A、B
	A.retainAll(B);
	若A、B之间有交集就把交集保存到集合A中,若无交集,那么集合A就为空,
	至于返回结果则取决于保存交集的A集与保存之前的集合内容是否有变化,
	有变化就返回true,没有变化就返回false
*/
boolean retainAll(Collection c);

6、集合转数组
Object[] toArray();//转型后的数组中每一个元素都是Object类型的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 迭代器

集合的迭代也叫集合的遍历,集合的迭代是通过迭代器完成的,迭代器是依赖于集合而存在的,也就是有集合才有迭代器

  • 迭代器(集合的专用遍历方式)
Iterator<E> iterator();
1
  • Iterator 接口中的方法:
Object next();//获取元素之后自动后移
boolean hasNext();//判断是否还有元素,如果仍有元素可以迭代就返回true
1
2
  • 迭代举例
Collection c = new ArrayList();
方式一:
Iterator it = c.iterator();//通过集合对象获取迭代器对象
while(it.hasNext())
{
	System.out.println(it.next());
}

方式二:
for(Iterator it = c.iterator(); it.hasNext();)
{
	System.out.println(it.next());
}

总:方式一结构清晰;方式二效率更高,运行更快,因为it循环之后就变成垃圾
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

问:迭代器为什么不定义成一个类,而定义成一个接口?
答:Java 中提供了很多的集合类,而这些集合类的数据结构是不同的,意味着它们的存储方式和遍历方式也各不相同,遍历一个集合应当具备判断功能和获取功能,因每种集合的方式不太一样,所以把这两个功能提取出来,这种方式就是接口,这个接口的实现类是以内部类的方式体现的

# List

  • List 集合:有序的 Collection(也称为序列),此接口的用户可以对列表中每个元素的插入位置进行精确控制,用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素,与 Set 不同的是 List 允许重复的元素
  • List 集合的特点:1、有序(存储和取出的元素顺序一致);2、可重复
  • List 集合特有的遍历
List  c = new ArrayList();
for(int i = 0; i < c.size(); i++)
{
	System.out.println(c.get(i));
}
1
2
3
4
5
  • List 集合特有的迭代器(列表迭代器)
列表迭代器:ListIterator listIterator();
该迭代器继承了Iterator迭代器,所以也可直接使用hasNext()和next()

列表迭代器特有的功能:
逆向遍历:
	Object previous();//获取上一个元素
	boolean hasprevious();//判断是否有元素
正向遍历:
	Object next();
	boolean hasNext();

注:ListIterator可以实现逆向遍历,但是必须同一迭代器正向遍历之后才能进行逆向遍历,无实际意义,一般不使用
1
2
3
4
5
6
7
8
9
10
11
12

# LinkedList

  • LinkedList 集合特有的功能
1、添加功能
public void addFirst(Object o);//开头添加
public void addLast(Object o);//结尾添加

2、获取功能
public Object getFirst();//获取开头元素
public Object getLast();//获取结尾元素

3、删除功能
public Object removeFirst();//删除开头元素并返回被删除元素
public Object removeLast();//删除结尾元素并返回被删除元素
1
2
3
4
5
6
7
8
9
10
11

# Map

  • Map 集合:Map 集合中键和值的关系——映射,可以通过键来获取值
  • Map 集合的特点:将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值(无序不重复)
  • Map 集合与 Collection 集合的区别:1、Map 集合存储元素是成对出现的(键值对),Map 集合的键是唯一的,值是重复的,Collection 集合存储元素是单独出现的,Collection 的 Set 是唯一的,List 是可重复的;2、Map 集合的数据结构针对键有效,跟值无关,Collecton 集合的数据结构针对元素有效
  • 给定一个键和一个值就可以将该值存储在一个 Map 对象中,之后可通过键来访问对应的值
  • 当访问的值不存在的时候,方法就会抛出一个 NoSuchElementException 异常
  • 当对象的类型和 Map 里元素类型不兼容时,方法就会抛出一个 ClassCastException 异常
  • 当在不允许使用 Null 对象的 Map 中使用 Null 对象时,方法就会抛出一个 NullPointerException 异常
  • Map 集合中常用的功能:
1、添加功能
/*
(key表示键,value表示值)如果键是第一次存储就直接存储元素并返回null,
如果键不是第一次存储就用现在的值把以前的值替换掉并返回以前的值
*/
v put(k key, v value);

2、删除功能
void clear();//移除所有的键值对元素
v remove(Object key);//根据键删除键值对元素并把值返回

3、判断功能
boolean containsKey(Object key);//判断集合中是否包含指定的键
boolean containValue(Object value);//判断集合是否包含指定的值
boolean isEmpty();//判断集合是否为空

4、长度功能
int size();//返回集合中键值对的对数

5、获取功能
v get(Object key);//根据键来获取值
Set<K> keySet();//获取集合中所有键的集合
Collection<V> values();//获取集合中所有值的集合
Set<Map.Entry<K,V>> entrySet();//返回的是键值对对象的集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  • Map 集合的遍历

Hashtable 与 HashMap 的区别:

  • Hashtable:线程安全,效率低,不允许 null 键和 null 值,初始容量为 11,扩容是:原容量 * 2+1
  • HashMap:线程不安全,效率高,允许 null 键和 null 值

# 哈希表的数据结构


注:

  • 如果一个类的 equals() 方法重写了,那么它的 hashCode() 方法必须重写
  • 放在 HashMap 集合 Key(键)部分的和放在 HashSet 集合中的元素需要同时重写 hashCode() 方法和 equals() 方法
  • 为了提高检索效率,在 JDK8 之后,如果哈希表的单向链表中元素大于等于 8 个 并且 数组长度大于等于 64 时,单向链表这种数据结构才会变成红黑树数据结构,如果数组长度小于 64 则会先将数组进行一次扩容(2 倍),如果扩容之后还没有达到长度 64 则继续比较下一个节点,链表不会转成红黑树,直到 table 数组长度大于等于 64 时单向链表才会变成红黑树,当红黑树上的节点数量小于 6 时,会重新把红黑树变成单向链表
  • HashMap 的默认初始化容量是 16(建议是 2 的倍数),加载因子是 0.75(当哈希表的元素超过总容量的 75% 时,哈希表将自动开始扩容(原容量 * 2)

# TreeSet

TreeSet 集合底层实际上是一个 TreeMap,也就是一个二叉树,放到 TreeSet 集合中的元素等同于放到 TreeMap 集合的 Key(键)部分了,TreeSet 集合中的元素无序不重复,可以按照元素的大小顺序自动排序

重点:
TreeSet 集合自动排序的特点是通过实现 java.lang 包下 Comparable 接口或 java.util 包下的 Comparator 接口来完成的,即要指定比较规则。如 String、Integer 等已经默认实现了 Comparable 接口,所以 TreeSet 中的 String、Integer 就不用再指定比较规则了,而放到 TreeSet 或 TreeMap 集合 key 部分的自定义元素要想做到排序就必须指定比较规则,有如下两种方式:

  1. 自定义元素实现 Comparable 接口中的 compareTo() 方法,在 compareTo() 方法中指定比较规则,这时 TreeSet 或 TreeMap 集合的构造方法是无参构造

  2. 在构造 TreeSet 或 TreeMap 集合时,用匿名内部类的方式实现比较器 Comparator 接口中的 compare() 方法(也可以单独建一个比较器类实现 Comparator 接口),在 compare() 方法中指定规则,这时 TreeSet 或 TreeMap 集合的构造方法是带参构造

说明:compareTo() 方法的返回值:

  • 返回值 0 表示相同,value 会覆盖
  • 返回值大于 0,会继续在右子树上找(左小右大)
  • 返回追小于 0,会继续在左子树上找(左小右大)

问:Comparable 和 Comparator 怎么选择
答:当比较规则不会发生改变的时候,或者说当比较规则只有一个的时候建议使用 Comparable 接口,如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用 Comparator 接口

# Collections

Collections 是针对集合进行操作的工具类,其中的方法都是静态的

Collection 与 Collections 的区别:

  • Collection:是单列集合的顶层接口,有子接口 List 和 Set
  • Collections:是针对集合操作的工具类

Collections 类中的常用方法:

1、排序,默认情况下是自然排序
public static <T> void sort(List<T> list);

2、二分查找
public static <T> int binarySearch(List<?> list,T key);

3、最大值(根据元素的自然顺序)
public static <T> T max(Collection<?> coll);

4、最小值
public static <T> T min(Collection<?> coll);

5、随机转换
public static void shuffle(List<?> list);

6、反转
public static void reverse(List<?> list);

7、将线程不安全的List转换成线程安全的List(Set和Map也有类似的方法)
public static <T> List<T> synchronizedList(List<T> list);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 泛型

泛型是一种把数据类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型,也叫参数化类型,把类型当作参数一样传递

  • 泛型的格式:
<数据类型> 注:这里的数据类型只能是引用类型

例:ArrayList<String> array = new ArrayList<String>();//array这个集合中所有元素都是String类型的,且只能是String类型的
1
2
3
  • 泛型的好处:1、把运行时期的问题提前到了编译期间;2、避免了强制类型转换;3、优化了程序设计;4、增强了程序的安全性
  • 看 API,如果类、接口、抽象类后面跟有 就表示要使用泛型,一般来说在集合中使用的情况居多

# 泛型通配符

  • <?>:任意类型,如果没有明确,那么就是 Object 以及任意的 Java 类了
  • 泛型如果明确时前后必须一致
  • ?表示任意的类型都可以(后面 new 的类型是任意引用类型)
Collection<?> c1 = new ArrayList<Object>();
Collection<?> c2 = new ArrayList<Animal>();
Collection<?> c3 = new ArrayList<Dog>();
1
2
3
  • <? extends E>:向下限定,后面 new 的类型必须是 E 及其子类
Collection<? extends Animal> c = new ArrayList<Dog>();//Dog继承类Animal
1
  • <? super E>:向上限定,后面 new 的类型必须是 E 及其父类

# 静态导入

可以直接导入到静态方法的级别

  • 静态导入格式
import static 包名.类名.方法名;

import static java.lang.System.out;
out.println("java");
1
2
3
4
  • 方法必须是静态的
  • 当有多个同名静态方法时,就必须加前缀使用了,即用静态导入的方法是唯一的

# 可变参数

  • 当定义方法的时候不确定该定义多少个参数时就使用可变参数
public int sum(int...a);//这里必须是三个点
1
  • 可变参数本质上是一个数组
  • 如果一个方法有可变参数,并且有多个参数时,可变参数必须写在最后面
public int sum(int b, int c, int...a);
1
  • 一个方法只能指定一个可变参数

# 枚举

枚举(enum)是一种引用数据类型,编译之后生成 class 文件,枚举中的每一个值可以看作常量

枚举语法格式;

enum 枚举类型名
{
	枚举值1, 枚举值2, 枚举值3...
}
1
2
3
4

说明:结果只有两种情况的建议使用布尔类型,结果超过两种并且可以一枚一枚列举出来的建议使用枚举类型,如颜色、四季、星期等都可以使用枚举类型

下列程序只是为了演示枚举语法,并无实际开发意义:

# 异常

# 异常继承体系图

  • 错误:错误不是异常而是脱离程序员控制的问题,Java 程序通常不捕获错误,错误一般发生在严重故障时,它们在 Java 程序处理的范畴外
  • 编译时异常:也叫受检异常或受控异常,编译时异常不是在编译阶段发生的(所有的异常都发生在运行阶段),它表示必须在编译(编写)程序的时候预先对这种异常进行处理,如果不处理编译器就报错(直接父类为 Exception 的异常称为编译时异常)
  • 运行时异常:也叫未受检异常或未受控异常,Runtime Exception 的子类称为运行时异常,运行时异常在编译阶段可处理也可不处理
  • 异常在 Java 中以类的形式存在,每一个异常类都可以创建异常对象
  • 不管是错误还是异常都是可抛出的,所有的错误只要发生,Java 程序只有一个结果,那就是终止程序的执行,退出 JVM,因为错误是不可处理的

# 处理异常的两种方式

  1. 在方法内部使用 try…catch… 语句进行异常捕捉,可理解为异常自行处理

try…catch… 语法格式:

try{
	//可能出现异常的代码
}catch(异常类名 变量名){
	//针对异常的提示处理
}finally{
	//不管try内有没有异常出现,finally语句块中的语句一定执行
	//这里一般是资源的释放和关闭
}

注:
1、虽然说所有的异常类名都可写Exception,但异常类名能明确就明确,方便调错
2、try语句块中的某一行出现异常该行后面的代码不会执行,只有在try...catch...捕捉异常后,后续代码才可执行
3、当try语句块中有return时,finally中的语句也会执行,且return语句在finally之后执行,也就是最后执行
4、如果在执行finally之前JVM退出了(System.exit(0)),那么就不会再执行finally里的语句了
1
2
3
4
5
6
7
8
9
10
11
12
13
14

出现多个异常时:

方式一:针对每一个异常写一个try...catch...
	
	方式二:将异常集中在一个try中,多个catch
	try{
		...
	}catch(异常类名1 变量名){
		...
	}catch(异常类名2 变量名){
		...
	}

注:平级关系的异常谁前谁后无所谓,如果出现父子关系,那么父必须出现在子的后面,否则会报错
1
2
3
4
5
6
7
8
9
10
11
12

JDK8 的一个新异常处理方式

try{
	...
}catch(异常类名1 | 异常类名2 | ... 变量名){
	...
}

注:这个方法很简洁,特点是处理方式一致,且多个异常间必须是平级关系
1
2
3
4
5
6
7

异常对象有两个重要的方法

1、获取异常简单的描述信息
public String getMessage();

2、打印异常追踪的堆栈信息
public void printStackTrace();
1
2
3
4
5

例:

  1. 在方法声明的位置上使用 throws 关键字,将异常抛给调用者处理(上抛),调用者也面临这两种处理方式

语法格式:

throws 异常类名(可以跟多个异常类名)
1

  • throws:用于方法声明后面,其后跟的是异常类名,将异常上抛给调用者处理,抛出的异常可能会发生
  • throw:手动抛异常,用在方法体内,其后跟的是异常对象名,且只能抛出一个异常对象,抛出的异常一定会发生。注意:1、当抛出的是编译时异常就必须与 throws 连用(因为编译时异常必须处理),而抛出的是运行时异常就不必与 throws 连用(因为运行时异常可处理也可不处理)。2、只要异常没有被捕捉,采用上抛的方式,此方法的后续代码不会执行
public static void myException() throws ClassNotFoundException
{
	Class.forName("文件路径");
	//因为异常只是被上抛,没有被处理,所以以下代码不会执行
	System.out.println("Hello");
}
1
2
3
4
5
6

如果方法内部可以将异常处理就用 try,如果内部处理不了就用 throws 上抛

# 自定义异常

分两步:

  1. 编写一个类继承 Exception 或 Runtime Exception,要编写编译时异常就继承 Exception,如果编写运行时异常就继承 Runtime Exception
  2. 提供两个构造方法,一个无参构造,一个带有 String 参数的构造方法
public class MyException extends Exception //编译时异常
{
	public MyException()
	{
		
	}
	public MyException(String s)
	{
		super(s);
	} 
}
1
2
3
4
5
6
7
8
9
10
11

# final、finally、finalize

  • final:关键字,表示最终,修饰类时类不能被继承,修饰方法时方法不能被重写,修饰变量时变量变常量
  • finally:关键字,是异常处理的一部分,用于释放资源,一般来说其中的代码肯定会执行,特殊情况:在执行到 finally 之前 JVM 退出了
  • finalize:标识符,Object 类的一个方法,用于垃圾回收

# 异常注意事项

  • 子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类
  • 如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内部有异常产生,那么子类只能 try…catch…

# IO 流

# IO 流的释义

IO 流是数据传输的通道 / 管道,是实现数据输入和输出的基础,通过 IO 流可以完成硬盘文件的读和写

# IO 流的分类

按照流的方向进行分类(以内存作为参照物):

  • 输入流:数据从硬盘到内存里去叫作输入或读,可理解为读进去
  • 输出流:数据从内存中出来到硬盘叫作输出或写,可理解为写出来

按照数据的读取方式进行分类:

  • 字节流:按照字节的方式读取数据,一次读取一个字节 byte,等同于一次读取 8 个二进制位,这种流是万能的,什么类型的文件都可以读取,包括:文本文件、图片、声音文件、视频文件
  • 字符流:按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,但这种流不能读取:图片、声音、视频等文件,只能读取纯文本文件,也读不了 word 文件

总:在 Java 中只要类名以 “Stream” 结尾的都是字节流,以 “Reader/Writer” 结尾的都是字符流

  • 字节输入流:InputStream
  • 字节输出流:OutputStream
  • 字符输入流:Reader
  • 字符输出流:Writer

注:1、以上所有的流都实现了 Closeable 接口,表明所有的流都可以关闭,都有 close() 方法,切记用完流之后一定要关闭流。2、所有的输出流都实现了 Flushable 接口,表明所有的输出流都是可以刷新的,都有 flush() 方法,输出流在最终输出完后一定要记得 flush() 方法刷新一下,这个刷新表示将通道当中剩余未输出的数据强行输出完(清空通道),如果没有 flush() 方法可能为导致数据丢失

# 文件专属流

  • 字节输入流(FileInputStream)
常用方法

1、返回流当中剩余的没有读到的字节数量
public int available();

2、跳过n个字节不读
public long skip(long n);

3、返回读到的字节值,每次读一个字节,读完自动后移,文件读完返回-1
public int read();

4、将读到的内容存入字节数组中,且最多读入b.length个字节,返回读到的字节总数,文件读完返回-1
public int read(byte[] b);
1
2
3
4
5
6
7
8
9
10
11
12
13
  • 字节输出流(FileOutputStream)
常用方法

1、将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流
public void write(byte[] b, int off, int len);
1
2
3
4
  • 字符输出流与字符输入流的常用方法与以上的区别在于把 byte 数组换成了 char 数组

文本复制:

用字节流完成文本复制
FileInputStream fis = null;
		FileOutputStream fos = null;
		try{
			//创建字节输入流对象
			fis = new FileInputStream("src/lianxi_io/myio_1");
			//创建字节输出流对象,true表示追加
			fos = new FileOutputStream("src/lianxi_io/myio_2", true);
			
			byte[] bytes = new byte[1024];
			int rcount = 0;
			while((rcount = fis.read(bytes)) != -1)
			{
				fos.write(bytes, 0, rcount);
			}
			//输出流刷新(刷新缓冲区)
			fos.flush();
		} catch (FileNotFoundException e){
			
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		} finally {
			//关闭流
			if(fis != null)
			{
				try{
					fis.close();
				} catch (IOException e){
					e.printStackTrace();
				}
			}
			
			if(fos != null)
			{
				try{
					fos.close();
				} catch (IOException e){
					e.printStackTrace();
				}
			}
		}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 转换流

  • InputStreamReader
通过构造方法将字节输入流转换为字符输入流
public InputStreamReader(InputStream in);
1
2
  • OutputStreamWriter
通过构造方法将字节输出流转换为字符输出流
public OutputStreamWriter(OutputStream out);
1
2

注:当一个流的构造方法中需要一个流的时候,这个被传进来的流叫作节点流,外部负责包装的这个流叫包装流或处理流,只需关闭包装流就行,当包装流关闭后节点流会自动关闭

# 缓冲流

缓冲流是为了提高数据的读写速度而存在的,因为缓冲流自带缓冲区,不需要再定义数组

  • BufferedReader
  • BufferedWriter
  • BufferedInputStream
  • BufferedOutputStream

注:其中 BufferedReader 的特殊方法

一次读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达文本末尾,则返回 null 
public String readLine();
1
2

# 数据流

数据流中 DateOutputStream 可以将数据连同数据的类型一并写入文件中,这个文件不是普通的文本文件,用记事本打不开,只能使用 DateInputStream 去读,并且读的时候需要与写的顺序一致才可以正常取出数据

# 标准输出流

  • printStream
  • printWriter

标准的输出流默认输出到控制台

System.out.println("Hello");
1

改变输出方向, 输入到指定文本中

PrintStream ps = new PrintStream(new FileOutputStream("src/lianxi_io/myio_1", true));
//改变输出方向
System.setOut(ps);
1
2
3

# 序列化与反序列化

  • 序列化:Java 对象按照流的方式存入文本文件或网络中,将 Java 对象的状态保存下来的过程,通过 ObjectOutputStream 完成(对象 ----> 流数据)
  • 反序列化:将硬盘上的流数据重新恢复到内存中,恢复成 Java 对象,通过 ObjectInputStream 完成(流数据 ----> 对象)
  • 参与序列化和反序列化的对象必须实现 serializable 接口
  • serializable 接口只是一个标志接口,这个接口当中什么也没有,它是给 JVM 参考的,当 JVM 识别到这个接口后,就会为实现该接口的类自动生成一个序列化版本号用来标识类
  • Java 虚拟机识别一个类的时候先通过类名,如果类名一致就再通过序列化版本号
  • 凡是一个类实现了 serializable 接口,建议手动给该类提供一个固定不变的序列化版本号,这样,以后这个类即使被修改了但是版本号没有变,Java 虚拟机也会认为是同一类
private static final long serialVersionUID= 1L;
1
  • 在实现 serializable 接口的类中若不想某个成员变量被序列化,可用 transient 关键字声明

实例:

序列化
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class IoTest
{
	public static void main(String[] args)
	{
		ObjectOutputStream oos = null;
		try{
			//序列化
			oos = new ObjectOutputStream(new FileOutputStream("src/lianxi_io/myio_1"));
			
			oos.writeObject(new Student("xss", 23));
			oos.writeObject(new Student("xxx", 34));
			
			oos.flush();
		} catch (FileNotFoundException e){
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		} finally {
			try{
				oos.close();
			} catch (IOException e){
				e.printStackTrace();
			}
		}
	}
}

class Student implements Serializable
{
	//手动固定序列化版本号
	private static final long serialVersionUID = 2L;
	private String name;
	private int age;
	private String address;

	public Student()
	{

	}

	public Student(String name, int age)
	{
		super();
		this.name = name;
		this.age = age;
	}

	public String toString()
	{
		return "Student []";
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
反序列化
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class lianxi
{
	public static void main(String[] args)
	{
		ObjectInputStream ois = null;
		try{
			//反序列化
			ois = new ObjectInputStream(new FileInputStream("src/lianxi_io/myio_1"));
			
			Object obj1 = ois.readObject();
			System.out.println(obj1);
			Object obj2 = ois.readObject();
			System.out.println(obj2);
		} catch (FileNotFoundException e){
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		} catch (ClassNotFoundException e){
			e.printStackTrace();
		} finally {
			try{
				ois.close();
			} catch (IOException e){
				e.printStackTrace();
			}
		}
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# File 类

  • 相对路径:从当前路径开始(在 IDEA 和 Eclipse 中,默认的当前路径是项目(project)路径)
  • 绝对路径:从盘符开始
  • File 类的概述:文件和目录路径的抽象表示形式
  • File 类的构造方法
1、根据一个路径得到FIle对象
public File(String pathname);

2、根据一个目录和一个子文件/目录得到File对象
public File(String parent, String child);

3、根据一个父File对象和一个子文件/目录得到对象
public File(File parent, String child);
1
2
3
4
5
6
7
8
  • 创建功能
1、创建文件,如果已存在该文件就不再创建并返回false
public boolean createNewFile();

2、创建文件夹,如果已存在该文件就不再创建并返回false
public boolean mkdir();

3、创建文件夹,且是多级创建,如果父文件夹不存在就创建
public boolean mkdirs()
1
2
3
4
5
6
7
8
  • 删除功能(Java 中的删除不走回收站)
删除文件或文件夹
public boolean delete();
1
2
  • 重命名功能(如果路径相同就是重命名,路径不同就是重命名加剪切)
public boolean renameTo(File dest);
1
  • 判断功能
1、判断是否是目录/文件夹
public boolean isDirectory()

2、判断是否是文件
public boolean isFile();

3、判断是否存在
public boolean exists();

4、判断是否可读
public boolean canRead();

5、判断是否可写
public boolean canWrite();

6、判断是否隐藏
public boolean isHidden();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • 基本获取功能
1、获取绝对路径
public String getAbsolutePath();

2、获取相对路径
public String getPath();

3、获取名称
public String getName();

4、获取文件大小
public long length();

5、获取最后一次修改时间,毫秒值
public long lastModified();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 高级获取功能
1、获取指定目录下的所有文件或文件夹的名称数组
public String[] list();

2、获取指定目录下的所有文件或文件夹的File数组
public File[] listFiles();
1
2
3
4
5
编辑 (opens new window)
上次更新: 2024/06/09, 21:19:54
技巧
高级

← 技巧 高级→

最近更新
01
大模型学习笔记
11-29
02
机器学习笔记
11-29
03
深度学习知识点总结
11-22
更多文章>
Theme by Vdoing | Copyright © 2019-2024 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式