集合框架中的父接口:Collection
子接口: List,Queue,Set
List:有序(索引是按照添加顺序指定的),可重复(存放同一个对象多次,equals方法相同的不同对象)
能存储null元素,没有个数限制。
派生出两个子类:
ArrayList:基于动态数组的数据结构,有连续的索引,从0开始
在使用get/set方法时,效率高
LinkedList:基于双链表的数据结构,每个节点上都有前后两个元素的引用。
在add/remove方法时,效率高
迭代器:用来遍历集合的。提供了hasNext():询问是否有下一个元素
next():用来获取下一个元素。
ps:在迭代期间,想删除集合的元素,需要使用迭代器自己的remove()方法
foreach循环:
for(元素类型 变量:要遍历的集合或数组){
逻辑
}
实现原理:使用了迭代器思想
Queue:队列,进出原则:FIFO
方法: boolean offer(E e)—进
E poll()—–出
E peek()—–查看队首
Deque:队列的子接口,双端队列,两端都可以进可以出
方法:
boolean offerFirst(E e)
boolean offerLast(E e)
E pollFirst()
E pollLast()
E peekFirst()
E peekLast()
栈: 双端队列的特殊情况:一端禁止进出。FILO
方法: void push(E e)–进栈
E pop()—–出栈
泛型机制:
(1)概念
jdk1.5版本开始使用的新特性,本质是进行”参数化类型”,在类
,接口,方法的定义上都可以使用,用来指定数据类型名的。
(2)集合在定义时,可以用泛型机制来指定元素的类型,这样
编译器在编译期间就可以进行检查元素类型是否匹配,避免了
程序在运行时出现过多的错误
(3)集合框架中的所有类型(接口,抽象类,实现类)都是用了
泛型机制
(4)泛型机制的参数只能传引用类型。
练习: 自定义一个类型,练习泛型机制
定义一个类型MyContaionner:
使用泛型机制,用于规定要存储的元素类型
List排序
Comparable接口:
如何定义集合中元素之间的大小之分?我们需要在定义元素类型
时实现Comparable接口,实现接口内的compareTo(E e)。实现此接口的类型的对象之间可以进行
比较。
方法:
int compareTo(E e):
比较规则:
(1)this与e比较,this-e,
如果大于0,返回大于0的一个数
如果等于0, 返回0
如果小于0, 返回小于0的一个数
按照升序排序
(2)e-this,降序排序
工具类:Collections
提供了一个sort(Collection c)方法,
对集合里的元素进行排序
练习:定义一个类型Point,在集合List中存储五个Point对象
按照到原点的距离长短进行降序排序。
Comparator比较器接口:
如果元素类型已经实现了comparable接口,定义了默认的比较规则。
之后,再想换其他比较规则时,不修改源码。可以利用比较器接口
来重新定义比较规则
方法:
int compare(E o1,E o2);
比较规则:
升序: o1-o2
降序: o2-o1
Set接口:
特点1: 无序,存储的元素与添加顺序无关
特点2: 不可重复(使用元素的equals方法来判定是否重复)
特点3: 能存储null元素,只能存储一次。
Hash算法机制
Set集合在添加或查看元素时,当集合中的元素过多时,就是进行
多次的比较,效率变低。
在设计元素类型时,提供hash算法,用于返回对象的一个int值。
在内存中开辟很多小的区域,用于存储一定范围的返回值的对象。
当我们想添加元素或查看元素,先计算此元素的返回值,然后去
相应区域中查找遍历,
–如果在这个区域没有找到对象,说明
集合中可以添加这个对象。
–如果有,然后查看两个对象的equals的返回值
–如果为true, 不能添加
–如果为false, 可以添加,添加至
对应的链表结构中(尽可能的避免发生)
重写HashCode方法:
重写规则:尽可能的让所有的成员变量都参与运算,
尽可能的避免出现hash值碰撞
注意:
重写的必要性:
(1)如果重写了equals(), 有必要重写hashCode方法
(2)如果equals()返回true, hashCode返回值有必要相同
(3)如果equals()返回false,hashCode返回值不一定相同,
如果返回值不同,可以提高检索的效率
反过来说:
(1)hashCode值相同,equals方法可能不同
(2)hashCode值不同,equals方法一定不同
Set接口派生的子类
HashSet:通过实现hash算法的一种数据结构,
无序,不重复
LinkedHashSet:通过实现hash算法的一种数据结构,但是
通过链表来维持顺序。顺序与添加顺序一致。
TreeSet: 使用二叉树的一种数据结构,顺序与自然排序有关系。
支持定制排序
Set集合:
特点:无序,不重复。
存储时采用了hash算法机制,计算存储位置。
HashCode方法:
Object是引用类型的父类,提供了hashCode()方法以及equals()方法
因此我们在定义类型时,一般都重写hashCode和equals方法。
重写的重要性:
equals方法我们用来判断集合中的元素是否重复
hashCode方法我们在使用Set集合时,必须要重写,因为
我们采用的hash算法计算Set集合元素的存储位置。
int hashCode():
Object提供的方法是通过地址计算hash值,不可控。
我们需要在自定义类中重写此方法。
重写原则: 尽可能的让所有成员变量都参与运算
尽可能的减少hash值的碰撞
public int hashCode(){
int result = 7;--定义一个局部变量,进行初始化
int prime = 53 --定义一个局部变量,赋值为素数
result = prime*result+field1;
result = prime*result+field2;
return result;
}
Set集合的遍历
因为Set集合是无序的,无下标可言,因此不能使用经典for
循环。我们可以使用迭代器原理。
(1) 调用集合的iterator()获取迭代器
(2) 使用foreach循环
Set集合的元素:
不能轻易修改参与hash值算法的成员变量。
否则容易引起内存溢出。
原因:成员变量修改后,会出现新的hash值,但是存储位置还在
原hash值的位置上。因此操作时,找不
到具体的存储位置。
子类:
HashSet:
无序,不重复,底层使用hash算法计算存储位置。
增加删除时效率高
LinkedHashSet:是HashSet的子类
底层使用hash算法计算存储位置,同时使用链表来维护
顺序,顺序与添加顺序一致。
在查看检索时,效率比较高
TreeSet:是SortedSet子接口的实现类,使用二叉树的数据结构维护
元素的顺序。
Map接口:集合框架中的另一个父接口
Map集合,用于储存一一对应的元素数据,第一个对象可以作为
索引,第二个对象作为值,我们称之为key-value,键值对。
储存数据的特点:
(1)以key-value形式进行存储。
(2)key与value都必须是引用类型
(3)key可以为null。
(4)key与value是单向一对一映射。
(5)key不能重复
存储机制:
Map是基于数组和链表的数据结构进行存储数据。
作为key的对象采用了hash算法计算存储的数组
(散列数组,散列桶)的位置.如果计算出来的位置,
数组中此位置没有元素,就可以添加到
散列桶内,如果有元素,key的equals方法
返回值为false,就会存储在散列桶元素对应的单向链表中。
如果key的equals方法返回true,就进行替换(覆盖)。
PS:使用Map集合,做为key的数据类型应该重写equals和
HashCode方法
常用方法:
V put(K k,V v):
作用:用于存储一对key-value. 返回被替换的value值
如果不是替换就返回null
V get(K k):
作用:通过key对象,获取对应的value对象,如果集合中
没有此key,返回null
Map集合的遍历
Set keySet();
用于获取Map中所有的key对象,返回一个Set集合
Set
}
Map接口的子类:
HashMap与HashTable的区别
(1)HashTable是一个古老的类。不建议使用
(2)HashTable是一个线程安全的类,HashMap线程不安全
(3)HashTable的key不能是null,HashMap可以是null
LinkedHashMap:是HashMap子类,使用链表来维护key-value的
顺序,在迭代时顺序与添加顺序一致。
TreeMap:
是SortedMap子接口的实现类,使用了二叉树的数据结构维护
填入集合的顺序。
(1)自然排序:
往TreeMap里添加的key对象,可以实现Comparable接口。重写
compareTo方法
(2)定制排序:做为key对象的数据类型,可以不实现Comparabel接口。
需要创建一个比较器Comparator对象。实现compare方法
Properties:
是HashTable的子类型,用于封装属性文件的key-value信息
因为在文件里写的都是字符串,因此Properties的key与value
都是字符串类型
File类型
java.io.File类型,可以对硬盘上的文件以及目录,进行操作。
如查看文件/目录的属性信息,创建,删除文件/目录。此类型
不能查看和修改文件里的内容。
常用构造器:
File(String pathname):
指定一个路径,创建一个File对象
路径:
(1)文件的路径,要写到文件的扩展名为止
(2)目录的路径,要写到当前目录的名称为止
常用方法:
boolean exists():
判断指定路径的File对象是否存在
exists();//
isFile();
isDirectory();
getName());
lastModified();
isAbsolute();
getAbsolutePath();
getParent();
length();
java.io.File类型
一、概念
可以用来创建,删除文件/目录,还可以查看文件/目录的属性信息。
但是不可以修改文件里的数据。如果需要修改,应该使用输入/输出流。
二、常用构造器
File(String pathname)
创建一个指定路径的File对象
File(File parent,String child)
在指定parent路径下,创建一个child的file对象
File(String parent,String child)
在指定parent路径下,创建一个child的file对象
三、
绝对路径:是从根目录开始写的路径
window: 从盘符开始书写:
D:\a\f1.txt
D:\a\b
linux: /home/scott/f1.txt
/home/scott
相对路径: 相对某一文件/目录的路径,不是从根路径书写。
reg: f2.txt相对于a目录的路径:
window: b\f2.txt
linux: b/f2.txt
reg: f3.txt相对于f2.txt的路径
../c/f3.txt
四、常用方法
boolean exists();判断指定的路径是否存在
boolean isFile();判断指定路径是不是文件
boolean isDirectory();判断指定路径是不是目录
String getName());获取文件/目录名称
long lastModified();获取文件/目录的最后修改时间
boolean isAbsolute();判断指定路径是不是绝对路径
String getAbsolutePath();获取绝对路径
String getParent();获取父目录的路径
long length();获取文件大小
文件/目录创建方法:
boolean createNewFile();创建文件
boolean mkdir();创建目录
boolean mkdirs();创建多级目录
文件/目录的删除方法
boolean delete()
可以删除文件,删除目录时,需要目录下没有文件或子目录
File[] listFiles()
获取目录里的file对象
递归:
递归思想:分成递与归。一层层递进,最后再一层层归。
两种递归:
(1) 方法调用自己
(2) 方法A调用方法B,方法B调用A
举例:
n*(n-1)*……*1
z = f(n) 计算n的阶乘
= n*f(n-1)
= n*(n-1)*f(n-2)
= n*(n-1)*......*1
f(n)是一个函数:
里的逻辑:
n*f(n-1)
练习:
斐波那契数列: 第n个数是第n-1个数与第n-2个数的和。
1,1,2,3,5,8,13,.......
计算第10个数的值。
IO流:(Input,Output)
我们在做项目时,除了自定义的一些数据外,还可能需要从”外界”
引入数据,或者将数据导出到”外界”。这时,我们需要I/O操作。
外界:指的可能是 键盘,显示器,硬盘,另外一个程序。
输入:又叫读入操作
数据时从”外界”流向程序
输出:又叫写出操作
数据时从程序流向”外界”
流: 就是数据序列, 一经创建成功,就会打开一个通道。所以使用完
应该进行关闭操作。
IO流的分类:
(1)按照流向分类:
输入流
输出流
(2)按照处理的数据单位分类:
字节流
字符流
(3)按照功能分类:
节点流:直接连接两个设备的流类型
处理流:对节点流再次封装与处理的流类型
字节流:
抽象父类 InputStream/OutputStream
文件字节流:
FileInputStream/FileOutputStream
(1)构造器:
FileInputStream(File file)
创建一个指定路径的File对象的文件输入流对象
FileInputStream(String name)
创建一个指定路径的字符串的文件输入流对象
常用方法:
int read()
读取该流中的一个字节数据,即8位二进制,存储到一个int数
据的低八位上
如果返回-1,读至文件末尾,
long skip(long n)
跳过流中n个字节
int read(byte[] b)
读取字节存入byte数组中,最多能读b.length个字节
返回的是实际读取的字节个数
int available()
查看此输入流中剩余的字节数量
(2)构造器
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
创建一个指定路径的输出流对象,append表示在文件末尾追加
PS:如果指定路径下的文件名不存在,会自动创建。
如果父路径不存在,则报异常FileNotFoundException
常用方法:
void write(int b)
写出参数b中的一个字节,int类型的低八位。
void write(byte[] b)
将字节数组b中的字节按顺序写出
void write(byte[] b,int off,int len)
将字节数组b中的字节按顺序写出,从下标off,写len个
File:可以创建,删除,查看文件/目录的信息。但是不
能查看/修改文件里的内容
删除目录时:需要注意使用递归思想(不能直接删除不为空的目录)
IO流:
用途,传输数据。
输入:读取数据
输出: 写出数据
流:数据序列
分类:
(1)按照流向分类
(2)按照处理的单位分类
(3)按照功能分类
字节流:
抽象父类:
InputStream:定义了字节输入流的常用方法
int available()
void close();
int read():读取一个字节,存入int的低八位上,范围是0-255
int read(byte[] b):
读取字节存入字节数组b中,返回的是读取的有效字节个数。
int read(byte[] b,int off,int len)
skip(int n);
OutputStream:定义了字节输出流的常用方法
void close();
void flush();//冲刷,作用是将流的数据,冲刷进文件中
void write(int b);写一个字节
void write(byte[] b);写一个字节数组
void write(byte[] b,int off,int len)
子类:
FileInputStream/FileOutputStream
继承了字节流的抽象父类。重写了方法,并且提供了自己独有的方法
构造器:
FileInputStream(File file)
FileInputStream(String path)
FileOutputStream(File file)
FileOutputStream(File file,boolean append)
FileOutputStream(String pathname)
FileOutputStream(String pathname,boolean append)
PS:所有的输出流,对于指定的路径中的文件若是不存在,
都会自动创建。
缓冲流:
BufferedOutputStream:字节缓冲输出流
在写数据时,如果一个字节一个字节的写,写的次数明显很多,效率就会变得很低。
如何提高效率呢。
缓冲输出流的特点是:在流里维护了一个缓冲区,写字节时,先将字节
写入缓冲区, 当缓冲区满时,再一次性的将数据写到文件里。这样就
降低了写的次数,因此提高了效率。
因此缓冲输出流缺失即时性,可以使用flush方法进行冲刷
常用构造器:
BufferedOutputStream(OutputStream out)
创建一个指定字节输出流的缓冲流对象
BufferedOutputStream(OutputStream out,int size)
创建一个指定字节输出流的缓冲流对象,并设置缓冲区的大小
PS:当一次写的字节超出缓冲区大小,会不使用缓冲区直接写在硬盘中
常用方法:
void write(int b):
写int数据的低八位,写入缓冲区内
void write(byte[] b,int off,int len)
写指定长度len的字节数组,写入缓冲区
BufferedInputStream:字节缓冲输入流
在读取字节时,也是一个字节一个字节的读,次数多,效率低。
使用缓冲输入流,内部维护了一个缓冲区,默认8k,先一次性将缓冲区装满
等待读取.
当将缓冲区的数据读完,缓冲区再次存储后续数据。读取的次数明显降低
效率高
构造器:
BufferedInputStream(InputStream is);
BufferedInputStream(InputStream is,int size);
常用方法:
int read(byte[] bs)
读取缓冲区里的字节存储bs中,
当一次性得去的字节小于缓冲区,我们是从缓冲区里读数据。
此时,效率高
当一次性读取的字节超出缓冲区大小。
不使用缓冲区,直接从文件里读。
int read(byte[] bs,int off,int len)
数据字节流,与缓冲流一样,父类都是过滤字节流(
FilterOutputStream/FilterInputStream
)
这两个类提供了几个特殊的方法,可以直接写基本数据类型
数据输出流:DataOutputStream
构造器:
DataOutputStream(OutputStream os)
创建一个指定字节输出流的数据输出流对象
常用方法:
除了提供写一个字节和写一个字节数组的方法外,还提供了如下方法
writeByte(int b)
writeShort(int s)
writeInt(int i)
writeLong(long l)
writeFloat(float f)
writeDouble(double d);
writeChar(int c);
writeBoolean(boolean b)
writeUTF(String s);
对象流:
有的时候,我们可能需要将内存中的对象持久化到硬盘上,或者将
硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入
输出流。
序列化: 是对象转换成一个字节序列的过程,是一个写操作
反序列化: 一个字节序列转换成对象的过程 ,是一个读操作
ObjectOutputStream
构造器:
ObjectOutputStream(OutputStream out)
创建一个指定字节输出流的对象输出流对象。
常用方法: 除了提供了一些基本数据类型的写方法外,还提供了
void writeObject(Object obj)
将内存中的对象持久化到硬盘上
ObjectIntputStream
ObjectIntputStream(OutputStream out)
创建一个指定字节输入流的对象输入流对象。
常用方法: 除了提供了一些基本数据类型的读方法外,还提供了
Object readObject();
从硬盘上读取一个字节序列,转换成对象
Serializable:序列化接口
如果想将对象序列化,那么对象的类型必须实现此接口。此接口
内什么都没有,只是一个序列化标识。
serialVersionUID:
每个能序列化的对象,在被序列化时,系统会默认给此对象的类计算一个
序列化版本号。不同的平台默认提供的序列化版本号多数情况下不会相同。
因此当我们反序列时,如果硬盘里存储的对象的版本号与当前设计的类型
的版本号不一致。会出现运行时异常:
java.io.InvalidClassException,这种情况叫不兼容问题。
如果我们想解决不兼容问题。我们应该手动提供版本号。尽可能的相同
这样来解决不兼容问题
另外一种情况:
序列化过后,可能会修改类型,如果使用系统默认提供的
版本号,在反序列时,会有异常,如果手动提供,不出现异常
多出来的成员变量,以默认值的形式,赋值给反序列化回来的对象。
transient:成员变量的一个修饰词,可以理解为瘦身。
有的时候,在序列化对象时,我们不需要将对象的某些成员变量
值持久化到硬盘上(因为不重要),此时,我们可以在这些成员变量
前添加修饰词transient(保存时,进行减肥)
字符流:
在输出输入操作时,以字符为单位进行操作,默认是unicode编码集
字符流的抽象父类分别是
Writer/Reader
Writer提供了字符输出流的常用方法
void close():关闭
void write(char[] cbuf):写一个字符数组
void write(char[] cbuf, int off, int len)
写一个字符数组的一部分
write(int c):写一个字符
write(String str):写一串字符
write(String str, int off, int len)
写字符串的一部分
Reader提供了字符输入流的常用方法
int read():读一个字符,存储到int的低16位
int read(char[] cbuf):将数据读进字符数组中,返回的是读取的有效字符个数
int read(char[] cbuf, int off, int len)
将字符读入数组的一部分。
子类中转换流:
OutputStreamWriter:
将字符转换成字节写出到硬盘上
构造器:
OutputStreamWriter(OutputStream out)
创建一个指定字节输出流的字符输出流对象,采用的是系统默认的编码集
OutputStreamWriter(OutputStream out, Charset cs)
OutputStreamWriter(OutputStream out, CharsetEncoder enc)
OutputStreamWriter(OutputStream out, String charsetName)
创建一个指定字节输出流的字符输出流对象,采用指定编码集。
write(int a);
当a的低16位,如果被设计成相应的字符时,如果两个字节都是
有效字节,会写出两个。如果低16位对应是无效字符,或是有效
字节只有一位时,会写一个字节。
InputStreamReader()
将字节转换成字符读进程序中
构造器:
InputStreamReader(InputStream in)
创建一个使用默认字符集的InputStreamReader。
InputStreamReader(InputStream in, Charset cs)
InputStreamReader(InputStream in, CharsetDecoder dec)
InputStreamReader(InputStream in, String charsetName)
创建一个使用指定字符集的InputStreamReader。
缓冲流:
PrintWriter:提供了丰富的方法,比BufferedWriter更加常用,此类型提供了
行自动刷新的功能
构造器:
PrintWriter(File file)
PrintWriter(OutputStream out)
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(String fileName)
PrintWriter(Writer out)
PrintWriter(Writer out, boolean autoFlush)
上述构造器,有第二个参数的,可以设置为true,表示行自动刷新。
只有一个参数的构造器,相当有两个参数时,设置为false的情况,即取消了
行自动刷新的功能
常用方法:
println()
通过写入行分隔符字符串来终止当前行。
println(boolean x)
打印一个布尔值,然后终止该行。
void println(char x)
打印一个字符,然后终止该行。
void println(char[] x)
打印字符数组,然后终止行。
void println(double x)
打印双精度浮点数,然后终止行。
void println(float x)
打印一个浮点数,然后终止该行。
void println(int x)
打印一个整数,然后终止该行。
void println(long x)
打印一个长整型,然后终止行。
void println(Object x)
打印一个对象,然后终止该行。
void println(String x)
BufferedReader:提供了一个缓冲区
构造器:
BufferedReader(Reader in)
创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)
创建使用指定大小的输入缓冲区的缓冲字符输入流。
常用方法:
String readLine():
读一行字符串,读至换行符号为止,返回的数据不包含换行符
当返回值为null时,表示读至文件末尾
文件字符流:
FileWriter/FileReader
FileWriter:相当于OutputStreamWriter与
FileOutputStream合起来的功能,内部也维护
了一个缓冲区,但是需要手动flush
构造器:
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(String fileName)
FileWriter(String fileName, boolean append)
append:表示追加,但是此流不能设置字符集。
常用方法与 OutputStreamWriter的差不多
FileReader:相当于InputStreamReader和FileInputStream合起来的功能
内部也维护了一个缓冲区
构造器:
FileReader(File file)
FileReader(String fileName)
常用方法与InputStreamReader的方法差不多
System是一个final修饰的类型
两个成员变量
out:是PrintStream类型,默认的输出目的地是控制台console
in: 是InputStream类型, 默认的数据源是键盘