Java之IO流中Data流、对象流以及Collotion接口下Arrays LIst、LikedList的学习

mac2026-03-31  8

IO流

Data流

读写基本数据类型+String类型数据,是字节流功能流的一种

请注意:Data流的输出和输入的顺序必须保持一致

类名新增方法DataInputStreamreadXxx()DataOutputStreamwriteXxx()

由于有新增方法,我们不用他父类去接收他的对象

XXX是代表四类八种基本数据类型,此外还可以使用UTF读取字符串,示例如下;

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; //重打代码:先写出在写入 public class DataDemo01 { public static void main(String[] args) { } //写出 public static void write(String path) throws IOException{ //1.序列化输出流 DataOutputStream out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(path))); //2.准备数据 short s=1; int i=1; long l=1L; float f=1.0f; double d=2.0; char c='c'; boolean b=true; String str="哈哈"; //3.写出 写出和读入的顺序要一致 out.writeShort(s); out.writeInt(i); out.writeLong(l); out.writeFloat(f); out.writeDouble(d); out.writeChar(c); out.writeBoolean(b); out.writeUTF(str); //4.刷出 out.flush(); //5.关闭 out.close(); } //写入 public static void read(String path) throws IOException{ //1.选择输入流 DataInputStream is=new DataInputStream(new BufferedInputStream(new FileInputStream(path))); //2.写入,按写出的顺序写入 short s=is.readShort(); int i=is.readInt(); long l=is.readLong(); float f=is.readFloat(); double d=is.readDouble(); char c=is.readChar(); boolean b=is.readBoolean(); String str=is.readUTF(); //3.关闭 is.close(); } }

对象流

​ 对象流:Object保存数据类型+数据,是字节的功能流,可以使用一个对象流。

​ 序列化:把对象类型的数据转化为可存储的|可传输的状态的过程

类名称呼新增方法ObjectInputStream反序列化输入流readObject()ObjectOutputStream序列化输出流writeObject()

注意:

先序列化后反序列化序列化和反序列化前后顺序一致不是所有的类都能序列化 类实现序列化,必须实现java.io.Serializable,该接口是一个空接口 不是所有的属性都需要序列化 可以在前面加上transient就不会被序列化 static修饰的内容不会被序列化如果父类实现Serializable接口,子类可以序列化所有内容。如果子类实现Serializable接口,但是父类没有实现,子类只能序列化子类独有的内容。 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class ObjectDemo02 { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { //1.文件先写出 write("d://one.txt"); //2.文件写入 read("d://one.txt"); } //构建一个方法,.作为序列化输出 public static void write(String path) throws FileNotFoundException, IOException{ //1.选择序列化输出流 ObjectOutputStream os=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(path))); //2.创建对象 Person p1=new Person("测试一",15,25); String[] p2={"文本测试"}; //3.把对象存储到 文件中 os.writeObject(p1); os.writeObject(p2); //4.刷出 os.flush(); //5.关闭 os.close(); //6.设置 static 修饰的值k //如果k的值被写入到文件中,读取的时候,k的值应该是不会变 //但是如果kd值没有被写入到文件,则应该取静态变量的最后一次 p1.setK(100); } //构建一个方法,作为反序列化输入 public static void read(String path) throws FileNotFoundException, IOException, ClassNotFoundException{ //1.选择一个反序列化输入流 ObjectInputStream is=new ObjectInputStream(new BufferedInputStream(new FileInputStream(path))); //2.读取内容,按顺序读 Object p1=is.readObject(); if(p1 instanceof Person){ Person p=(Person)p1; //打印 System.out.println(p); //name成功获取, //age获取不到,因为被transient修饰 //k获取到最后一个值,因为是静态的,只能获取到最新的 } String[] s=(String[])is.readObject(); //3.关闭流 is.close(); //4.打印 } } //构建一个测试类 实现Serializable接口,是类具有序列化的能力 class Person implements Serializable{ private String name; private transient int age; private static int k; public int getK() { return k; } public void setK(int k) { this.k = k; } public Person(String name, int age, int k) { super(); this.name = name; this.age = age; this.k = k; } public Person() { super(); // TODO Auto-generated constructor stub } 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; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", k=" + k + "]"; } }

小结

IO流:重点在于字节流的使用,了解其他流的特点

名称分类特点字节流字节流可以读写任意内容万能流字符流字符流程序到文件,只能读写存储文本的内容缓冲流节点流缓冲流包裹一个字节流使用,提高读写效率基本数据类型流字节功能流读写基本数据类型以及String类型对象流字节功能流读写基本数据类型以及对象类型数据,但一般由于对象

容器

类别特点数组存储多个数据数据类型相同长度不可变有序(索引)容器存储多个数据长度可以随着内容的多少变动可以存储任意类型的数据

两大体系

类型优点Collection存储单个数据的容器体系Map键值对形式数据的容器体系

自定义容器

要求:只能存储字符类型的数据,实现添加、删除、修改、查询的功能。

代码如下:

import java.util.Arrays; public class App01 { public static void main(String[] args) { MyContainer my=new MyContainer(); my.add("钢铁侠"); System.out.println(my); my.add("闪电侠"); System.out.println(my); my.add("绿箭侠"); System.out.println(my); my.delete(1); System.out.println(my); } } //自定义容器类 class MyContainer{ //1.字符串数组,存储容器中数据 private String[] arr; //2.存储中的个数 private int size; //3.在构造器中设置,初始长度为0 public MyContainer() { super(); // TODO Auto-generated constructor stub arr=new String[0]; } //实现查询的功能 //4.设置一个get器,用于获取当前索引位置下的元素 public String get(int index){ //判断是否有没有越界 if(index>=size){ return "越界"; } return arr[index]; } //实现修改的功能 //5.设置一个set器,用于修改当前路径的下的内容 public void set(int index,String str){ //判断是否有没有越界 if(index>=size){ System.out.println("越界了,无法修改"); }else{ arr[index]=str; } } //实现单个元素的添加功能 //6.设置一个add方法,用于添加数据 public void add(String src){ //备份原数组的地址 String[] temp=arr; arr=new String[size+1]; //原数组拷贝到对应的位置 for(int i=0;i<size;i++){ arr[i]=temp[i]; } //把参数赋值给数组最后的位置 arr[size]=src; //长度+1 size++; } //7.根据索引删除一个元素 public void delete(int index){ //判断是否有没有越界 if(index>=size){ System.out.println("越界了,无法修改"); return; } //备份数据 String[] temp=arr; //原数组长度-1 arr=new String[size-1]; //根据索引循环,判断是否索引值是否与要删除的数据的索引值相同 for(int i=0;i<size;i++){ if(i>=index){ //如果相同跳出本次循环 if(i==index){ continue; }else{ //否则把 原数组的后一个值给新数组的前一个位置 arr[i-1]=temp[i]; } }else{ arr[i]=temp[i]; } } } @Override public String toString() { return "MyContainer [arr=" + Arrays.toString(arr) + ", size=" + size + "]"; } }

Collection接口

Collectio你是容器体系的上层接口

Collection表示一组对象,这些对象对象也称为Collection的元素.一些Collection允许有重复的元素,而另一些不允许。一些Collection是有序的,一些Collection是无序的。

Collection接口中需要实现的方法

类别方法增加boolean add(E e)boolean addAll(Collection<? extends E> c)删除boolean remove(Object o)boolean removeAll(Collection<?> c)查询boolean contains(Object o)boolean containsAll(Collection<?> c)迭代Iterator iterator()

List接口下的实现类

与Collection接口是继承关系

ArraysList类

​ ArraysList时候List的实现类,我们通过这个类来学习这个类中的常用方法

​ ArrayList是List接口下实现的类

​ List接口的实现类有序可重复

ArrayList:

​ 底层实现:由可变数组实现,通过数组拷贝实现容器可以根据内容进行变动.。

​ 优点:遍历和获取的效率高,因为数据根据索引操作效率高

​ 缺点:增删效率低,大量涉及到数组拷贝问题

​ 扩容:使用Arrays的copyOf方法进行扩容,每次扩容到原容量 的1.5倍,新的容量是老的容量的1.5倍。

**新增方法**:没有新增方法,可以多态

​ 应用场景:单线程的环境下,在做大量的查询业务,适合还是用ArrayList容器.

Vetor:

​ 和ArrayLis非常像

​ 区别:

ArrayList线程不安全,效率较高,Vector线程安全,效率较大

扩容是每次扩容到原来的2的被,ArrayList是1.5倍

应用:多线程环境下,保证数据安全,大量查询适合使用Vector

ArrayList常用方法
import java.util.ArrayList; import java.util.Collection; public class CollectionDemo02 { public static void main(String[] args) { Collection co1=new ArrayList();//用实现的接口去接收实现类的对象 Collection co2=new ArrayList();//用实现的接口去接收实现类的对象 co1.add(1); System.out.println("添加1 打印"); System.out.println(co1); co2.add("我很好"); co1.addAll(co2); System.out.println("添加co2对象打印"); System.out.println(co1); co2.clear(); System.out.println("清除co2"); System.out.println(co2); //判断是否包含 System.out.println(co1.contains(1)); //判断是否包含所有元素 co2.add("我很好"); co2.add("我好"); System.out.println(co1.contains("我很好")); //判断是co1是否包含co2的所有元素 co1.addAll(co2); System.out.println(co1); System.out.println(co1.containsAll(co2)); //判断是否为空 System.out.println(co1.isEmpty()); //移动指定元素的实例 System.out.println(co2); co1.removeAll(co2); System.out.println(co1); //返回元素个数 System.out.println(co1.size()); } }
List的遍历方式
普通For循环
import java.util.ArrayList; import java.util.List; public class ListDemo01 { public static void main(String[] args) { //添加泛型 增强可读性 List<Integer> ls=new ArrayList<Integer>(); //存储班级学生分数 ls.add(2); ls.add(25); ls.add(56); ls.add(79); //打印结合中的所有内容 //因为List重写了toString方法,可以直接打印 System.out.println(ls.toString()); //admin(index) //使用普通for做遍历 for(int i=0;i<ls.size();i++){ System.out.println(ls.get(i)); } } }
增强For循环
import java.util.ArrayList; import java.util.List; public class ListDemo01 { public static void main(String[] args) { //添加泛型 增强可读性 List<Integer> ls=new ArrayList<Integer>(); //存储班级学生分数 ls.add(2); ls.add(25); ls.add(56); ls.add(79); //打印结合中的所有内容 //因为List重写了toString方法,可以直接打印 System.out.println(ls.toString()); //admin(index) //使用增加for for(int x:ls){ System.out.println(x); } } }
迭代器
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Demo02 { public static void main(String[] args) { // 定义一个容器,存储你喜欢的漫威人物 //如果有灭霸,就添加一个惊奇队长 List<String> list=new ArrayList<String>(); //1.添加内容 list.add("闪电侠"); list.add("钢铁侠"); list.add("黑寡妇"); list.add("雷声"); list.add("灭霸"); list.add("绿箭侠"); list.add("伸缩侠"); //打印该List容器中的所有内容 System.out.println(list); //2.遍历,使用迭代器,报错 //2.1设置一个遍历器 Iterator<String> it=list.iterator(); //2.2判断条件为,是否有下一个元素 for(;it.hasNext();){ //3.判断是否有灭霸,如果有则添加,没有则不添加 if("灭霸".equals(it.next())){//此行会报异常 //4.添加元素 System.out.println("和"); list.add("惊奇队长"); } } System.out.println(list); } }

第29行会报异常,其中详细信息如下

Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at list03.Demo02.main(Demo02.java:29)

​ 这个是因为,不能有个"对象"同时操作同一个对象,官方文档中表示:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。其实就是it.next()和it.hasnext(),在同时指向下一个对象时,系统会抛出异常.

​ 我们可以采用Java提供的另一个迭代器,列表迭代器

列表迭代器
import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class Demo02_01 { public static void main(String[] args) { // 定义一个容器,存储你喜欢的漫威人物 //如果有灭霸,就添加一个惊奇队长 List<String> list=new ArrayList<String>(); //1.添加内容 list.add("闪电侠"); list.add("钢铁侠"); list.add("黑寡妇"); list.add("雷声"); list.add("灭霸"); list.add("绿箭侠"); list.add("伸缩侠"); //打印该List容器中的所有内容 System.out.println(list); //2.遍历,使用迭代器,报错 //2.1设置一个列表遍历器 ListIterator<E> listIterator() ListIterator<String> it=list.listIterator(); //2.2判断条件为,是否有下一个元素 while(it.hasNext()){ if("灭霸".equals(it.next())){ it.add("惊奇队长"); } } System.out.println(list); //[闪电侠, 钢铁侠, 黑寡妇, 雷声, 灭霸, 惊奇队长, 绿箭侠, 伸缩侠] //我们发现<惊奇队长>是放在<灭霸>的后面,这个是因为遍历的时候,就把 //<惊奇队长>添加进去

List接口下实现类

LinkedList

​ 底层实现:底层是由双向链表结构实现的

​ 优点:做增删效率高

​ 缺点:做查询效率低

​ 新增方法:新增了一些有链表头和链表尾的方法

equqal方法

​ 我们通常喜欢比较的时候,使用equals方法,而equals方法如果没有进行重写,比较的这是地址,我们可以尝试写一个通过euqals方法比较的是对象的内容而不是地址.

import java.util.ArrayList; import java.util.Iterator; public class Demo03 { public static void main(String[] args) { //创建一个ArrayList对象,并且限制容器准许存储对象 ArrayList<Person> ls=new ArrayList(); //1.添加对象 ls.add(new Person("西沃",19)); ls.add(new Person("东土",25)); ls.add(new Person("北丐",25)); ls.add(new Person("南帝",25)); System.out.println(ls); //如何判断索引位置 indeOf System.out.println(ls.indexOf(new Person("东土",25)));//预计:1 结果:-1 //发现无法直接通过对象中的属性去查找相对应的位置,因为这个是一个新对象 //如果我们想要实现在equals方法中比较得出非地址的内容,就需要重写该该方法 //一般来说,我们可以直接在 调用的类中 重写该方法,以实现比较非地址的内容 //通过迭代遍历,我们可以取到值 Iterator<Person> it=ls.iterator(); while(it.hasNext()){ //取出新对象(下图new的对象)中的 name属性和 age属性,与原对象(前面new的对象)进行相比较 System.out.println(it.next().equals(new Person("东土",25))); } } } class Person{ private String name; private int age; @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person() { super(); // TODO Auto-generated constructor stub } 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; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
常用方法(不重要)
import java.util.LinkedList; public class LinkList { public static void main(String[] args) { //创建一个LinkedList对象 LinkedList<Character> ls=new LinkedList(); //添加元素 ls.add('a'); ls.add('b'); ls.add('t'); ls.add('k'); ls.add('w'); ls.add('y'); System.out.println(ls);//[a, b, t, k, w, y] //移出指定位置的元素 序号为3的元素被删除 ls.remove(3); System.out.println(ls);//[a, b, t, w, y] //其他用法与 ArrayList相同 } }
最新回复(0)