1.是我们常用类库中最重要的类
2.数组只能通过动态扩容来进行对数组的扩充
2.类集对象数组有很多问题.普通的对象数组最大的问题在于数组中的元素是固定的,不能动态扩容,所以最早的时候可以通过链表实现一个动态数组.但是这样做太发复杂了,所以在java中为了方便用户操作各个数据结构,所以引入了类集的概念,有时候就可以把类集成为java对数据结构的实现.
3.链表和二叉树1.链表1.什么是链表Class Person{ String name; int age; Person date;//一个Person连接到下一个Person的地址Person-->>Person}2.二叉树二叉树是树的一种,每个节点最多可具有两个子树,即结点的度最大为 2(结点度:结点拥 有的子树数)。
树由节点组成,每个节点的数据结构是这样的: 因此,我们定义树的时候往往是->定义节点->节点连接起来就成了树,而节点的定义就 是:一个数据、两个指针(如果有节点就指向节点、没有节点就指向 null)
4.Collection1.set不允许重复!!!!!!!!!!
set中存取的元素都是不允许重复的
1.HashSet散列存放(不能保证存储顺序的)-->>无序的存储方式
不允许重复!!!!!!!!!!
2.TreeSet二叉树存储-->>基于Map集合存储
基于HashMap集合进行存储
是有序的-->>自然循序
根据数据的顺序进行排序
package com.fan;import java.util.TreeSet;public class TreeSetDemo06 { public static void main(String[] args) { TreeSet<String> strings = new TreeSet<>(); //根据存储的数据内容进行排序 strings.add("A"); strings.add("C"); strings.add("D"); strings.add("b"); for(String date:strings){ System.out.println(date); } }}package com.fan;import java.util.TreeSet;public class TreeSetDemo06 { public static void main(String[] args) { TreeSet<String> strings = new TreeSet<>(); //根据存储的数据内容进行排序 strings.add("A"); strings.add("C"); strings.add("D"); strings.add("b"); for(String date:strings){ System.out.println(date); } TreeSet<Student> treeSet = new TreeSet<>(); Student student1 = new Student("小红",28); Student student2 = new Student("麻子",19); Student student3 = new Student("范一伟",17); Student student4 = new Student("章鱼",17);//如果一样大就不存这个数据到集合中,下面的返回值就是false System.out.println(treeSet.add(student1)); System.out.println(treeSet.add(student2)); System.out.println(treeSet.add(student3)); System.out.println(treeSet.add(student4)); for(Student student : treeSet){ System.out.println(student); } System.out.println(treeSet.size()); }} class Student implements Comparable<Student>{ String name; int age; @Override public int compareTo(Student o) { //返回值:this和0比较 //返回的数据: 负数this小/0一样大/正数this大 if(this.age>o.age){ return 1; }else if(this.age==o.age){ return 0; } return -1; } public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }2.List(接口)List中存取的元素可以重复(Collection的子接口)
ArrayList是线程安全的实现了List接口 LinkList是链表(双向链表)
1.ArrayList实现了List接口
代码演示(讲解)package com.fan;import java.util.ArrayList;/**. * ArrayList */public class MyTest { /** * 其实呢ArrayList使用无参构造器创建,第一次内部长度是为0的 * 如果要存入数据,进行判断,然后第一次直接给到10个大小的空间 * @param args */ public static void main(String[] args) { //ArrayList:使用的是数组结构,对于增加删除比较慢,而查找就很快 //内部也是使用了动态扩容的方式,一次扩容是原大小的1.5倍 ArrayList<Integer> data = new ArrayList<>(); //如果第一次就要存入大量数据,就要使用一参的构造方法,避免多次扩容 //泛型-->>类型 //注意:返回值一定是true,不论添加成功或者失败与否 boolean add = data.add(100); /* public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } */ data.add(200); System.out.println(data.get(0)); }}删除另一个集合中包含的元素ArrayList<Integer> list = new ArrayList<>(); System.out.println(list.size()); //从1-10 for (int i = 1; i <= 10; i++) { list.add(i); } //要删除的集合0-4,没有0忽略 ArrayList<Integer> removeList = new ArrayList<>(); for (int i = 0; i < 5; i++) { removeList.add(i); } list.removeAll(removeList); for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i)+"\t"); }2.Vectorpackage com.fan;import java.util.Vector;public class VectorDemo02 { public static void main(String[] args) { //一个是初始长度,一个是每次内存不够是扩容的大小 //注意:如果扩容为0,那摩每次扩容就是旧数组长度的两倍 Vector<Integer> vector = new Vector<>(5,5); vector.add(123); vector.add(234); System.out.println(vector.get(1)); System.out.println(vector.size()); }}3.LinkedListpackage com.fan;import java.util.LinkedList;public class LinkedListDemo03 { public static void main(String[] args) { //LinkedList :使用的是双向链表结构,对于增加删除快,查找慢 LinkedList<Integer> linkedList = new LinkedList<>(); //模拟栈 linkedList.push(100); linkedList.push(200); //栈遵循先进后出原则 //弹栈 Integer pop = linkedList.pop(); System.out.println(pop); }}声明:
List和Set都是实现了Collection接口的类,其中有些方法不一样
3.Iterator(迭代器)注意:只能用来迭代List下的集合
package com.fan;import java.util.ArrayList;import java.util.Iterator;import java.util.ListIterator;/** * 迭代器 */public class IteratorDemo04 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); //使用迭代器,返回一个Iterator类型// Iterator<Integer> iterator = list.iterator();// //hasnext判断下一个时候有元素,引入一个指针的概念// while (iterator.hasNext())// {// //指针向下走一个,并且返回指向的这个数据,刚开始next指向的不是第一个元素,而是空// Integer next = iterator.next();// System.out.println(next);//// } ListIterator<Integer> iterator = list.listIterator(); iterator.next(); iterator.next();//走到1下标的位置 iterator.set(200); //设置好后,向上走一个 iterator.previous(); System.out.println(iterator.next()); }}5.Foreachpackage com.fan;import java.util.ArrayList;public class ForeachDemo05 { public static void main(String[] args) { //foreach:增强for循环,最早出现在C#中 //用于迭代数组或集合(Collection) //语法for(数据类型 变量名:集合或数组名){} int []arr = {1,2,3,4,5,6,7}; for(int data:arr){ System.out.println(data); } System.out.println("---------------------"); ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("锄禾日当午"); arrayList.add("汗滴禾下土"); arrayList.add("谁知盘中餐"); arrayList.add("粒粒皆辛苦"); for(String data:arrayList){ System.out.println(data); } }}6.MapMapping-->>映射
Map<K,V>
<key,value>
双值存储(存储的是一个个的键值对数据)
扩展:前面说到Set-->>下面的HashSet,TreeSet 都是基于HashMap(基于Map)进行存储
而且用的是Map集合中的键进行存储(而键不能重复->相当于身份id),从而就实现了Set下面的集合中不能存重复的值.
7.哈希表概述散列因子,默认0.75-->>所有桶中如果开始大于75%,重新散列增加数组的大小,重新构建
散列因子给的越大,查询效率越低
注意:不要乱更改Map键中存储的对象
因为:存储的时候是依靠键进行获得一个hascode值,如果改变就会改变hascode的值,
导致程序紊乱,很难再找到存储的这个数据了
8.注意(Hash,线程安全问题)流概述IO1.字节流明确一个概念:一切皆字节
计算机中的任何数据(文本,图片,视频,音乐等等)都是以二进制存储的.在数据传输时 也都是以二进制形式存储的后续学习的任何流,在传输时底层都是二进制.1.Demo05_FileInputStreampackage com.fan;import java.io.FileInputStream;import java.io.IOException;public class Demo05_FileInputStream { public static void main(String[] args) throws IOException { FileInputStream fio = new FileInputStream("c:\\a.txt"); //byte read;// while (true){// read= (byte) fio.read();// if (read == -1){// return;// }// System.out.println((char) read);// } byte [] bytes = new byte[10]; int len; len = fio.read(bytes); System.out.println(new String(bytes,0,len));//从0构建到len len = fio.read(bytes); System.out.println(new String(bytes,0,len)); len = fio.read(bytes); System.out.println(new String(bytes,0,len)); //注意:如果构建String时:不从0构建len个,就会把原来bytes中没有重新覆盖掉的byte构建成String类型返回出来 fio.close(); }}2.Demo06_Writerpackage com.fan;import java.io.FileWriter;import java.io.IOException;/** * 字符流 * 玩Writer */public class Demo06_Writer { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("C://a.txt"); fw.write("锄禾日当午,汗滴禾下土"); fw.append("谁知盘中餐").append(",").append("粒粒皆辛苦"); fw.close(); }}3.Demo_FileReaderpackage com.fan;import java.io.FileWriter;import java.io.IOException;/** * 字符流 * 玩Writer */public class Demo06_Writer { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("C://a.txt"); fw.write("锄禾日当午,汗滴禾下土"); fw.append("谁知盘中餐").append(",").append("粒粒皆辛苦"); fw.close(); }}4.InputStreamReader(之后会常用从字节流装饰成字符流)package com.fan;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;public class Demo07_Delicate { public static void main(String[] args) throws IOException { //转换流 //字节流 装饰成 字符流 :使用了装饰者设计模式 FileInputStream fis = new FileInputStream("C://a.txt"); //转换成-->>从字节输入流转换为字符输入流 //参数1.要转换的字节流 //参数2.指定编码名称 InputStreamReader isr = new InputStreamReader(fis,"gbk"); // //鏃 因为我设置的记事本的编码就是utf-8,所以用gbk编码进行装饰的时候,就会出现乱码的情况 //ュ //綋 //鍗 //? while (true){ int read = isr.read(); if(read == -1){ break; } System.out.println((char) read); } fis.close(); isr.close(); }}5.Print与BufferReader(如果拿到一个字节流,更建议转换成打印流)package com.fan;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;public class Demo09_BufferedReader { //缓存读取流,将字符输入流转换为带有缓存 可以一次读取一行的缓存字符流 public static void main(String[] args) throws IOException { FileReader fr = new FileReader("c://c.txt"); BufferedReader bufferedReader = new BufferedReader(fr); String s = bufferedReader.readLine(); System.out.println(s); }}收集异常日志package com.fan;import java.io.FileNotFoundException;import java.io.PrintWriter;import java.text.SimpleDateFormat;import java.util.Date;public class Demo10_ExceptionToFile { public static void main(String[] args) throws FileNotFoundException { String str = null; try { str.toString(); }catch (Exception e){ PrintWriter pw = new PrintWriter("C://bug.txt"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = simpleDateFormat.format(new Date()); pw.println(format); e.printStackTrace(pw); pw.close(); } }}Properties相当于map集合
package com.fan;import java.io.*;import java.util.Properties;public class demo11_Properties { public static void main(String[] args) throws IOException { /*Properties ppt = new Properties(); ppt.put("name","西游记"); ppt.put("info","讲述了师徒四人西天取经的辛酸历程"); //properties当作Map键值对来玩 FileWriter fw = new FileWriter("C://book.properties"); ppt.store(fw,"书籍的详细信息"); fw.close();*/ Properties properties = new Properties(); Reader r = new FileReader("C://book.properties"); properties.load(r);//加载到这个文件中的数据,存入Properties类中 System.out.println(properties.get("name")); System.out.println(properties.get("info")); r.close(); }}序列化和反序列化package com.fan;import java.awt.print.Book;import java.io.*;import java.util.ArrayList;public class Demo12_xuliehua { public static void main(String[] args) throws IOException, ClassNotFoundException { /* //序列化技术 Student b = new Student("fyw",18,10001); try { ObjectOutputStream oop = new ObjectOutputStream(new FileOutputStream("c://book.txt")); oop.writeObject(b); oop.close(); } catch (IOException e) { e.printStackTrace(); }*/ /* //反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c://book.txt")); Object o = ois.readObject(); ois.close(); System.out.println(o);*/ //序列化一个Student集合 //然后取出ArrayList这个集合/* Student b0 = new Student("范一伟",18,10001); Student b1 = new Student("宋佳琪",19,15557); Student b2 = new Student("程毅龙",20,96543); Student b3 = new Student("周岑雨",21,10009); ArrayList<Student> list = new ArrayList<>(); list.add(b0); list.add(b1); list.add(b2); list.add(b3); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C://book.txt",true)); oos.writeObject(list); oos.close();*/ //取出ArrayList,如果存入两个ArrayList FileInputStream fis = new FileInputStream("C://book.txt"); ObjectInputStream ois = new ObjectInputStream(fis); while (fis.available() > 0){ Object o = ois.readObject(); fis.skip(4);////跳过两次写入过程中间的头部信息 ArrayList<Book> books = (ArrayList<Book>) o; System.out.println(books); } ois.close(); } //注意要标记接口才能进行序列化 static class Student implements Serializable { private String name; private int age; private int id; Student(){} public Student(String name, int age, int id) { this.name = name; this.age = age; this.id = id; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } }}注意:读取多个对象时候遇到的问题:
在使用十六进制打开之前对象写入的文件test.txt时,发现里面确实包含有这两个数:
官方文档也说明了输出流的信息是由头部信息和数据组成的:
Primitive data, excluding serializable fields and externalizable data, is written to the ObjectOutputStream in block-data records. A block data record is composed of a header and data. The block data header consists of a marker and the number of bytes to follow the header.总结一下错误的原因:
ObjectOutputStream在构造时,首先会将流的头部信息(“AC ED 00 05”)写入到文件中。然后在调用write时,写入其他数据,直到关闭。当再次使用ObjectOutputStream追加写入对象时,头部信息又会再次写入。所以当你用ObjectInputStream来读取对象时,流虽然能够将第一个头部信息(“AC ED 00 05”)跳过,但是其他头部信息会当做数据来处理,造成无法解析,所以读取会出现StreamCorruptedException: invalid type code: AC错误。
3.解决 了解了上述原理后,也就大概有了两种解决思路:
不读取头部信息 不写入头部信息
//通过读取到下次头部的时候使用fileInputStream.skip(4);//跳过头部信息就可以了1.部分属性序列化注意:如果想要类的部分属性不支持序列化,就加上1.transient关键字(短暂的)
transient:转瞬即逝的,被指定的属性就不进行序列化操作
2.对属性加上static关键字
2.自定义工具类序列化和反序列化,在类中写Seralizable接口中的方法来指定序列化成员变量package com.fan;import com.utils.MySerializable;import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.Serializable;public class Demo13_MySerializable { public static void main(String[] args) throws IOException, ClassNotFoundException { Person p = new Person("范一伟",18,1005); String filename = "C://person.txt"; MySerializable.seralizable(p,filename); Object o = MySerializable.noSeralizable(filename); Person person = (Person) o; System.out.println(person); }}class Person implements Serializable { String name; int age; int id; private void writeObject(java.io.ObjectOutputStream out) throws IOException { //序列化成谁 out.writeObject(name); out.writeObject(age); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { //反序列化谁-->>得到的是什么 name = (String) in.readObject(); id = (int) in.readObject(); } private void readObjectNoData(){ } public Person(String name, int age, int id) { this.name = name; this.age = age; this.id = id; } public Person() { } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; }}序列化和反序列化工具
package com.utils;import java.io.*;public class MySerializable { /** * 自定义工具类,序列化对象到一个指定的文件路径下 * @param obj * @param filename * @throws IOException */ public static void seralizable(Object obj,String filename) throws IOException { FileOutputStream fileInputStream = new FileOutputStream(filename); ObjectOutputStream oos = new ObjectOutputStream(fileInputStream); oos.writeObject(obj); oos.close(); fileInputStream.close(); } public static Object noSeralizable(String filename) throws IOException, ClassNotFoundException { FileInputStream fis = new FileInputStream(filename); ObjectInputStream ois = new ObjectInputStream(fis); Object o = ois.readObject(); ois.close(); fis.close(); return o; }}3.通过实现Externalizable接口来重写两个方法,来实现序列化和反序列化必须要重写两个方法
4.Externalizable VS Serializable