4 Java 核心类库

4.1 泛型

泛型,即“参数化类型”。就是将原来具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

作用:

  • 提高代码的复用率
  • 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

4.1.1 泛型类

public class ClassName<T> {private T data;public   T getData() {return data;}public void setData() {this.data = data;}
}

4.1.2 泛型接口

public interface InterfaceName<T> {T getData();
}// 实现接口时可以选择指定泛型类型,也可以不指定:// 指定类型:
public class Interface1 implements InterfaceName<String> {private string text;@Overridepublic String getData() {return text;}
}// 不指定类型:
public class Interface2<T> implements InterfaceName<T> {private T data;@Overridepublic T getData() {return data;}
}

4.1.3 泛型方法

private static <T> T methodName(T a, T b) {}// e.g.
public static <T> void print(T a) {system.out.println(a);
}

4.1.4 泛型限制类型

指定泛型的限定区域,例如: 必须是某某类的子类或 某某接口的实现类:

// 格式:<T extends 类或接口1 & 接口2>// e.g.
public static void main(String[] args) {Plate<Apple> p = new Plate<>();
}
interface Fruit{}
class Apple implements Fruit{}
class Plate<T extends Fruit> {T data;
}

4.1.5 通配符 ?

  • <? extends Parent> 指定了泛型类型的上界

  • <? super Child> 指定了泛型类型的下界

  • <?> 指定了没有限制的泛型类型

Plate<? extends Fruit> p = new Plate<Apple>(); // 上界
Plate<? super Apple> p = new Plate<Fruit>(); // 下界

注意:在编译之后程序会采取去泛型化的措施,也就是说Java中的泛型只在编译阶段有效,而不会进入到运行时阶段。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦除,并在对象进入和离开方法的边界处添加类型检查和类型转换的方法。


4.2 常见类库

4.2.1 java.util.Objects

  • 此类包含static实用程序方法(null或null防范,用于计算对象的哈希代码,返回对象的字符串,比较两个对象,检索索引或子范围值是否超出范围),用于操作对象或在操作前检查某些条件
  • 源码:
// static boolean equals(Object a, Object b)
public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));
}// static boolean isNull(Object obj)
public static boolean isNull(Object obj) { return obj == null; }// static boolean nonNull(Object obj)
public static boolean isNull(Object obj) { return obj != null; }// static boolean requireNonNull(T obj):检查对象引用是否不是null
public static <T> T requireNonNull(T obj) {if (obj == null)throw new NullPointerException(); //如果是空,直接抛出异常return obj;
}

4.2.2 java.lang.Math

//四舍五入
Math.round(-100.5); // -100

4.2.3 java.util.Arrays

binarySearch, compare, equals, sort, toString, copyOf

int[] arr = {2,3,4,5,1};
System.out.println(arr); //打印的是内存地址(哈希值)
System.out.println(Arrays.toString(arr)); //打印[2,3,4,5,1]
Arrays.sort(arr); //排序
Arrays.binarySearch(arr, 6); //二分查找
arr = Arrays.copyOf(arr, 15); //扩容至长度为15

4.2.4 java.math.BigDecimal

实现小数的精准运算

// 构造方法
public BigDecimal(String val) {}// 常用方法
public BigDecimal add(BigDecimal augend);
public BigDecimal subtract(BigDecimal augend);
public BigDecimal multiply(BigDecimal augend);
public BigDecimal devide(BigDecimal augend);// e.g.
BigDecimal b1 = new BigDecimal("0.1");
BigDecimal b2 = new BigDecimal("0.2");
BigDecimal b3 = b1.add(b2); // 0.3
double d = b3.doubleValue(); // 转换为double类型

4.2.5 java.util.Date

表示特定的时刻,精度为毫秒

构造方法:

  • Date() 当前时间
  • Date(long date)

方法:

  • long getTime() 返回自1970年1月1日00:00:00GMT以来的毫秒数
  • void setTime(long time) 设置时间点

4.2.6 java.text.DateFormat

  • 用于格式化和解析日期字符串
  • 是一个抽象类,使用子类SimpleDateFormat
  • 常用方法:
    • String format(Date date) 格式化日期
    • Date parse(String source) 解析日期字符串
/*** y: 年* M: 月* d: 日* H: 时* m: 分* s: 秒*/
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String text = format.format(new Date()); // 将date对象格式化为字符串
Date date = format.parse("2021-12-12 12:12:12"); // 将符合格式的字符串转化为date对象,可用于计算时间差

4.2.7 java.util.Calendar

  • 是一个抽象类,通过其getInstance()方法创建对象
  • 年月日时分秒都存储在filed数组里,通过传入下标(例如Calendar.YEAR)用get()方法获取
  • 常用方法:
    • set get add
    • getTime 获取日历时间表示的Date对象
    • getActualMaximum 获取某字段的
Calendar cl = Calendar.getInstance(); //创建对象int year = cl.get(Calendar.YEAR); //2020
int year = cl.get(Calendar.MONTH); //0-11
int day = cl.get(Calendar.DAY_OF_YEAR); //一年的第几天,从0开始cl.set(Calendar.YEAR, 2021); //设置年为2021
cl.add(Calendar.YEAR, 1); //设置年+1Date d = cl.getTime(); //获取日历时间表示的Date对象
int m = cl.getActualMaximum(Calendar.DAY_OF_MONTH); //当前月份的最大值

4.2.8 java.lang.System

常用方法:

  • gc() 运行垃圾回收器
  • exit(int status) 终止当前运行的Java虚拟机
  • static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 复制数组

4.2.9 java.lang.String

  • 字符串是不变的,他们的值在创建后无法更改

    String str = "abc";
    // 相当于
    char data[] = {'a', 'b', 'c'};
    string str = new String(data);
    
  • String类 用final修饰,不能被继承

  • 两个字符串内容如果完全相同,则它们采用同一块内存地址(即可共享);但如果 是通过new创建的对象,一定是新开辟的空间

  • 字符串常量池(存在方法区中)

    1. 方法区Method Area(加载代码的内存区),又称永久代Permanent Generation,被所有线程共享2. 堆heap
    1) 一个JVM实例只存在一个堆内存,大小是可以调节的;
    2) 类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行;
    3) 堆 在逻辑上分为三部分(Perm):
    - 新生代 YoungGen:存刚创建的对象,gc回收很快
    - 老年代 OldGen:存常用的对象(在新生代中连续15次没有被回收)
    - 永久代 PermGen:类、方法、常量、static修饰的(不会被垃圾回收)3. JDK1.8演变
    字符串常量池还在堆,运行时常量池还在方法区,只不过方法区的实现从永久代变成了元空间Metaspace;
    元空间与堆不相连,但与堆共享物理内存,逻辑上可认为在堆中
    
  • 一种构造方法:

    String(byte[] bytes, Charset charset) 使用charset字符集解码字节数组

  • 方法:

    • int compareTo(String anotherString) 按字典顺序比较两个字符串
    • boolean contains(CharSequence s) 是否包含指定的char值序列
    • int indexOf(int ch) 指定字符第一次出现在字符串中的索引
    • String trim() 删除首尾空格
  • 字符串拼接:

    • 每+一次就在内存中创建一个新的String对象,即产生一次垃圾(在永久代里不会被回收)
    • 因此不应该使用String,应该使用StringBuffer / StringBuilder
    String, StringBuilder, StringBuffer 的区别:1. String 是字符串常量,不可变,修改时会创建了一个新的String对象,然后将指针指向它2. StringBuffer 和 StringBuilder 是字符串变量,使用时会对对象本身进行操作(会动态扩容),而不是生成新的对象再改变对象引用,最后可以用 toString()方法转成 String3. StringBuffer 是线程安全的;而 StringBuilder 不是(不能保证同步),速度更快,单线程时使用4. 在某些特别情况下, String 对象的字符串拼接其实被 Java Compiler 编译成了 StringBuffer 对象的拼接,所以这时 String 对象的速度不比 StringBuffer 对象慢,例如:String s1 = "This is only a" + "simple" + "test";StringBuffer Sb = new StringBuilder("This is only a" ).append("simple").append("test");其实在 Java Compiler 里,自动做了如下转换:String s1 = "This is only a simple test";但如果拼接的字符串来自另外的 String 对象的话,Java Compiler 就不会自动转换了,速度也就没那么快了,例如:String s2 = “This is only a”;  String s3 = “ simple”;  String s4 = “ test”;  String s1 = s2 + s3 + s4;
    

4.3 集合

4.3.1 Collections

  • Java类集中保存单值的最大操作接口
  • 子接口:List,Set(区分集合中是否允许有重复元素)

4.3.2 List

  • 常用的实现类:ArrayList, Vector, LinkedList
  • 常用方法:
    • E get(int index) 根据索引位置取出元素
    • int indexOf(Object o) 查找指定对象的位置
    • void add(int index, E element) 在指定位置添加元素
    • E remove(int index) 删除指定位置的元素(重载了继承的父类Collections中的boolean remove(Object o)方法)

ArrayList

  • 构造方法:

    • 无参(初始容量10):先构造一个长度为0的列表,而添加一个元素时会自动扩容
    • 一参(指定初始容量)
    • ArrayList(Collection<? extends E> c) 构造包含指定集合元素的列表
  • boolean add(E e) 一定返回true

    • 扩容:

      private Object[] grow(int minCapacity) {return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));
      }private int newCapacity(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍//如果计算的新长度比需要的长度小(还不够存):0*1.5=0, 1*1.5=1, 添加一组数据,长度不可控if (newCapacity - minCapacity <= 0) { // 如果是第一次创建,没有传长度if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); // 默认长度(10)与minCapacity(第一次为1)取最大}if (minCapacity < 0)throw new OutOfMemoryError();return minCapacity;}return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); // MAX_ARRAY_SIZE= Integer.MAX_VALUE-8
      }
      

Vector

  • 构造方法中可以指定容量增量(即比ArrayList多一种构造方法):

    Vector(int initialCapacity, int capacityIncrement)

ArrayList, Vector, LinkedList 区别

链表(LinkedList) vs 数组(ArrayList/Vector)
1. 数组是连续存储的,链表不必相连(灵活地分配内存空间)
2. 数组查找快(通过下标查询),增删慢(需要移动元素);链表查找慢 O(n),增删快 O(1)
3. ArrayList和Vector都是基于动态数组实现的(通过新数组覆盖老数组的方式扩容),而LinkedList是通过链表实现的ArrayList vs Vector
1. ArrayList是线程不安全的,速度较快;而Vector是线程安全的,是同步的
2. Vector比ArrayList多了一种构造方法,可以指定容量增量(默认为一倍);而ArrayList的增量为0.5倍,不能指定

4.3.3 Iterator, ListIterator 迭代器

  • Iterator 用于迭代 Collections的所有集合(List, Set)
  • ListIterator 只能迭代 List的集合
    • 可以控制指针往前走:previous()
    • 可以插入元素(插入到next()返回的元素之前):add(E e)
    • 可以修改当前指针指定的数据:set(E e)
ArrayList<Integer> data = new ArrayList<>();
data.add(1);
data.add(2);
data.add(3);
Iterator<Integer> iterator = data.iterator();
while (iterator.hasNext()) {Integer i = iterator.next();
}
// remove前需要先获取:
Iterator<Integer> iterator = data.iterator();
iterator.next();
iterator.remove();

forEach

  • 用于迭代数组或Colleciton的集合(用迭代器)

    int[] arr = {5,4,3,2,1}
    for (int data : arr) {System.out.println(data);
    }
    //
    ArrayList<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    for (String s: list) {System.out.println(s);
    }
    

4.3.4 Set

  • 不包含重复元素(包括null)
  • 获取元素方法(没有get(int index)方法,即不能通过传入下标的方式查找数据):
    • iterator()方法得到迭代器
    • toArray()变成数组

HashSet

  • 散列存放(哈希表/散列表,内部有一个HashMap对象),无序存储

  • 单值存储,即重复利用了双值存储的HashMap:

    private static final Object PRESENT = new Object();
    public boolean add(E e) {return map.put(e, PRESENT) == null;
    }
    

TreeSet

  • 二叉树存储(基于TreeMap),有序(根据数据的顺序)

  • 其iterator方法返回的迭代器是快速失败的:在并发修改的情况下,迭代器快速而干净地失败

    • 快速失败:如果在创建迭代器之后修改了集合(除了通过迭代器自己的remove方法),迭代器将抛出ConcurrentModificationException

    • 安全失败(通常):遍历的是复制的集合,所以迭代时不会失败

TreeSet<String> data = new TreeSet<>();
data.add("c");
data.add("a");
data.add("b");
for (String s: data) {System.out.println(s); // a b c
}

4.3.5 Map<K, V>

  • 存储一个个的键值对数据

  • 键key 不可重复(所以Set的内部都使用了Map)

  • 每个键最多可映射一个值

  • 方法:

    • Set<K> keySet() 得到键的set
    • 遍历:对key进行迭代,调用V get(Object key)取到值
    • 存储:V put(K key, V value) 如果产生了替换,会返回旧值,否则返回null
    • 删除:V remove(Object key) default boolean remove(Object key, Object value)

HashMap

  • 实现:哈希桶:对象数组+链表/红黑树

    • 取模:hashCode()%N (初始桶数量16,则得到0-15的下标/索引,存到对应位置)

    • 数组的每个元素都是一个链表/红黑树(解决哈希值冲突问题)

    • 1.8优化:当哈希桶(链表)中的数据量>8,链表会转化成红黑树(更利于查找);

      ​ 当哈希桶中的数据量减少到6时,从红黑树转换为链表

    • 散列因子0.75:如果桶中有75%存了数据,扩容一倍(*2),可以指定

      • 过小:浪费内存空间
      • 过大:查询效率低
    • 扩容:散列,重建

  • 搜索:不需要遍历,只需得到hashcode取余运算得到下标

Hashtable, HashMap, ConcurrentHashMap, LinkedHashMap 区别

1. HashMap线程不安全(同时,不保证同步),效率高;Hashtable线程安全(排队机制),效率低
2. ConcurrentHashMap:采用分段锁机制保证线程安全,效率又比较高(只有当操作的是同一下标的桶时才需要排队)HashMap不保证存储顺序(因为hashcode计算),LinkedHashMap能保证存储顺序(会同时存进双向链表中)

4.4 IO

4.4.1 java.io.File

  • 文件和目录路径名的抽象表示
  • 常用构造方法:
    • File(String pathname)
    • File(File parent, String child) 文件夹,新文件名称
    • File(String parent, String child)
  • 字段:
    • static String pathSeparator 与系统相关的路径分隔符
    • static String separator 与系统相关的名称分隔符
  • 常用方法:
    • boolean delete()
    • boolean deleteOnExit()
    • boolean createNewFile() 创建指定新文件(指定文件不存在时)
    • boolean mkdir() 创建目录
    • boolean mkdirs() 创建目录(包括不存在的父目录)
    • String getAbsolutePath() 获取文件/目录的绝对路径(从盘符开始)
    • String getPath() 返回的是定义时的路径
    • String getName() 获取文件/目录名称
    • String getParent() 获取父目录名称
    • File getParentFile() 获取父目录对象
    • long length() 获取文件的大小(字节)
    • boolean exists() 判断文件/目录是否存在
    • boolean isDirectory() 判断对象是否为目录
    • boolean isFile() 判断对象是否为文件
    • File[] listFiles() 获取目录中所有的对象
    • String[] list() 获取目录中所有的对象名称
    • boolean renameTo(File deat) 重命名/移动
// 获取字段
System.out.println(File.pathSeparator); // ; 路径分隔符
System.out.println(File.separator); // \ 名称分隔符// 构造方法1,创建新文件夹
File dir = new File("c://haha");
dir.mkdir();
// 构造方法2,创建新文件
File a = new File(dir, "a.txt");
a.createNewFile();
// 构造方法3,创建新文件
File b = new File("c://haha", "b.txt");
b.createNewFile();//删除
a.delete();
b.delete();
  • 文件遍历

    public static void main(String[] args) throws IOException {File e = new File("e:\\");File[] files = e.listFiles();listFiles(files);
    }// 遍历目录,删除所有200MB以上的avi文件
    public static void listFiles(File[] files) {if (files != null && files.length>0) {for (File file : files) {if (file.isFile()) {// 是文件if (file.getName().endsWith(".avi")) {// 找到了一个avi文件if (file.length() > 200*1024*1024) {file.delete();System.out.println(file.getAbsolutePath()+" 已删除");}}} else {// 文件夹File[] files2 = file.listFiles();listFiles(files2); // 递归遍历子文件夹}}}
    }
    

文件过滤器 FileFilter

public static void listFiles(File dir) {// 1. 创建一个过滤器 并 描述规则FileFilter filter = new FileFilter() { // 匿名内部类,只使用一次@Overridepublic boolean accept(File pathname) {if (pathname.getName().endsWith(".avi") || pathname.isDirectory())return true;return false;}};// 2. 获取文件,遍历File[] files = dir.listFiles(filter);if (dir != null && dir.length>0) {for (File file : dir) {if (file.isDirectory())listFiles(file);else System.out.println(file.getAbsolutePath());}}
}

4.4.2 IO流 概述

  • 将数据传输操作看作一种数据的流动,按照流动的方向分为输入Input和输出Output
  • Java中的IO操作主要指的是java.io包下的一些常用类的使用,通过这些常用类对数据进行读取(输入Input) 和 写出(输出Output)
  • 数据传输时都是以二进制形式存储的
  • IO流的分类:
    • 按方向分:输入流 输出流
    • 按流动的数据类型:
      • 字节流:

        • 输入流:InputStream
        • 输出流:OutputStream
      • 字符流:
        • 输入流:Reader
        • 输出流:Writer

4.4.3 字节流

java.io.OutputStream
  • 字节输出流的所有类的超类
  • 常用方法:
    • void close() 关闭此输出流并释放与该流相关的所有系统资源
    • void flush() 刷新此输出流并强制写出任何缓冲的输出字节
    • void write(byte[] b) 将所有字节从指定字节数组写入到此输出流
    • void write(byte[] b, int off, int len) 将从偏移量off开始的指定字节数组中的len个字节写入输出流
    • abstract void write(int b) 将指定的字节写入此输出流(写入的字节是b的八个地位)
java.io.FileOutputStream
  • OutputStream的常用子类
  • 构造方法:
    • FileOutputStream(File file)
    • FileOutputStream(File file, boolean append) append=true表示接着原来的写
    • FileOutputStream(String name)
    • FileOutputStream(String name, boolean append)
public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("c://a.txt");fos.write(65); // Abyte[] bytes = {65,66,67,68,69};fos.write(bytes); // AABCDEfos.close();
}
public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("c://a.txt");byte[] bytes = {65,66,67,68,69};fos.write(bytes); // ABCDE; 如果改成FileOutputStream("c://a.txt", true)则为AABCDEABCDEfos.close();
}
public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("c://a.txt");byte[] bytes = "ABCDE".getBytes();fos.write(bytes, 1, 2); // BCfos.close();
}
java.io.InputStream
  • 字节输入流:把硬盘中的文件读取输入到内存中
  • 常用方法:
    • abstract int read() 从输入流中读取下一个数据字节(返回值范围0-255;如果由于达到流末尾而没有可用字节,则返回 -1)
    • int read(byte[] b) 从输入流中读取一些字节数并存储到缓冲区数组b
    • void close()
java.io.FileInputStream
  • InputStream的常用子类
  • 构造方法:
    • FileInputStream(File file)
    • FileInputStream(String name)
public static void main(String[] args) {FileInputStream fis = new FileInputStream("c://a.txt"); // abcdef// 一次读取一个字节byte b = (byte) fis.read(); // 97char b2 = (char) fis.read(); // b// 循环读取一个字节直至结束:cdefwhile (b != -1) {byte b = (byte) fis.read();System.out.print((char) b); }fis.close();
}
public static void main(String[] args) {FileInputStream fis = new FileInputStream("c://a.txt"); // a-z// 一次读取10个字节byte[] bytes = new byte[10];fis.read(bytes);System.out.println(new String(bytes)); //abcdefghijfis.read(bytes);System.out.println(new String(bytes)); //klmnopqrstfis.read(bytes);System.out.println(new String(bytes)); //uvwxyzqrst 放在数组的前6位,后面的没有清空fis.close();
}

解决该问题:

public static void main(String[] args) {FileInputStream fis = new FileInputStream("c://a.txt"); // a-z// 一次读取一组(10个)字节(常用,减少IO频率)byte[] bytes = new byte[10];int len = fis.read(bytes);while (len != -1) {System.out.println(new String(bytes, 0, len)); len = fis.read(bytes);}/* abcdefghijklmnopqrstuvwxyz*/fis.close();
}

文件加密和解密

加密/解密用异或运算:任何数据^相同的数字两次=其本身

public static void main(String[] args) {System.out.print("请输入文件存储的全路径:");Scanner input = new Scanner(System.in);String fileName = input.nextLine();// 原文件: a.pngFile oldFile = new File(fileName);// 加密存储的新文件: mi-a.pngFile newFile = new File(oldFile.getParentFile() + "mi-" + oldFile.getName());FileInputStream fis = new FileInputStream(oldFile);FileOutputStream fos = new FileOutputStream(newFile);while (true) {int b = fis.read();if (b == -1) break;fos.write(b^10); }System.out.println("加密或解密完成");fis.close();fos.close();
}

4.4.4 字符流

  • 以字符为单位,只能操作文字
Writer 字符输出流
  • 常用方法:

    • abstract void close()
    • Writer append(CharSequence csq) 将指定字符串序列追加到此Writer
    • void write(int c) 写一个字符
    • void write(char[] cbuf) 写一个字符数组
    • abstract void write(char[] cbuf, int off, int len) 写一个字符数组的一部分
    • void write(String str) 写一个字符串
    • void write(String str, int off, int len) 写一个字符串的一部分
FileWriter
  • 构造方法:

    • FileWriter(File file)
    • FileWriter(File file, boolean append)
    • FileWriter(File file, Charset charset)
public static void main(String[] args) {FileWriter fw = new FileWriter("c://b.txt");fw.write('a');fw.write("床前明月光");FileWriter fw2 = (FileWriter) fw.append("锄禾日当午"); //fw==fw2fw2.append(", ").append("汗滴禾下土");fw.close();
}
flush刷新管道
  • 操作字符输出流时需要注意:

    输出方(内存)给输入方(硬盘)发送的过程中,有一个缓存

  • 字符输出的时候,刷新缓存空间,强制把缓存空间的内容写出到文件:fw.flush()

  • close()时会自动刷新

Reader 字符输入流
  • 常用方法:

    • abstract void close()
    • int read() 一次读取一个字符
    • int read(char[] cbuf) 一次读取一组字符至数组
    • int read(char[] cbuf, int off, int len) 一次读取字符至数组的一部分
FileReader
  • 构造方法:

    • FileReader(String fileName)
    • FileReader(String fileName, Charset charset)
    • FileReader(File file)
public static void main(String[] args) {FileReader fr = new FileReader("b.txt");// 循环一次读一个字符while (true) {int c = fr.read();if (c == -1) break;System.out.println((char) c);}fr.close();
}
public static void main(String[] args) {FileReader fr = new FileReader("b.txt");// 循环一次读一组字符到数组char[] chars = new char[100]; //注意:默认为0(空格)fr.read(chars);System.out.println(new String(chars)); //不足100的话后面跟着空格fr.close();
}

解决:

public static void main(String[] args) {FileReader fr = new FileReader("b.txt");// 循环一次读一组字符到数组char[] chars = new char[100]; //注意:默认为0(空格)int len = fr.read(chars);System.out.println(new String(chars, 0, len)); //不足100的话后面跟着空格fr.close();
}

4.4.5 转换流 InputStreamReader

  • 将字节流 装饰为 字符流:使用了装饰者设计模式
  • 输入流转换:
public static void main(String[] args) {FileInputStream fis = new FileInputStream("c://a.txt");// 将字节输入流 转换为 字符输入流// 参数1:要转换的字节流; [参数2:编码名称]InputStreamReader isr = new InputStreamReader(fis, "gbk");while (true) {int c = isr.read();if (c == -1) break;System.out.print((char) c);}}
  • 输入流转换:
public static void main(String[] args) {FileInputStream fis = new FileInputStream("c://a.txt");// 将字节输入流 转换为 字符输入流// 参数1:要转换的字节流; [参数2:编码名称]InputStreamReader isr = new InputStreamReader(fis, "gbk");while (true) {int c = isr.read();if (c == -1) break;System.out.print((char) c);}isr.close();
}
  • 输出流转换:
public static void main(String[] args) {FileOutputStream fos = new FileOutputStream("c://a.txt");// 将字节输出流 转换为 字符输出流OutputStreamWriter osw = new OutputStreamWriter(fos);osw.write("锄禾日当午,汗滴禾下土");osw.flush();osw.close();
}

4.4.6 打印流 PrintStream, PrintWriter

  • 字符输出(System.out)
  • PrintStream 是 FileOutputStream 的子类;PrintWriter 是 Writer 的子类
PrintStream ps = new PrintStream("c://c.txt");
ps.println("锄禾日当午,汗滴禾下土");
PrintWriter pw = new PrintWriter("c://c.txt");
pw.println("锄禾日当午,汗滴禾下土");
pw.flush(); //字符流需要刷新管道
  • 也可以用于转换字节流(建议)

    FileOutputStream fos = new FileOutputStream("c://c.txt");
    PrintWriter pw = new PrintWriter(fos);
    pw.println("锄禾日当午,汗滴禾下土");
    pw.flush();
    

4.4.7 缓存读取流 BufferedReader

  • 将字符输入流转换为带有缓存,可以一次读取一行的缓存字符读取流
  • 读到结尾时返回null
FileReader fr = new FileReader("c://c.txt");
BufferedReader br = new BufferedReader(fr);
String text = br.readLine();
System.out.println(text);

4.4.8 收集异常日志

try {String s = null;s.toString();
} catch (Exception e) {PrintWriter pw = new PrintWriter("c://bug.txt");// 打印日期SimpleDateFormat sdf = new SimpleDateFormat("yyyy-dd HH:mm:ss");pw.println(sdf.format(new Date()));// 写入异常e.printStackTrace(pw);pw.close();
}

4.4.9 Properties

  • 是HashTable的子类,是Map集合

  • .properties文件:一行存储一个键值对,可以存储多行

  • 方法:

    • synchronized Object put(Object key, Object value) 存储键值对
    • synchronized void load(Reader reader) 把properties文件加载成程序中的Map集合
    • synchronized void load(InputStream inStream)
    • void store(Writer writer, String comments) 存储为properties文件,字符串为注释
    • void store(OutputStream out, String comments)
  • 存储:

    public static void main(String[] args) throws IOException {Properties ppt = new Properties();ppt.put("name", "金苹果");ppt.put("info", "讲述了苹果种植的过程");FileWriter fw = new FileWriter("c://book.properties");ppt.store(fw, "存储的图书");fw.close();
    }
    

    book.properties:

    #\u5B58\u50A8\u7684\u56FE\u4E66
    #Sun Aug 23 00:27:56 CST 2020
    name=金苹果
    info=讲述了苹果种植的过程
    
  • 读取:

    public static void main(String[] args) throws IOException {Properties ppt = new Properties();Reader r = new FileReader("c://book.properties");ppt.load(r);//System.out.println(ppt.get("name"));//System.out.println(ppt.get("info"));System.out.println(ppt.getProperty("name"));System.out.println(ppt.getProperty("info"));
    }
    

4.4.10 序列化技术

  • 对象序列化:将 Java 对象的状态转换为字节数组,以便存储或传输

  • 反序列化:将字节数组转换回 Java 对象原有的状态

  • 实现:该类需要实现Serializable接口,其包含的对象的类也需要实现Serializable接口

    public static void main(String[] args) throw IOException {// 序列化Book b = new Book("金苹果", "描述了苹果种植的过程");ObjectOutputStream oos = new ObjectOutputStream(new FileOutputSteam("c://book.txt"));oos.writeObject(b);oos.close();// 反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c://book.txt"));Book o = (Book) ois.readObject();
    }static class Book implements Serializable {private String name;private String info;public Book() {}public Book(String name, String info) {this.name = name;this.info = info;}public void setName(String name) { this.name = name; }public String getName() { return name; }public void setInfo(String info) { this.info = info; }public String getInfo() { return info; }
    }
    

4.4.11 try-with-resources

关闭并释放资源:

  • JDK1.7之前:

    public static void main(String[] args) {FileReader fr = null;try {fr = new FileReader("c://book.txt");int c = fr.read();System.out.println((char) c);} catch (IOException e) {e.printStackTrace();} finally {try {fr.close();} catch (Exception e) {e.printStackTrace();}}
    }
    
  • JDK1.7:FileReader extends InputStreamReader extends Reader implements Closeable extends AutoCloseable { void close() throws Exception; }

    =>能在try()括号中创建的对象必须实现AutoCloseable接口,即必然拥有close()方法

    public static void main(String[] args) {try (FileReader fr = new FileReader("c://book.txt")) {int c = fr.read();System.out.println((char) c);} catch (IOException e) {e.printStackTrace();}
    }
    
    public static void main(String[] args) {try (CloseDemo d = new CloseDemo()) {} catch (Exception e) {}
    }
    static class CloseDemo implements Closeable {@Overridepublic void close() throws IOException {System.out.println("close方法被调用了");}
    }
    
  • JDK9:

    public static void main(String[] args) throw FileNotFoundException {FileReader fr = new FileReader("c://book.txt");PrintWriter pw = new PrintWriter("c://book.txt");try (fr; pw) {int c = fr.read();System.out.println((char) c);} catch (IOException e) {e.printStackTrace();}
    }
    

Java学习笔记 - 4 Java核心类库相关推荐

  1. Java学习笔记1:Java中有关print、println、printf的用法和区别

    Java学习笔记1:Java中有关print.println.printf的用法和区别 最近在学习java,写一些笔记记录下. 1.print()函数是一般的标准输出,但是不换行. 2.println ...

  2. Java学习笔记(java基础)

    Java学习笔记(第一周) Java 介绍 Java 发展方向 JVM , JDK , JRE 名词解释 Java语言的特点 Java安装 安装包的下载 配置环境变量 验证是否安装成功 Java的第一 ...

  3. 【java】java学习笔记之java oop(面向对象)

    如下图所示为笔者总结的java oop(面向对象)学习笔记,其中,附带有代码示例(未展开),方便理解记忆.需要源文件的请到我的资源中下载,下载地址:https://download.csdn.net/ ...

  4. Java学习笔记01—Java概述、数据类型、变量、标识符、类型转换

    1. Java概述 1.1 Java语言发展史(了解) 语言:人与人交流沟通的表达方式 计算机语言:人与计算机之间进行信息交流沟通的一种特殊语言 Java语言是美国Sun公司(Stanford Uni ...

  5. 【java】java学习笔记之java常用类

    如下图所示为笔者总结的java常用类学习笔记,其中,附带有代码示例(未展开),方便理解记忆.需要源文件的请到我的资源中下载,下载地址:https://download.csdn.net/downloa ...

  6. java学习笔记(一) ----java下常用的包功能

    ***java下常用的包*** java.lang----包含一些java语言的核心类,如String,Math,Integer,System,Thread,提供常用的功能. java.awt---- ...

  7. Java 学习笔记(4)——java 常见类

    上次提前说了java中的面向对象,主要是为了使用这些常见类做打算,毕竟Java中一切都是对象,要使用一些系统提供的功能必须得通过类对象调用方法.其实Java相比于C来说强大的另一个原因是Java中提供 ...

  8. Java学习笔记-7.Java IO流

    一.输入/输出流 1.流:不同类型的输入.输出源    数据流:输入或输出的数据 Java数据流的所有接口和类都是在java.io包中定义的,因此应在程序开头加入 import java.io.* 2 ...

  9. JAVA学习笔记 03 - JAVA语言程序结构

    本文是Java基础课程的第三课.计算机语言的程序结构无外乎顺序结构.分支结构.循环结构,本文主要介绍Java语言中这些程序结构是如何实现的 文章目录 一.程序结构 二.分支结构 1.单分支if语句 2 ...

最新文章

  1. 阅读准备-构建redis容器
  2. “docker exec“ requires at least 2 arguments. See ‘docker exec --help‘.
  3. 数据结构单向不循环链表实现多项式合并
  4. [CodeForces]Codeforces Round #432 (Div. 2)
  5. CF 570D. Tree Requests [dsu on tree]
  6. spring boot 整合mybatis + swagger2
  7. 乐优商城(01)--项目启动
  8. QQ2000 的聊天室刷屏机设计技术
  9. [渝粤教育] 浙江大学 设计思维与创新设计 参考 资料
  10. 路由器刷openwrt固件准备工作
  11. Treedp贪吃的九头龙详解
  12. Windows10视频文件没有预览图的解决办法
  13. 用cmd 改电脑ip
  14. python100个常用术语_Python 常用术语
  15. CSS的水平居中、垂直居中和水平垂直居中
  16. Android DOM解析xml
  17. Java实现随机人名抽取
  18. 机器人届的“擎天柱”来了!能够在空中变形以快速栖息的四旋翼机器人
  19. MATLAB生成随机点
  20. 暗备用的运行状态_电力系统自动装置随堂练习

热门文章

  1. FreeMarker 指南(二) -【纯属整理】
  2. SkeyeVSS综合安防监控Onvif、RTSP、GB28181视频云无插件直播点播解决方案之系统参数配置日志管理
  3. 什么是Hosts文件以及如何修改Hosts文件
  4. 真正的高手,都在刻意练习(建议收藏)
  5. 2023年上海大学文物与博物馆考研上岸前辈初复试备考经验指导
  6. Win11系统关闭防火墙的方法
  7. 随机数生成器【LCG算法】
  8. QQ怎么让好友在列表里隐藏
  9. python爬虫学习之Soup模块
  10. 分享电影《了不起的老爸》