IO流
Data流
读写基本数据类型+String类型数据,是字节流功能流的一种
请注意:Data流的输出和输入的顺序必须保持一致
类名 | 新增方法 |
---|---|
DataInputStream | readXxx() |
DataOutputStream | writeXxx() |
由于有新增方法,我们不用他父类去接收他的对象
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相同
}
}