JavaSE_知识点(下1)(集合,IO流)

Java-----集合,IO流

文章目录

1.集合(java.util.*)

(1).概述

Ⅰ.集合实际上是一个容器(载体),可存储多个对象;(数组是最简单的集合);
Ⅱ.集合中不能存储基本数据类型和java对象,存储的是java对象的内存地址
Ⅲ.每个不同的集合底层对应不同的数据结构(数组,二叉树,链表,哈希表…);

(2).集合的分类和结构图

<1>.Collection接口:

超级父接口:java.util.Collection

a.Collection继承结构图:

JavaSE_知识点(下1)(集合,IO流)
概述:

①.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();

<2>.Iterator迭代器接口:

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()方法删除可自动更新迭代器。

<3>.List接口:存储元素有下标,有序可重复

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);
        }

<4>Map接口:元素无下标,无序不可重复

超级父接口:java.util.Map
a.数据存储特点
Map集合以key和value的方式存储数据,即【键值对】方式。
key和value都是引用数据类型,都存对象的内存地址。

Map继承结构图

JavaSE_知识点(下1)(集合,IO流)

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);

2.IO流(Input/Output Stream)

(1).概述

作用:
通过IO流可完成【硬盘文件的读和写】。
读和写的区分:
·读进入内存为输入【】;
·写出来内存为输出【】。
所在包:
java中所有的流均在java.io.*下。
分类:

Ⅰ.java.io.InputStream:字节输入流;
Ⅱ.java.io.OutputStream:字节输出流;
Ⅲ.java.io.Reader::字符输入流;
Ⅳ.java.io.Writer:字符输出流。

实现的接口:
①所有的【输出流】都实现了java.io.Flushable接口,存在flush()方法,作用是【刷新流】。
②【所有流】都实现了java.io.Closeable接口,存在close()方法,作用是【关闭流】。

(2).文件类流详解:

分类:

Ⅰ.java.io.FileInputStream
Ⅱ.java.io.FileOutputStream
Ⅲ.java.io.FileReader
Ⅳ.java.io.FileWriter

<1>.FileInputStream类详解:


定义:
文件字节输出流】,可读取任意格式的文件

构造方法:
源码:

/*
*@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);

<2>.FileOutputStream类详解:

定义:
文件字节输出流】。

构造方法:

/*
*@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();
            }
        }

<3>.FileReader类简介:

定义:
文件字符输入流】,仅能读取【普通文本】。

<4>.FileWriter类简介:

定义:
文件字符输出流】,仅能读取【普通文本】。

<5>.文件拷贝功能实现:

源代码:

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】,在此过程中同时进行了重命名操作。

(3).缓冲区类流详解:


缓冲区类流有:

Ⅰ.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测试文本"));

(4).标准输出流详解:


<1>.PrintStream

所在包:java.io.PrintStream
①.标准的【字节输出流】,默认输出到控制台。
②.该流无需手动关闭。
③.手动改变输出方向:(System类下)

public static void setOut(PrintStream ps);

<2>.PrintWriter

所在包:java.io.PrintWriter
①.标准的【字符输出流】,与上同;

(5).对象类流详解:

概述:
serialize,deserialize
①.【(反)序列化】:(反)将内存中的java对象放入硬盘文件中。
②.参与序列化与反序列化的对象,必须实现Serializable接口。
③.在属性前加【transient】关键字,表现该变量不参与(反)序列化。
④.IDEA可自动生成序列化版本号。
⑤.Map集合中的Properties类中的load()方法可将硬盘文件加载到内存中。

public synchronized void load(InputStream inStream);
public synchronized void load(Reader reader);

(6).java.io.File类详解:

概述:
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();

(7).拷贝目录程序设计:

/*
*该方法用于目录的拷贝
*@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);
        }
    }
}

上一篇:xml和集合混合使用-图书管理器


下一篇:PHP FastCGI进程管理器PHP-FPM的架构