Java常见工具类总结

 


目录

 

 

1. 基础知识:Java中 == 和 equals 的区别

2. Java 重写equals()  方法

3. Java 中常用的集合类

3.1 集合中重要类的接口介绍:

3.2 常见的几种集合类的对比

4. 常见的输入输出流

4.1 java 中的文件类 File

4.2 字节流

4.3 字符流Writer/Reader

4. 4 如何选择IO 流:


 

1. 基础知识:Java中 == 和 equals 的区别

 

  1.1  基本类型数据:

    

byte,short,char,int,long,float,double,boolean 他们之间的比较应该使用(==),比较的是他们的值。

equals 比较的是引用是否相同

        String s1 = "abc";
        String s2 = "abc";
        String s3 = new String("abc");

        System.out.println(s1 == s2); // true
        System.out.println(s1 == s3); // false
        System.out.println(s3.equals(s1)); // true

1.2 引用类型数据:

a, 当使用 === 比较的时候,比较的是 他们在内存中的存放地址。

String a = "abc";
String b = "abc";
System.out.println(a == b);//true

b, 当使用 equals 比较时,这个方法的初始行为是比较对象在堆内存中的地址。

 

equals()方法是用来判断其他的对象是否和该对象相等.

//equals()方法在object类中定义如下: 
public boolean equals(Object obj) {  
    return (this == obj);  
}  

但在一些诸如String,Integer,Date类中把Object中的这个方法覆盖了,作用被覆盖为比较内容是否相同。

Math、Integer、Double等这些类都是重写了equals()方法的,从而进行的是内容的比较,而不再是地址的比较。当然,基本类型是进行值的比较。

String 的内存分配图

String str1= "hello";   
String str2= new String("hello");   
String str3= str2;   

从图中可以发现每个String对象的内容实际是保存到堆内存中的,而且堆中的内容是相等的,但是对于str1和str2来说所指向的地址堆内存地址是不等的,所以尽管内容是相等的,但是地址值是不相等的
“==”是用来进行数值比较的,所以str1和str2比较不相等,因为str2和str3指向同一个内存地址所以str2和str3是相等的。所以“==”是用来进行地址值比较的。


链接:https://www.jianshu.com/p/08445889bbb1
 

2. Java 重写equals()  方法

重写 equals()方法的模板:

package MyDemo;

import java.util.Objects;

public class Human {

    private int age;
    private String name;

    public Human(int age, String neme){
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int hashCode(){
        return Objects.hash(age, name);
    }

    public boolean equals(Object obj){

        // 测试两个对象是否相同
        if (this == obj) return true;

        // 检测对象是否为空
        if (obj == null) return false;

        //  检测两个对象所属于的类是否相同;
        if (this.getClass() != obj.getClass()) return false;

        //  对 otherObject 进行类型转换和 类 Human 对象比较
        Human other = (Human)obj;
        return Objects.equals(name, other.name) && age == other.age;
    }

    public static void main(String[] args) {

        Human human = new Human(14, "zhangsan");
        Human human1 = new Human(14, "zhangsan");

        System.out.println(human.equals(human1));  // 初始没有重写equals 为false
        System.out.println(human.hashCode());
        System.out.println(human1.hashCode());  // 如果 name 和 age 都是相同的话,哈希值相同


    }

}

为什么重写equals方法之前要重写hashCode方法:

因为 Object规范中说到: 相等的对象必须具有相等的散列码
因为hashCode散列码的目的是为了HashSet、HashMap、HashTable比较的时候缩小范围空间,它只是返回一个散列整数然后根据散列码去散列桶中查找对象区间。它不保证对象是否是相等的

 

抽象类和接口的区别:

1. 抽象类:

抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类作为很多子类的父类,它是一种模板式设计。

抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,男人和女人都是属于人类,它们都有一些共性,比如有眼睛、鼻子、会走路等等,就可以把这些方法抽象出来。

继承是一个 "是不是"的关系,如 男人 是不是 人类

public abstract class Employee
{
   private String name;
   private String address;
   private int number;

   public Employee(String name, String address, int number) // 构造方法
   {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }

   public double computePay()  // 自己实现的方法
   {
     System.out.println("Inside Employee computePay");
     return 0.0;
   }
   
   public abstract double computePay();  // 抽象方法
   
   //其余代码
}

1. 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样

2. 抽象类相当于时定义一个类模板,是用来继承的,所以不能直接实例化

3. 抽象类中的抽象方法只是声明,不给出方法的具体实现

4. 如果类中有抽象方法,则必须是抽象类

5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

2. 接口:

接口是一种行为规范,没有继承的关系,接口 实现则是 "有没有"的关系,比如 定义一个接口 Fly(),

但 男人 这个类实现 飞 这个接口时,相当于拥有了这项 飞 的功能。所以,接口有扩展功能的作用。

interface Animal {
   public static final String NAME = "god";

   public void eat();
   public void travel();
}
  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法。
  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法,可以实现多继承。

3. 抽象类和接口的区别

  • 1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  • 2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  • 3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  • 4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

 

3. Java 中常用的集合类

在编程中,常常需要集中存放多个数据。从传统意义上讲,数组是我们的一个很好的选择,前提是我们事先已经明确知道我们将要保存的对象的数量。

一旦在数组初始化时指定了这个数组长度,这个数组长度就是不可变的,如果我们需要保存一个可以动态增长的数据(在编译时无法确定具体的数量),java的集合类就是一个很好的设计方案了。

 

集合是java中存放对象的容器,存放于java.util包中。下图是java集合类的继承与实现关系:

3.1 集合中重要类的接口介绍:

1、List(有序、可重复)

List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。

List是列表类型,以线性方式存储对象,自身的方法都与索引有关,个别常用方法如下。

方法返回值功能描述
add(int index, Object obj)void用来向集合中的指定索引位置添加对象,集合的索引位置从0开始,其他对象的索引位置相对向后移一位
set(int index, E element)Object用指定元素替换列表中指定位置的元素,返回以前在指定位置的元素
indexOf(Object obj)int返回列表中对象第一次出现的索引位置,如果集合中不包含该元素则返回-1
lastIndexOf(Object obj)int返回列表中对象最后一次出现的索引位置,如果集合汇总不包含该元素则返回-1
listIterator()ListIterator用来获得一个包含所有对象的ListIterator迭代器

2、Set(无序、不能重复)

Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。

Set接口常用方法如下

方法返回值功能描述
add(Object obj)boolean若集合中尚存在未指定的元素,则添加此元素
addAll(Collection col)boolean将参数集合中所有元素添加到集合的尾部
remove(Object obj)boolean将指定的参数对象移除
clear()void移除此Set中的所有元素
iterator()Iterator返回此Set中的元素上进行迭代的迭代器
size()int返回此Set集合中的所有元素数
isEmpty()boolean如果Set不包含元素,则返回true

3、Map(键值对、键唯一、值不唯一)

Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对 map  集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。

Map接口提供了将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射一个值。Map接口同样提供了clear()、isEmpty()、size()等方法,还有一些常用方法如下:

方法返回值功能描述
put(key k, value v)Object向集合中添加指定的key与value的映射关系
get(Object key)boolean如果存在指定的键对象,则返回该对象对应的值,否则返回null
values()Collection返回该集合中所有值对象形成的Collection集合

 

1. Interface Iterable
迭代器接口,这是Collection类的父接口。实现这个Iterable接口的对象允许使用foreach进行遍历,也就是说,所有的Collection集合对象都具有"foreach可遍历性"。这个Iterable接口只有一个方法: iterator()。它返回一个代表当前集合对象的泛型<T>迭代器,用于之后的遍历操作
1.1 Collection
Collection是最基本的集合接口,一个Collection代表一组Object的集合,这些Object被称作Collection的元素。Collection是一个接口,用以提供规范定义,不能被实例化使用
    1) Set
    Set集合类似于一个罐子,"丢进"Set集合里的多个对象之间没有明显的顺序。Set继承自Collection接口,不能包含有重复元素(记住,这是整个Set类层次的共有属性)。
    Set判断两个对象相同不是使用"=="运算符,而是根据equals方法。也就是说,我们在加入一个新元素的时候,如果这个新元素对象和Set中已有对象进行注意equals比较都返回false,     则Set就会接受这个新元素对象,否则拒绝。
    因为Set的这个制约,在使用Set集合的时候,应该注意两点:1) 为Set集合里的元素的实现类实现一个有效的equals(Object)方法、2) 对Set的构造函数,传入的Collection参数不能包  含重复的元素
        1.1) HashSet
        HashSet是Set接口的典型实现,HashSet使用HASH算法来存储集合中的元素,因此具有良好的存取和查找性能。当向HashSet集合中存入一个元素时,HashSet会调用该对象的     hashCode()方法来得到该对象的hashCode值,然后根据该HashCode值决定该对象在HashSet中的存储位置。
        值得主要的是,HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法的返回值相等
            1.1.1) LinkedHashSet
            LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置,但和HashSet不同的是,它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。       当遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。
            LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,但在迭代访问Set里的全部元素时(遍历)将有很好的性能(链表很适合进行遍历)
        1.2) SortedSet    
        此接口主要用于排序操作,即实现此接口的子类都属于排序的子类
            1.2.1) TreeSet
            TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态
        1.3) EnumSet
        EnumSet是一个专门为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式、或隐式地指定。EnumSet的集合元素也是有序的,     它们以枚举值在Enum类内的定义顺序来决定集合元素的顺序
    2) List
    List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合允许加入重复元素,因为它可以通过索引来访问指定位置的集合元素。List集合默认按元素   的添加顺序设置元素的索引
        2.1) ArrayList
        ArrayList是基于数组实现的List类,它封装了一个动态的增长的、允许再分配的Object[]数组。
        2.2) Vector
        Vector和ArrayList在用法上几乎完全相同,但由于Vector是一个古老的集合,所以Vector提供了一些方法名很长的方法,但随着JDK1.2以后,java提供了系统的集合框架,就将     Vector改为实现List接口,统一归入集合框架体系中
            2.2.1) Stack
            Stack是Vector提供的一个子类,用于模拟"栈"这种数据结构(LIFO后进先出)
        2.3) LinkedList
        implements List<E>, Deque<E>。实现List接口,能对它进行队列操作,即可以根据索引来随机访问集合中的元素。同时它还实现Deque接口,即能将LinkedList当作双端队列     使用。自然也可以被当作"栈来使用"
    3) Queue
    Queue用于模拟"队列"这种数据结构(先进先出 FIFO)。队列的头部保存着队列中存放时间最长的元素,队列的尾部保存着队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,   访问元素(poll)操作会返回队列头部的元素,队列不允许随机访问队列中的元素。结合生活中常见的排队就会很好理解这个概念
        3.1) PriorityQueue
        PriorityQueue并不是一个比较标准的队列实现,PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序,这点从它的类名也可以 看出来
        3.2) Deque
        Deque接口代表一个"双端队列",双端队列可以同时从两端来添加、删除元素,因此Deque的实现类既可以当成队列使用、也可以当成栈使用
            3.2.1) ArrayDeque
            是一个基于数组的双端队列,和ArrayList类似,它们的底层都采用一个动态的、可重分配的Object[]数组来存储集合元素,当集合元素超出该数组的容量时,系统会在底层重新分配一个Object[]数组来存储集合元素
            3.2.2) LinkedList
1.2 Map
Map用于保存具有"映射关系"的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value。key和value都可以是任何引用类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较结果总是返回false。
关于Map,我们要从代码复用的角度去理解,java是先实现了Map,然后通过包装了一个所有value都为null的Map就实现了Set集合
Map的这些实现类和子接口中key集的存储形式和Set集合完全相同(即key不能重复)
Map的这些实现类和子接口中value集的存储形式和List非常类似(即value可以重复、根据索引来查找)
    1) HashMap
    和HashSet集合不能保证元素的顺序一样,HashMap也不能保证key-value对的顺序。并且类似于HashSet判断两个key是否相等的标准也是: 两个key通过equals()方法比较返回true、   同时两个key的hashCode值也必须相等
        1.1) LinkedHashMap
        LinkedHashMap也使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序,与key-value对的插入顺序一致(注意和TreeMap对所有的key-value进行排序进行区分)
    2) Hashtable
    是一个古老的Map实现类
        2.1) Properties 
        Properties对象在处理属性文件时特别方便(windows平台上的.ini文件),Properties类可以把Map对象和属性文件关联起来,从而可以把Map对象中的key-value对写入到属性文     件中,也可以把属性文件中的"属性名-属性值"加载到Map对象中
    3) SortedMap
    正如Set接口派生出SortedSet子接口,SortedSet接口有一个TreeSet实现类一样,Map接口也派生出一个SortedMap子接口,SortedMap接口也有一个TreeMap实现类
        3.1) TreeMap
        TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对(节点)时,需要根据key对节点进行排序。TreeMap可以保证所有的     key-value对处于有序状态。同样,TreeMap也有两种排序方式: 自然排序、定制排序
    4) WeakHashMap
    WeakHashMap与HashMap的用法基本相似。区别在于,HashMap的key保留了对实际对象的"强引用",这意味着只要该HashMap对象不被销毁,该HashMap所引用的对象就不会被垃圾回收。  但WeakHashMap的key只保留了对实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被垃圾回收,当垃  圾回收了该key所对应的实际对象之后,WeakHashMap也可能自动删除这些key所对应的key-value对
    5) IdentityHashMap
    IdentityHashMap的实现机制与HashMap基本相似,在IdentityHashMap中,当且仅当两个key严格相等(key1 == key2)时,IdentityHashMap才认为两个key相等
    6) EnumMap
    EnumMap是一个与枚举类一起使用的Map实现,EnumMap中的所有key都必须是单个枚举类的枚举值。创建EnumMap时必须显式或隐式指定它对应的枚举类。EnumMap根据key的自然顺序  (即枚举值在枚举类中的定义顺序)

 

3.2 常见的几种集合类的对比

   3.2.1 Vector和ArrayList

1,vector是线程同步的,所以它也是线程安全的,而arraylist是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用arraylist效率比较高。

2,如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%。如果在集合中使用数据量比较大的数据,用vector有一定的优势。

3,如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,如果频繁的访问数据,这个时候使用vector和arraylist都可以。而如果移动一个指定位置会导致后面的元素都发生移动,这个时候就应该考虑到使用linkedlist,因为它移动一个指定位置的数据时其它元素不移动。

ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以索引数据快,插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快。

  3.2.2  arraylist和linkedlist

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

3.2.3  HashMap与TreeMap

1、 HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。

2、在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。

两个map中的元素一样,但顺序不一样,导致hashCode()不一样。

同样做测试:

在HashMap中,同样的值的map,顺序不同,equals时,false;

而在treeMap中,同样的值的map,顺序不同,equals时,true,说明,treeMap在equals()时是整理了顺序了的。

3.2.4  HashTable与HashMap

1、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。

2、HashMap允许存在一个为null的key,多个为null的value 。

3、hashtable的key和value都不允许为null。

 

4. 常见的输入输出流

计算机的存储器按用途可以分为主存储器和辅助存储器。

a. 主存储器又称内存,是CPU能直接寻址的存储空间,它的特点是存取速率快。内存一般采用半导体存储单元,包括随机存储器(RAM)、只读存储器(ROM)和高级缓存(Cache)。

b. 辅助存储器又称外存储器(简称外存),就是那些磁盘、硬盘、光盘,也就是你在电脑上看到的C、D、E、F盘。

 

这里写图片描述

根据处理数据类型的不同分为:字符流和字节流

字节流和字符流的区别:

  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

  • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

  • 字节流:一次读入或读出是8位二进制。

  • 字符流:一次读入或读出是16位二进制。

设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。

结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

输入流只能进行读操作,输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。

 

4.1 java 中的文件类 File

在Java语言的java.io包中,由File类提供了描述文件和目录的操作与管理方法。File类不同于输入输出流,它不负责数据的输入输出,而专门用来管理磁盘文件与目录。

File类共提供了三个不同的构造函数,以不同的参数形式灵活地接收文件和目录名信息。构造函数:
1)File (String   pathname)   

     例:File  f1=new File("FileTest1.txt");    //创建文件对象f1,f1 所指的文件是在当前目录下创建的FileTest1.txt
2)File (String  parent  ,  String child)

     例:File f2 = new  File(“D:\\dir1","FileTest2.txt") ;  //  注意:D:\\dir1目录事先必须存在,否则异常
3)File (File    parent  , String child)
     例:File  f4=new File("\\dir3");
          File  f5=new File(f4,"FileTest5.txt");  // 在如果 \\dir3目录不存在使用 f4.mkdir()先创建

一个对应于某磁盘文件或目录的File对象一经创建, 就可以通过调用它的方法来获得文件或目录的属性。    

       1)public boolean exists( )              判断文件或目录是否存在
       2)public boolean isFile( )               判断是文件还是目录 
       3)public boolean isDirectory( )      判断是文件还是目录
       4)public String getName( )            返回文件名或目录名
       5)public String getPath( )              返回文件或目录的路径。
       6)public long length( )                   获取文件的长度 
       7)public String[ ] list ( )                  将目录中所有文件名保存在字符串数组中返回。 

File类中还定义了一些对文件或目录进行管理、操作的方法,常用的方法有:


       1) public boolean renameTo( File newFile );         重命名文件
       2) public void delete( );                                         删除文件
       3)  public boolean mkdir( );                                   创建目录

 

4.2 字节流

4.2.1  字节流InputStream

InputStream 为字节输入流,它本身为一个抽象类,必须依靠其子类实现各种功能,此抽象类是表示字节输入流的所有类的超类。 继承自InputStream  的流都是向程序中输入数据的,且数据单位为字节(8bit);

InputStream是输入字节数据用的类,所以InputStream类提供了3种重载的read方法.

Inputstream类中的常用方法: 
  (1) public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。
  (2) public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的 
  (3) public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。 
  (4) public int available( ):返回输入流中可以读取的字节数。注意:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用, 
  (5) public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取 
  (6) public int close( ) :我们在使用完后,必须对我们打开的流进行关闭. 

         主要的子类:

        

         1) FileInputStream把一个文件作为InputStream,实现对文件的读取操作     
    2) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用 
    3) StringBufferInputStream:把一个String对象作为InputStream 
    4) PipedInputStream:实现了pipe的概念,主要在线程中使用 
    5) SequenceInputStream:把多个InputStream合并为一个InputStream 

例子:使用 FileInputStream 读取文件


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class A1 {

	/**
	 * 读取指定文件的内容
	 * @param filePath : 文件的路径
	 * @return  返回的结果
	 */
	public String readFile( String filePath ){
		FileInputStream fis=null;
		String result = "" ;
		try {
			// 根据path路径实例化一个输入流的对象
			fis  = new FileInputStream( filePath );

			//2. 返回这个输入流中可以被读的剩下的bytes字节的估计值;
			int size =  fis.available() ;
			//3. 根据输入流中的字节数创建byte数组;
			byte[] array = new byte[size];
			//4.把数据读取到数组中;
			fis.read( array ) ; 

			//5.根据获取到的Byte数组新建一个字符串,然后输出;
			result = new String(array);	

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch (IOException e) {
			e.printStackTrace();
		}finally{
			if ( fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return result ;
	}

	public static void main(String[] args) {
		A1 a1 = new A1();
	
		//电脑d盘中的abc.txt 文档
		String filePath = "D:/abc.txt" ;
		String reslut = a1.readFile( filePath ) ;
        System.out.println( reslut ); 
	}
}

 

4.2.2  字节流OutputStream

OutputStream提供了3个write方法来做数据的输出,这个是和InputStream是相对应的。 


  1. public void write(byte b[ ]):将参数b中的字节写到输出流。 
  2. public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。 
  3. public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。 
  4. public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。 
  5. public void close( ) : 关闭输出流并释放与流相关的系统资源。 

 

       主要的子类:

        

      1) ByteArrayOutputStream:把信息存入内存中的一个缓冲区中 
      2) FileOutputStream:把信息存入文件中 
      3) PipedOutputStream:实现了pipe的概念,主要在线程中使用 
      4) SequenceOutputStream:把多个OutStream合并为一个OutStream 

缓冲输入输出流:

计算机访问外部设备非常耗时。访问外存的频率越高,造成CPU闲置的概率就越大。为了减少访问外存的次数,应该在一次对外设的访问中,读写更多的数据。为此,除了程序和流节点间交换数据必需的读写机制外,还应该增加缓冲机制。缓冲流就是每一个数据流分配一个缓冲区,一个缓冲区就是一个临时存储数据的内存。这样可以减少访问硬盘的次数,提高传输效率

BufferedInputStream:当向缓冲流写入数据时候,数据先写到缓冲区,待缓冲区写满后,系统一次性将数据发送给输出设备。

BufferedOutputStream :当从向缓冲流读取数据时候,系统先从缓冲区读出数据,待缓冲区为空时,系统再从输入设备读取数据到缓冲区。

例子:

import java.io.*;
 
public class ReadWriteToFile {
	public static void main(String args[]) throws IOException {
		InputStreamReader sin = new InputStreamReader(System.in);
		BufferedReader bin = new BufferedReader(sin);

		FileWriter out = new FileWriter("myfile.txt");
		BufferedWriter bout = new BufferedWriter(out);
		String s;
		while ((s = bin.readLine()).length() > 0) {
			bout.write(s, 0, s.length()); // 从缓冲区将字符串s从offset开始,len长度的字符串写到某处。
		}
 
	}
}

4.3 字符流Writer/Reader

  Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。

 

4.3.1 字符流 Reader

    用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

      主要方法:

      (1)  public int read() throws IOException; //读取一个字符,返回值为读取的字符 

  (2)  public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/ 
  (3)  public abstract int read(char cbuf[],int off,int len) throws IOException; 
  /*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/ 

       

        1) FileReader :与FileInputStream对应  
           主要用来读取字符文件,使用缺省的字符编码,有三种构造函数: 
      (1)将文件名作为字符串 :FileReader f=new FileReader(“c:/temp.txt”); 
      (2)构造函数将File对象作为其参数。 
              File f=new file(“c:/temp.txt”); 
              FileReader f1=new FileReader(f); 
     (3)  构造函数将FileDescriptor对象作为参数 
            FileDescriptor() fd=new FileDescriptor() 
            FileReader f2=new FileReader(fd); 
               (1) 用指定字符数组作为参数:CharArrayReader(char[]) 
               (2) 将字符数组作为输入流:CharArrayReader(char[], int, int) 
          读取字符串,构造函数如下: public StringReader(String s); 
        2) CharArrayReader:与ByteArrayInputStream对应  
  3) StringReader : 与StringBufferInputStream对应 
  4) InputStreamReader 
        从输入流读取字节,在将它们转换成字符:Public inputstreamReader(inputstream is); 
  5) FilterReader: 允许过滤字符流 
        protected filterReader(Reader r); 
  6) BufferReader :接受Reader对象作为参数,并对其添加字符缓冲器,使用readline()方法可以读取一行。 
     Public BufferReader(Reader r); 

4.3.1 字符流 Writer 

     写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

      主要方法:

  (1)  public void write(int c) throws IOException; //将整型值c的低16位写入输出流 
  (2)  public void write(char cbuf[]) throws IOException; //将字符数组cbuf[]写入输出流 
  (3)  public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流 
  (4)  public void write(String str) throws IOException; //将字符串str中的字符写入输出流 
  (5)  public void write(String str,int off,int len) throws IOException; //将字符串str 中从索引off开始处的len个字符写入输出流 
  (6)  flush( ) //刷空输出流,并输出所有被缓存的字节。 
  (7) close()    关闭流 public abstract void close() throws IOException

其子类如下:

    

      1) FileWrite: 与FileOutputStream对应  
  将字符类型数据写入文件,使用缺省字符编码和缓冲器大小。 
  Public FileWrite(file f); 
  2)  chararrayWrite:与ByteArrayOutputStream对应 ,将字符缓冲器用作输出。 
      Public CharArrayWrite(); 
  3) PrintWrite:生成格式化输出 
      public PrintWriter(outputstream os); 
  4) filterWriter:用于写入过滤字符流 
      protected FilterWriter(Writer w); 
  5) PipedWriter:与PipedOutputStream对应   

      6) StringWriter:无与之对应的以字节为导向的stream  

4. 4 如何选择IO 流:

1)确定是 输入还是输出

              输入流: InputStream Reader
              输出流: OutputStream Writer

2)明确操作的数据对象是否是纯文本

             是: 字符流Reader,Writer
             否: 字节流InputStream,OutputStream

3)明确具体的设备

硬盘文件:

             读取:FileInputStream,, FileReader, 

              写入:FileOutputStream,FileWriter
内存用数组:

                  byte[]:ByteArrayInputStream, ByteArrayOutputStream
                  是char[]:CharArrayReader, CharArrayWriter

键盘:

                 用System.in(是一个InputStream对象)读取,用System.out(是一个OutoutStream对象)打印

4)是否需要缓冲提高效率

       加上Buffered:BufferedInputStream, BufferedOuputStream, BuffereaReader, BufferedWriter

 

项目推荐:

2000多G的计算机各行业电子资源分享(持续更新)

2020年微信小程序全栈项目之喵喵交友【附课件和源码】

Spring Boot开发小而美的个人博客【附课件和源码】

Java微服务实战296集大型视频-谷粒商城【附代码和课件】

Java开发微服务畅购商城实战【全357集大项目】-附代码和课件

最全最详细数据结构与算法视频-【附课件和源码】

在这里插入图片描述

 

 

 

 

 

 

 

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java中字符串编码转换的工具类可以通过使用Java自带的Charset类和String类的getBytes()方法来实现。下面是一个示例的工具类: ```java import java.nio.charset.Charset; public class EncodingUtils { // 将指定编码的字符串转换为默认编码的字符串 public static String convertToDefaultEncoding(String str, String sourceEncoding) { byte[] bytes = str.getBytes(Charset.forName(sourceEncoding)); return new String(bytes); } // 将默认编码的字符串转换为指定编码的字符串 public static String convertToEncoding(String str, String targetEncoding) { byte[] bytes = str.getBytes(); return new String(bytes, Charset.forName(targetEncoding)); } } ``` 使用示例: ```java public class Main { public static void main(String[] args) { String str1 = "中文字符串"; // 将UTF-8编码的字符串转换为默认编码的字符串 String defaultEncodingStr = EncodingUtils.convertToDefaultEncoding(str1, "UTF-8"); System.out.println("Default Encoding: " + defaultEncodingStr); // 将默认编码的字符串转换为GBK编码的字符串 String targetEncodingStr = EncodingUtils.convertToEncoding(defaultEncodingStr, "GBK"); System.out.println("Target Encoding: " + targetEncodingStr); } } ``` 在上述示例中,工具类`EncodingUtils`提供了两个静态方法。`convertToDefaultEncoding()`方法将指定编码的字符串转换为默认编码的字符串,而`convertToEncoding()`方法将默认编码的字符串转换为指定编码的字符串。 ### 回答2: Java字符串编码转换工具类是一种用于处理字符串编码转换的工具类,它可以将字符串从一种字符编码转换为另一种字符编码。在Java中,字符串的编码可以使用标准的UTF-8、UTF-16、ISO-8859-1等编码方式。 这个工具类通常提供以下几种方法: 1. `toUTF8(String str)`:将字符串从其他编码转换为UTF-8编码。 2. `fromUTF8(String str)`:将UTF-8编码的字符串转换为其他编码。 3. `toISO88591(String str)`:将字符串从其他编码转换为ISO-8859-1编码。 4. `fromISO88591(String str)`:将ISO-8859-1编码的字符串转换为其他编码。 使用这个工具类可以避免在转换编码时出现乱码或者字符串不可识别的问题。例如,当我们从外部资源读取数据时,如果字符串的编码与程序默认字符编码不一致,就会导致乱码,这时可以使用这个工具类进行编码转换。 在实现这个工具类时,可以使用Java提供的相关类库,如`java.nio.charset.Charset`、`java.nio.CharBuffer`等类来进行编码转换操作。首先,通过指定源编码和目标编码,创建`Charset`对象;然后,使用`encode`方法将源字符串编码成字节序列,并使用目标`Charset`对象的`decode`方法将字节序列解码成目标编码的字符串。 使用这个工具类时,需要注意的是源编码和目标编码必须是支持的字符编码,否则会抛出编码不支持的异常。此外,还应该注意对输入的异常情况进行处理,例如空字符串或空指针异常,以确保程序的健壮性。 总之,Java字符串编码转换工具类是一个方便实用的工具,可以帮助我们在不同编码间进行转换,避免乱码的问题,提高程序的稳定性和可靠性。 ### 回答3: Java提供了许多内置的工具类来方便字符串编码转换。其中最常用的工具类是`java.nio.charset.Charset`和`java.lang.String`类。 首先,`Charset`类包含了许多常见的字符集,比如UTF-8、GBK、ISO-8859-1等。我们可以使用`Charset.forName(String charsetName)`方法来获取指定字符集的一个实例。 接下来,`String`类提供了几个方法来进行字符串编码转换。其中最常用的是`getBytes(String charsetName)`方法,它将字符串按照指定的字符集转换为字节数组。例如,如果我们想将字符串转换为UTF-8编码的字节数组,可以使用`getBytes("UTF-8")`方法。 除了将字符串转换为字节数组,`String`类还提供了`getBytes()`方法,它将字符串按照默认的字符集转换为字节数组。默认的字符集可以通过调用`Charset.defaultCharset()`方法获取。 另外,如果我们想将字节数组转换为字符串,可以使用`String`类的构造方法`String(byte[] bytes, Charset charset)`。该构造方法将字节数组按照指定的字符集转换为字符串。 除了上述的方法,还有一些其他的工具类可以辅助字符串编码转换。比如,`java.io.InputStreamReader`和`java.io.OutputStreamWriter`类提供了将字节流与字符流进行转换的功能。 总结来说,Java提供了丰富的工具类来进行字符串编码转换。我们可以通过`Charset`类获取指定字符集的实例,通过`String`类的相关方法来进行字符串与字节数组之间的转换。另外,还可以使用`java.io.InputStreamReader`和`java.io.OutputStreamWriter`类进行字节流与字符流之间的转换。这些工具类的使用可以方便地实现字符串编码转换的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值