Ⅰ.集合实际上是一个容器(载体),可存储多个对象;(数组是最简单的集合);
Ⅱ.集合中不能存储基本数据类型和java对象,存储的是java对象的内存地址;
Ⅲ.每个不同的集合底层对应不同的数据结构(数组,二叉树,链表,哈希表…);
超级父接口:java.util.Collection
概述:
①.Collection可存放Object的所有子类对象;
②.由于Collection是接口,无法实例化,new对象应用多态机制创建子类的实现类对象。
b.常用方法
A.向集合中添加一个元素
//向集合中添加一个元素 public boolean add(Object e);
B.获取集合中的元素个数
//获取集合中元素的个数 public int size();
C.清空集合中的元素
//清空集合中的元素 public void clear();
D.判断集合中是否包含某元素
Tips:
该方法中底层调用了equals方法,放在集合中的元素应重写equals方法。
//判断集合中是否包含某元素 public boolean contains(Object e);
E.移除集合中的某元素
//移除集合中的某元素 public boolean remove(Object e);
F.判断集合是否为空
//判断集合是否为空 public boolean isEmpty();
G.将集合转换为数组
//将集合转换为数组 public Object[] toArray();
a.获取迭代器对象:
Collection c = new ArrayList(); Iterator it = c.iterator(); //iterator()方法是Collection接口的父接口Iterable中的方法
b.迭代器中的方法:
A.判断集合是否可以迭代
//判断集合是否可以迭代 public boolean hasNext();
B.返回迭代的下一个元素
//返回迭代的下一个元素 public Object next();
C.删除当前指向的元素
//删除当前指向的元素 public void remove();
c.使用迭代器需要注意的:
A.对迭代器来说,当集合结构发生改变时,迭代器必须重新获取;
B.采用迭代器的remove()方法删除可自动更新迭代器。
a.常用方法:
A.在指定位置i处添加元素
//在指定位置i处添加元素 public void add(int index,Object element);
B.根据下标获取元素
//根据下标获取元素 public Object get(int index);
C.获取指定对象第一次出现的索引
//获取指定对象第一次出现的索引 public int indexOf(Object element);
D.获取指定对象最后一次出现的索引
//获取指定对象最后一次出现的索引 public int lastIndexOf(Object element);
E.删除指定位置的元素
//删除指定位置的元素 public void remove(int index);
F.修改指定位置的元素值
//修改指定位置的元素值 public void set(int index,Object Element);
b.ArrayList类详解:
A.初始容量
ArrayList集合底层由数组实现,初始容量为10,也可通过构造方法new ArrayList(int capacity);
指定初始化容量。
B.扩容
当存储空间不够时,该集合自动扩容1.5倍。
本质上是位运算符二进制右移一位1010>>1=0101—>5
,左移同理。
C.优缺点
优点:检索效率较高,末尾加元素效率较高;
缺点:增删效率较低。
c.LinkedList类详解:
A.链表数据结构
结点Node是链表中的基本单元。
单向链表:
每一个Node中有两个属性:存储的数据和下一个结点的内存地址。
双向链表:
每一个Node中有三个属性:存储的数据,下一个和上一个结点内存地址。
B.优缺点
优点:随机增删元素的效率较高;
缺点:查询效率较低,查找元素需从头开始向下遍历。
d.Vector类详解:
A.初始容量
Vector集合底层由数组实现,初始化容量是10,也可通过构造方法new Vector(int initialCapacity);
设置初始化容量。
B.扩容
Vector存储空间用满时,自动扩容2倍。
C.方法特征
Vector集合中的方法都是线程安全的(带有synchronized关键字)。
e.泛型机制:
A.作用
规定集合中存储的元素类型固定,集合中数据类型更统一。
B.语法机制
//规定List方法中仅能存储String类型的数据 例子 //方法一: List<String> l = new ArrayList<>(); //方法二: List l = new ArrayList<String>(); //方法三: List<String> l = new ArrayList();
C.优缺点
优点:
①集合中存储的元素类型统一了;
②从集合中取出的数据是泛型指定类型,无需更多的向下转型。
缺点:
导致集合中的元素类型缺乏多样性。
f.总结集合的迭代与遍历
//创建集合以及添加元素 List<String> l1 = new ArrayList <>(); l1.add(0,"香辣牛肉月饼"); l1.add(1,"莲蓉月饼"); l1.add(2,"五仁月饼");
A.迭代器遍历
//迭代器遍历集合 Iterator <String> it = l1.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
B.采用List集合的下标
//下标遍历 for (int i = 0;i < l1.size();i++){ System.out.println(l1.get(i)); }
C.采用增强for进行遍历
//foreach遍历 for (String s:l1){ System.out.println(s); }
超级父接口:java.util.Map
a.数据存储特点
Map集合以key和value的方式存储数据,即【键值对】方式。
key和value都是引用数据类型,都存对象的内存地址。
c.常用方法
A.向Map集合中添加键值对
Map<K,V> map = new TreeMap<>();
//向Map集合中添加键值对 public V put(K key,V value);
B.通过key值来获取value值
//通过key值来获取value值 public V get(K key);
C.清空Map集合
//清空Map集合 public void clear();
D.判断Map集合中是否包括某个key或者value
//判断Map集合中是否包括某个key或者value public boolean containsValue(Object value); public boolean containsKey(Object key);
E.判断Map集合是否为空
//判断Map集合是否为空 public boolean isEmpty();
F.获取Map集合中所有的Key存储至一个Set集合中
//获取Map集合中所有的Key存储至一个Set集合中 public Set<K> keySet();
G.通过key值删除键值对
//通过key值删除键值对 public V remove(Object key);
H.获取Map集合中键值对的个数
//获取Map集合中键值对的个数 public int size();
I.获取Map中所有的Value存储到一个Collection中
//获取Map中所有的Value存储到一个Collection中 public Collection<V> values();
J.将Map集合转换成Set集合
//将Map集合转换成Set集合 public Set<Map.Entry<K,V>> entrySet();
d.Map集合的遍历方法
//创建集合以及添加元素 TreeMap map = new TreeMap<Integer,String>(); map.put(1,"汉堡包"); map.put(2,"炸薯条"); map.put(3,"香辣鸡翅");
A.获取所有的Key,通过get方法和迭代器遍历
//获取所有的key,再通过get方法得到value值 Set<Integer> set = map.keySet(); Iterator <Integer> it = set.iterator(); while(it.hasNext()){ Integer key = it.next(); System.out.println(key+"="+map.get(key)); }
B.通过entrySet方法将键值对转换为Set集合,再迭代器遍历
//通过entrySet将map转换为set集合,再迭代器遍历 Set<Integer> set = map.entrySet(); Iterator <Integer> it = set.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
e.HashMap类详解:
A.哈希表数据结构概述
定义:
哈希表是一个数组和单向链表的结合体,综合了以上二者的优点。
哈希下标:
①.同一个单向链表上的结点哈希值相同,因为其数组下标相同;
②.HashMap集合的key使用时应重写hashCode()
和equals()
方法。
put(K key,V value)方法实现原理:
①.封装key,value到Node对象中;
②.调用key的hashCode()方法得出Hash值。
③.通过哈希算法将Hash值转换为数组下标。
若下标位置无元素,则将Node添加上去;
若有元素(链表),将key与链表上每个结点key进行equals()比对:
若返回均为false,则该结点被加至末尾;
若返回存在true,则该结点的value值被覆盖。
get(K key)方法实现原理:
①.调用key的hashCode()得出哈希值;
②.通过哈希算法将哈希值转换为数组下标;
③.通过下标锁定位置。
若下标元素无元素,返回一个null;
若有元素(链表),拿参数key与单向链表上每个结点进行equals比对:
若返回均为false,则该方法返回null;
若返回存在true,则返回该结点的value值。
B.HashMap集合详解:
初始容量
HashMap集合的初始化容量为16。
也可通过new HashCode(int capacity)
进行初始化容量操作,但该集合容量必须是2的整数次幂。
(即当容量达到【16x0.75=12时】,集合自动扩容值32。)
默认加载因子
定义:当集合存储元素容量达到默认加载因子时,集合自动扩容。
HashMap:该集合的默认加载因子为0.75。
存储元素信息
HashMap集合中的【key】值可以为null,【value】值也可以为null。
f.Hashtable类详解:
A.Hashtable类概述:
初始容量
Hashtable集合的初始容量为11;
默认加载因子及扩容量
Hashtable的默认加载因子为0.75,扩容量为【原容量*2+1】。
存储元素信息
①.Hashtable集合中的【key】值和【value】值均不可为null。
②.该集合是线程安全的。
B.properties类详解:
存储数据类型:
key和value类型都应是String类型。
常用方法:
向集合中存入数据
//向集合中存入数据 public synchronized Object setProperty(String key,String value);
得到集合中的元素
//得到集合中的元素 public synchronized String getProperty(String key);
g.TreeSet和TreeMap类详解
A.概述:
①.TreeSet集合底层是个TreeMap集合,TreeMap底层是二叉树数据结构。
②.TreeSet集合中的元素相等于放入了TreeMap集合中的key部分了。
③.Map集合无序不可重复,TreeMap集合可自动排序。
B.排序规则:
①.TreeSet对自定义的类来说,TreeSet不可排序;
②.若给自定义的类添加【排序规则】,即实现Comparable接口和内部的comparedTo()方法,在其中写入【排序规则】即可。
③.TreeMap和TreeSet的排序规则采取二叉树中的【中序遍历】。
C.实现排序的两种方法:
①.实现java.util.Comparable接口,通常用于排序规则不会改变;
②.构建集合对象时传入一个比较器对象comparator接口,通常用于排序规则频繁改变。
方法一测试:
准备工作:准备一个学生类Student,让其实现Comparable接口,并重写comparedTo()方法,排序规则如下书写:
//学生作key时,先让其比较学生的学号,如果学号相等,再比较学生姓名 public int compareTo(Student o) { if (this.no < o.no){ return -1; }else if (this.no > o.no){ return 1; }else{ return this.name.compareTo(o.name); } }
书写测试类:
public static void main(String[] args) { Map<Student,Integer> map = new TreeMap <>(); map.put(new Student("shawn",5),5); map.put(new Student("Alice",6),6); map.put(new Student("James",7),7); map.put(new Student("Jane",8),8); map.put(new Student("Alice",7),7); System.out.println(map); }
测试结果与总结:
{Student{name=‘shawn’, no=5}=5,
Student{name=‘Alice’, no=6}=6,
Student{name=‘Alice’, no=7}=7,
Student{name=‘James’, no=7}=7,
Student{name=‘Jane’, no=8}=8}
总结:由上述结果可知,对于学号no较小的被排在上面,而中间学号no相等时,会比较姓名,从而达成了自定义类的排序功能。
方法二测试:
准备工作:准备一个学生类Student,让其实现Comparable接口,并重写comparedTo()方法,排序规则与上同
测试类书写:
public static void main(String[] args) { Map<Student,Integer> map = new TreeMap <>(new Comparator <Student>() { @Override public int compare(Student o1, Student o2) { if (o1.getNo()<o2.getNo()){ return -1; }else if (o1.getNo()>o2.getNo()){ return 1; }else{ return o1.getName().compareTo(o2.getName()); } } }); map.put(new Student("shawn",5),5); map.put(new Student("Alice",6),6); map.put(new Student("James",7),7); map.put(new Student("Jane",8),8); map.put(new Student("Alice",7),7); System.out.println(map); }
输出结果:
(与上同!)
h.集合的工具类Collections:
常用方法:
A.将集合从非线程安全变为线程安全
//将集合从非线程安全变为线程安全 public static List<T> synchronizedList(list l);
B.排序集合中的元素
//排序集合中的元素 public static List<T> sort(List l);
作用:
通过IO流可完成【硬盘文件的读和写】。
读和写的区分:
·读进入内存为输入【读】;
·写出来内存为输出【写】。
所在包:
java中所有的流均在java.io.*
下。
分类:
Ⅰ.
java.io.InputStream
:字节输入流;
Ⅱ.java.io.OutputStream
:字节输出流;
Ⅲ.java.io.Reader:
:字符输入流;
Ⅳ.java.io.Writer
:字符输出流。
实现的接口:
※ ①所有的【输出流】都实现了java.io.Flushable
接口,存在flush()
方法,作用是【刷新流】。
※ ②【所有流】都实现了java.io.Closeable
接口,存在close()
方法,作用是【关闭流】。
分类:
Ⅰ.
java.io.FileInputStream
Ⅱ.java.io.FileOutputStream
Ⅲ.java.io.FileReader
Ⅳ.java.io.FileWriter
定义:
【文件字节输出流】,可读取任意格式的文件。
构造方法:
源码:
/* *@param name:文件名 */ public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null); } /* *@param file:读取的文件对象 */ public FileInputStream(File file);
read()方法和read(byte[] bytes)方法:
/* *该方法一次可读取目标文件中的一个字节,效率较低。 *@return 若有读取值返回读到的字节本身,无读取值则取-1 */ public int read();
为了减少硬盘和内存之间的交互,引入read(byte[] bytes)方法
/* *该方法一次课读取目标文件的【bytes.length】个字节,效率较高。 *@return 返回读取到的字节数目,无读取值则返回-1 */ public int read(byte[] b);
※ 使用read(byte[] b)方法时,输出字节本身可以使用String的构造方法
//将byte数组转换为字符串进行输出即可 new String(byte[] bytes,int offset,int readCount);
从而得出读文件的最优解:
Tips:【io测试文本】中存储为【“Hello IOStream!”】
//创建流对象:(让fis对象作用域扩展,能在finally语块中读取到该对象) FileInputStream fis = null; try { //指定要读取的文件 fis = new FileInputStream("io测试文本.txt"); int readCount = 0; byte[] bytes = new byte[4]; while((readCount = fis.read(bytes)) != -1){ System.out.print(new String(bytes,0,readCount)); } } catch (IOException e) { e.printStackTrace(); } finally{ //最后必须关闭流:(加入判断为了防止【空指针异常】) if (fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } }
输出结果为:
【Hello IOStream!】
其他方法:
available()
//使用该方法一次读完数据 /* *@return 返回可读取的字节数量 */ public int available();
skip()
/* *@param l:bytes数组需要跳过总字节数 *@return 实际跳过的字节数 */ public long skip(long l);
定义:
【文件字节输出流】。
构造方法:
/* *@param name:需要写入的文件名 *@param append:写入的数据是否在原有基础上拼接 */ new FileOutputStream(String name,boolean append);
write(byte[] bytes)方法:
/* *向原文件中写入数据 *@param bytes 写入的数据的byte数组 */ public void wirte(byte[] bytes);
※:添加字符串时可调用String中的getByte(String s)方法将字符串转换为byte数组。
写入数据样例:
//定义输出流 FileOutputStream fos = null; try { fos = new FileOutputStream("io测试文本.txt",true); String str = "我是中国人,我骄傲"; //将字符串转换为byte数组 byte[] bytes = str.getBytes(); fos.write(bytes); //输出流需刷新流: fos.flush(); } catch (IOException e) { e.printStackTrace(); }finally{ try { //结尾需要关闭流 if (fos != null){ fos.close(); } } catch (IOException e) { e.printStackTrace(); } }
定义:
【文件字符输入流】,仅能读取【普通文本】。
定义:
【文件字符输出流】,仅能读取【普通文本】。
源代码:
package IO流; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class FileCopy { public static void main(String[] args) { //输入流的定义 FileInputStream fis = null; //输出流的定义 FileOutputStream fos = null; try { fis = new FileInputStream("E:\\highlights\\跑跑机器人.mp4"); fos = new FileOutputStream("E:\\泡泡机器人.mp4"); //初始化计数变量readCount和数组byte[] int readCount = 0; byte[] bytes = new byte[1024*1024];//一次性拷贝1M文件 //一边写一边读 while((readCount = fis.read(bytes))!= -1){ fos.write(bytes,0,bytes.length); } //刷新输出流 fos.flush(); } 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(); } } } } }
结果:
【E:/highlights/跑跑机器人.mp4】视频文件成功被拷贝到
【E:/泡泡机器人.mp4】,在此过程中同时进行了重命名操作。
缓冲区类流有:
Ⅰ.
java.io.BufferedReader
Ⅱ.java.io.BufferedWriter
Ⅲ.java.io.BufferedInputStream
Ⅳ.java.io.BufferedOutputStream
BufferedReader类(BufferedWriter类同理):
定义:自带缓冲区的字符输入流;
构造方法:
new BufferedReader(Reader reader);
方法:
readLine()方法:
//一次读取文件的一行内容。 public String readLine();
read()方法:
//一次读取一个字符,返回值为ASCII值。 public int read();
read(char[] chars)方法:
//一次读取chars.length个长度,存入chars数组中,返回值为读到的字符数量 public int read(char[] chars);
转换流InputStreamReader:将字节流转换为字符流:
InputStreamReader I = new InputStreamReader(new FileInputStream("io测试文本"));
所在包:java.io.PrintStream
①.标准的【字节输出流】,默认输出到控制台。
②.该流无需手动关闭。
③.手动改变输出方向:(System类下)
public static void setOut(PrintStream ps);
所在包:java.io.PrintWriter
①.标准的【字符输出流】,与上同;
概述:
【serialize,deserialize】
①.【(反)序列化】:(反)将内存中的java对象放入硬盘文件中。
②.参与序列化与反序列化的对象,必须实现Serializable
接口。
③.在属性前加【transient】关键字,表现该变量不参与(反)序列化。
④.IDEA可自动生成序列化版本号。
⑤.Map集合中的Properties类中的load()
方法可将硬盘文件加载到内存中。
public synchronized void load(InputStream inStream); public synchronized void load(Reader reader);
概述:
File类不能完成对象的读和写,File是一个路径名的抽象表现形式。
构造方法:
//文件的路径名 new File(String pathname);
方法:
exists()方法:
//判断是否存在目标文件 public boolean exists()
createNewFile()方法:
//在当前目录下创建一个文件 public void createNewFile();
mkdir()方法:
//在当前目录下创建出一个子目录 public void mkdir();
getParent():
//获取文件父路径 public String getParent();
getAbsolutePath():
//获取文件的绝对路径 public String getAbsolutePath();
listFiles();
//获取当前目录下所有子文件 public File[] listFiles();
/* *该方法用于目录的拷贝 *@param srcFile:拷贝源文件对象 *@param deskFile:拷贝目标文件对象 *@param src:拷贝源文件地址 *@param desk:拷贝目标文件地址 */ public static void copy(File srcFile,File deskFile,String src,String desk){ //列出源目录下的所有子目录: File[] files = srcFile.listFiles(); //遍历files数组拿到所有的子目录与子文件: //当拿到的是文件时: if (srcFile.isFile()){ //使用FOS与FIS即可实现拷贝: FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(src); fos = new FileOutputStream(desk); int readCount = 0; byte[] bytes = new byte[1024*1024];//一次传1MB while((readCount = fis.read(bytes))!=-1){ fos.write(bytes,0,readCount); } //输出流刷新: 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(); } } } return; } //当拿到目录时: for (File file : files){ if (file.isDirectory()){ String srcDir = file.getAbsolutePath(); String deskDir = (deskFile.getAbsolutePath(). endsWith("\\")?deskFile.getAbsolutePath() :deskFile.getAbsolutePath()+"\\")+srcDir.substring(3); System.out.println(srcDir); System.out.println(deskDir); File newFile = new File(deskDir); if (newFile.exists()){ newFile.mkdirs(); } } // 递归调用 copy(file,deskFile,src,desk); } } }