Java 学习笔记 基础类

集合

一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储。另一方面,使用 Array 存储对象方面具有一些弊端,而 Java 集合就像一种容器,可以动态地把多个对象的引用放入容器中。

Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。

Java 集合可分为 CollectionMap 两种体系。

  • Collection 接口:
    • Set:元素无序、不可重复的集合 —类似高中的“集合”
    • List:元素有序,可重复的集合 —“动态”数组
  • Map 接口:具有映射关系 key-value 对的集合 —类似于高中的“函数” y = f(x) (x1,y1) (x2,y2)

框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|---Collection(接口)
|---List(接口)
|---ArrayList(主要的实现类)
|---LinkedList(更适用于频繁的插入、删除操作)
|---Vector(古老的实现类、线程安全的,但效率要低于ArrayList)
|---Set(接口)
|---HashSet(主要的实现类)
|---LinkedHashSet
|---TreeSet
|---Map(接口)
|---HashMap
|---LinkedHashMap
|---TreeMap
|---Hashtable
|---Properties

Collection 接口

Collection 接口是 List SetQueue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 ListQueue 集合。

JDK 不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List)实现。

Collection 接口中的方法:

  • add(Object obj) # boolean,添加元素 obj 至集合中
  • addAll(Collection coll) # boolean,添加coll中所有元素至该集合
  • size() # int,返回元素个数
  • clear() # void,移除集合中的所有元素
  • isEmpty() # boolean,判断集合是否为空
  • remove(Object obj) # boolean,从此集合中移除指定元素,如果存在的话
  • removeAll(Collection coll) # boolean,移除coll中包含在指定集合中的所有元素
  • retainAll(Collection coll) # boolean,求集合与coll的交集
  • equals(Object obj) # boolean,比较集合与指定对象是否相等
  • contains(Object obj) # boolean,判断集合是否包含指定元素
  • containsAll(Collection coll),hashCode() # boolean,判断集合是否包含coll中所有元素
  • iterator() # 迭代器
  • toArray() # 与数组相互转化

List 接口与 HashSet LinkedHashSet TreeSet

List 集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。List 容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。

List 接口存储有序的,可以重复的元素,相当于“动态”数组。

Collection 的基础上,List 新增的方法有:

  • 删除 remove(int index)
  • 修改 set(int index, Object obj)
  • 获取 get(int index)
  • 插入 add(int index, Object obj)

添加进 List 集合中的元素(或对象)所在的类一定要重写 equals() 方法

ArrayListList 主要的实现类; LinkedList 更适用于频繁的插入、删除操作; Vector 是古老的实现类、线程安全的,但效率要低于 ArrayList

Set 接口与 HashSet LinkedHashSet TreeSet

Set 接口存储无序的,不可重复的元素。相当于高中的“集合”概念。

Set 有如下特点:

  1. Set 使用的方法基本上都是 Collection 接口下定义的。
  2. 添加进 Set 集合中的元素所在的类一定要重写 equals()hashCode()。要求重写 equals()hashCode() 方法保持一致。
  3. 无序性:无序性!= 随机性。真正的无序性,指的是元素在底层存储的位置是无序的。
  4. 不可重复性:当向Set中添加进相同的元素的时候,后面的这个不能添加进去。

HashSetSet 主要的实现类; LinkedHashSetHashSet 的子类,当我们遍历集合元素时,是按照添加进去的顺序实现的,频繁的遍历,较少的添加、插入操作建议选择此类; TreeSet 可以按照添加进集合中的元素的指定属性进行排序。

两种排序方式:

  1. 自然排序:
    ① 要求添加进 TreeSet 中的元素所在的类 implements Comparable 接口
    ② 重写 compareTo(Object obj),在此方法内指明按照元素的哪个属性进行排序
    ③ 向 TreeSet 中添加元素即可。若不实现此接口,会报运行时异常
  2. 定制排序:
    ① 创建一个实现 Comparator 接口的实现类的对象。在实现类中重写 Comparator 的 compare(Object o1,Object o2) 方法
    ② 在此 compare() 方法中指明按照元素所在类的哪个属性进行排序
    ③ 将此实现 Comparator 接口的实现类的对象作为形参传递给 TreeSet 的构造器中
    ④ 向 TreeSet 中添加元素即可。若不实现此接口,会报运行时异常
  3. 注:要求重写的compareTo()或者compare()方法与equals()和hashCode()方法保持一致。

Map 接口

Map 接口用于存储“键-值”对的数据,相当于高中的“函数 y = f(x)” (x1,y1) (x2,y2)。 Map 中的 keyvalue 都可以是任何引用类型的数据。

Map 中的 keySet 来存放,不允许重复,即同一个 Map 对象所对应的类,须重写 hashCode()equals() 方法。value 可以重复的,使用 Collection 来存放的。一个 key-value 对构成一个 entry(Map.Entry)entry 使用 Set 来存放。

Map 接口中的方法:

  • 添加、删除操作:
    Object put(Object key, Object value)
    Object remove(Object key)
    void putAll(Map t)
    void clear()
  • 元视图操作的方法:
    Set keySet()
    Collection values()
    Set entrySet()
  • 元素查询的操作:
    Object get(Object key)
    boolean containsKey(Object key)
    boolean containsValue(Object value)
    int size()
    boolean isEmpty()
    boolean equals(Object obj)

HashMap 与 LinkedHashMap

HashMap 是 Map 接口使用频率最高的实现类。允许使用 null 键和 null 值,与 HashSet 一样,不保证映射的顺序。

HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。 HashMap 判断两个 value 相等的标准是:两个 value 通过 equals() 方法返回 true。

LinkedHashMapHashMap 的子类。与 LinkedHashSet 类似, LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致。所以 LinkedHashMap 可以按照添加进 Map 的顺序实现遍历。

TreeMap

TreeMap 存储 Key-Value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。

TreeMap 的 Key 的排序:

  • 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
  • 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 MapKey 实现 Comparable 接口

TreeMap 判断两个 key 相等的标准:两个 key 通过 compareTo() 方法或者 compare() 方法返回 0 。若使用自定义类作为 TreeMapkey ,所属类需要重写 equals()hashCode() 方法,且 equals() 方法返回 true 时, compareTo() 方法应返回 0

Hashtable 与 Properties

Hashtable 是个古老的 Map 实现类,线程安全。与 HashMap 不同, Hashtable 不允许使用 null 作为 keyvalue 。 与 HashMap 一样, Hashtable 也不能保证其中 Key-Value 对的顺序,且判断两个 keyvalue 相等的标准与 hashMap 一致。

Properties 类是 Hashtable 的子类,该对象用于处理属性文件。由于属性文件里的 keyvalue 都是字符串类型,所以 Properties 里的 keyvalue 都是字符串类型。存取数据时,建议使用 setProperty(String key,String value) 方法和 getProperty(String key) 方法。

集合的遍历与 Iterator 接口

主要作用是用来遍历集合中的元素。

List 遍历的代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("AA");
coll.add("BB")

// 方法一:增强for循环
for(Object i: coll){
System.out.println(i);
}

// 方法二:使用迭代器
Iterator i = coll.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}

Map 遍历的代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Map map = new HashMap();
map.put("aa", 123);
map.put("BB", 45);
map.put(123, "CC");
map.put(null, null);

//1. 遍历key集
Set set = map.keySet();
for (Object obj : set) {
System.out.println(obj);
}
//2. 遍历key集
Collection values = map.values();
for (Object obj : values) {
System.out.println(obj);
}
//3. 遍历key - value 对
//方式一:
Set set1 = map.keySet();
for(Object obj: set1) {
System.out.println(obj + "----->" + map.get(obj));
}
//方式二
Set set2 = map.entrySet();
for(Object obj: set2) {
Map.Entry entry = (Map.Entry)obj;
System.out.println(entry);
}

Collections 工具类

操作 CollectionMap 的工具类,大部分为 static 的方法。

排序操作

  • reverse(List):反转 List 中元素的顺序
  • shuffle(List):对 List 集合元素进行随机排序
  • sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
  • sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
  • swap(List,int,int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

查找、替换

  • Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
  • Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
  • Object min(Collection)
  • Object min(Collection,Comparator)
  • int frequency(Collection,Object):返回指定集合中指定元素的出现次数
  • void copy(List dest,List src):将src中的内容复制到dest中
  • boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值

同步控制

Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。

  • static Collection synchronizedCollection(Collection c)
    返回指定 collection 支持的同步(线程安全的)collection。
  • static List synchronizedList(List list)
    返回指定列表支持的同步(线程安全的)列表。
  • static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
    返回由指定映射支持的同步(线程安全的)映射。
  • static Set synchronizedSet(Set s)
    返回指定 set 支持的同步(线程安全的)set。
  • static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
    返回指定有序映射支持的同步(线程安全的)有序映射。
  • static SortedSet synchronizedSortedSet(SortedSet s)
    返回指定有序 set 支持的同步(线程安全的)有序 set。

Java 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Test
public void testCollections1(){
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
System.out.println(list);
Collections.reverse(list); //反转
System.out.println(list);
Collections.shuffle(list); //随机洗牌
System.out.println(list);
Collections.sort(list); //排序
System.out.println(list);
Collections.swap(list, 0, 2); //交换
System.out.println(list);
}

@Test
public void testCollections2(){
List list = new ArrayList();
list.add(123);
list.add(456);
list.add(12);
list.add(78);
list.add(456);
Object obj = Collections.max(list); // 求最大值
System.out.println(obj);
int count = Collections.frequency(list, 456); // 求456频率
System.out.println(count);

List list_new = Arrays.asList(new Object[list.size()]);
Collections.copy(list_new, list); // 复制
System.out.println(list_new);
}

Properties 的使用

占位

泛型

枚举和注解

枚举

枚举类:类的对象是有限个的,确定的。

自定义枚举类

步骤:

  1. 私有化类的构造器,保证不能在类的外部创建其对象
  2. 在类的内部创建枚举类的实例。声明为:public static final
  3. 若类有属性,那么属性声明为:private final 。此属性在构造器中赋值。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class TestSeason {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
spring.show();
System.out.println(spring.getSeasonName());
}
}
//枚举类
class Season{
//1. 提供类的属性,什么为private final
private final String seasonName;
private final String seasonDesc;
//2. 声明为final的属性,在构造器中初始化
private Season(String seasonName, String seasonDesc) {
super();
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//3. 通过公共的方法来调用属性
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//4. 创建枚举类的对象
public static final Season SPRING = new Season("spring", "春暖花开");
public static final Season SUMMER = new Season("summer", "夏日炎炎");
public static final Season AUTUMN = new Season("autumn", "秋高气爽");
public static final Season WINTER = new Season("winter", "白雪皑皑");
@Override
public String toString() {
return "Season [seasonName=" + seasonName + ", seasonDesc=" + seasonDesc + "]";
}
public void show() {
System.out.println("这是一个季节");
}
}

枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰。上述代码中类的属性和构造器都命名为 private 说明,枚举类的属性和构造器不能在外部访问,只能通过在类内部创建对象。

关键字 enum 定义枚举类

其中常用的方法:

  • values()
  • valueOf(String name);

枚举类如何实现接口:

  • 让类实现此接口,类的对象共享同一套接口的抽象方法的实现。
  • 让类的每一个对象都去实现接口的抽象方法,进而通过类的对象调用被重写的抽象方法时,执行的效果不同

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class TestSeason {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
spring.show();
System.out.println(spring.getSeasonName());
System.out.println();
//1. values()
Season[] seasons = Season.values();
for(int i=0; i < seasons.length; i++)
System.out.println(seasons[i]);
//2. valueOf(String name):要求传入的形参name是枚举类对象的名字
String str = "SPRING";
Season sea = Season.valueOf(str);
System.out.println(sea);
}
}
//接口
interface Info{
void show();
}
//枚举类
enum Season implements Info{
//1. 必须在开头声明,每个枚举类中show方法不同
SPRING("spring", "春暖花开"){
public void show(){
System.out.println("春天在哪里?");
}
},
SUMMER("summer", "夏日炎炎"){
public void show(){
System.out.println("生如夏花");
}
},
AUTUMN("autumn", "秋高气爽"){
public void show(){
System.out.println("秋天是用来分手的季节");
}
},
WINTER("winter", "白雪皑皑"){
public void show(){
System.out.println("冬天里的一把火");
}
};
//2. 定义枚举类的属性和构造器
private final String seasonName;
private final String seasonDesc;
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//3. 通过公共的方法来调用属性
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}

@Override
public String toString() {
return "Season [seasonName=" + seasonName + ", seasonDesc=" + seasonDesc + "]";
}
public void show() {
System.out.println("这是一个季节");
}
}

注解

使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素。

JDK提供的常用的三个注解

  • @Override: 限定重写父类方法, 该注释只能用于方法
  • @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
  • @SuppressWarnings: 抑制编译器警告

自定义注解

SuppressWarnings 为例进行创建即可

元注解

JDK 的元 Annotation 用于修饰其他 Annotation 定义,即元注解是修饰注解的注解。

JDK5.0提供了专门在注解上的注解类型,分别是:

  • Retention
  • Target
  • Documented
  • Inherited

@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值:

  • RetentionPolicy.SOURCE :编译器直接丢弃这种策略的注释
  • RetentionPolicy.CLASS :编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。 这是默认值
  • RetentionPolicy.RUNTIME :编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注释. 程序可以通过反射获取该注释

@Target :用于修饰 Annotation 定义,用于指定被修饰的 Annotation 能用于修饰哪些程序元素。 @Target 也包含一个名为 value 的成员变量。

@Documented :用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档。定义为 Documented 的注解必须设置 Retention 值为 RUNTIME

@Inherited :被它修饰的 Annotation 将具有继承性。如果某个类使用了被 @Inherited 修饰的 Annotation,则其子类将自动具有该注解实际应用中,使用较少。

IO 流

File 类

java.io.File 类:文件和目录路径名的抽象表示形式,与平台无关。File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。File 对象可以作为参数传递给流的构造函数。

java.io.File 类的特点:

  • File 既可以表示一个文件(.doc .xls .mp3 .avi .jpg .dat),也可以表示一个文件目录!
  • File 类的对象是与平台无关的。
  • File 类针对于文件或文件目录,只能进行新建、删除、重命名、上层目录等等的操作。如果涉及到访问文件的内容, File 是无能为力的,只能使用IO流下提供的相应的输入输出流来实现。
  • 常把 File 类的对象作为形参传递给相应的输入输出流的构造器中!

File 类的构造

  • public File(String pathname)
    以 pathname 为路径创建 File 对象,可以是绝对路径或者相对路径,如果 pathname 是相对路径,则默认的当前路径在系统属性 user.dir 中存储。
  • public File(String parent,String child)
    以 parent 为父路径,child 为子路径创建 File 对象。

File 的静态属性 String separator 存储了当前系统的路径分隔符。在 UNIX 中,此字段为‘/’,在 Windows 中,为‘\\’。

代码示例:

1
2
3
4
5
6
// 绝对路径方式,包括盘符在内的完整文件路径
File file1 = new File("d:/io/helloworld.txt");
// 相对路径方式,在当前文件目录下的文件路径
File file1 = new File("hello.txt");
// 文件夹路径,不包含文件名
File file1 = new File("d:\\io\\il1");

Flie 类常用方法

访问文件名

  • getName()
  • getPath()
  • getAbsoluteFile()
  • getAbsolutePath()
  • getParent()
  • renameTo(File newName)

文件检测

  • exists()
  • canWrite()
  • canRead()
  • isFile()
  • isDirectory()

获取常规文件信息

  • lastModified()
  • length()

文件操作相关

  • createNewFile()
  • delete()

目录操作相关

  • mkDir()
  • mkDirs()
  • list()
  • listFiles()

IO 流原理

IO 流用来处理设备之间的数据传输。Java 程序中,对于数据的输入/输出操作以”流(stream)” 的方式进行。java.io 包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。

输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中

IO 流的划分

  • 按照流的流向的不同:输入流输出流 (站位于程序的角度)
  • 按照流中的数据单位的不同:字节流字符流(纯文本文件使用字符流 ,除此之外使用字节流)
  • 按照流的角色的不同:节点流处理流(流直接作用于文件上是节点流(4个),除此之外都是处理流)

IO 流的体系

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象类型 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
访问字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
对换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream
FilterInputStream FilterOutputStream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

注:

  1. 从硬盘中读入一个文件,要求此文件一定得存在。若不存在,报 FileNotFoundException的异常;
  2. 从程序中输出一个文件到硬盘,此文件可以不存在。若不存在,就创建一个实现输出。若存在,则将已存在的文件覆盖;
  3. 真正开发时,就使用缓冲流来代替节点流;
  4. 主要最后要关闭相应的流。先关闭输出流,再关闭输入流。将此操作放入 finally;

IO 流的应用

FileInputStream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//从硬盘存在的一个文件中,读取内容到程序中使用FileInputStream
@Test
public void testFileInputStream() {
//2. 创建一个FileInputStream类的对象
FileInputStream fis = null;
try {
//1. 创建一个File类的对象
File file = new File("hello.txt");
fis = new FileInputStream(file);
//3. 调用FileInputStream的方法,实现file文件的读取
byte[] b = new byte[20];//读取到的数据写入数组
int len;// 每次读入到byte中的字节的长度
while((len = fis.read(b)) != -1) {
// for(int i=0; i < len; i++)
// System.out.print((char)b[i]);
String str = new String(b, 0, len);
System.out.print(str);
}
}catch (IOException e) {
e.printStackTrace();
}finally {
if(fis != null) {
//4. 关闭相应的流
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

FileOutputStream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void testFileOutputStream() {
//1. 创建一个File对象,表明要写入的文件位置。
//输出的物理文件可以不存在,当执行过程中,若不存在,会自动的创建。若存在,会将原有文件覆盖
File file = new File("hello2.txt");
//2. 创建一个FileOutputStream的对象,将file的对象作为形参传递给FileOutputStream的构造器中
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
//3. 写入操作
fos.write(new String("I love China I love the World!").getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
//4. 关闭输出流
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

FileReader 与 FileWriter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Test
public void testFileReaderWriter() {
//1.输入流对应的文件src一定要存在,否则抛异常。输出流对应的文件dest可以不存在,执行过程中会自动创建
FileReader fr = null;
FileWriter fw = null;
try {
//2. 创建File对象
File src = new File("dbcp.txt");
File dest = new File("dbcp1.txt");
//3. 创建输入与输出字符流对象
fr = new FileReader(src);
fw = new FileWriter(dest);
char[] c = new char[24];
int len;
while((len = fr.read(c)) != -1) {
fw.write(c, 0, len);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
if(fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

缓冲流

为了提高数据读写的速度,Java API 提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组。

缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。

对于输出的缓冲流,写出的数据会先在内存中缓存,使用 flush() 将会使内存中的数据立刻写出。

对应于节点流,缓冲流有如下4种:

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • Buffered]Writer

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.junit.Test;

public class TestBuffered {
// 使用 BufferedInputStream 和 BufferedOutputStream 实现非文本文件的复制
@ Test
public void testBufferedInputOutputStream() {
// 3. 将创建的节点流的对象作为形参传递给缓冲流的构造器中
BufferedInputStream bis = null;
BufferedOutputStream bos= null;
try {
// 1. 提供读入、写出的文件
File file_in = new File("angel.png");
File file_out = new File("angel_copy.png");
// 2. 创建相应的节点流,FileInputStream、FileOutputStream
FileInputStream fis = new FileInputStream(file_in);
FileOutputStream fos = new FileOutputStream(file_out);
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
// 4. 具体的实现文件复制的操作
byte[] b = new byte[1024];
int len;
while((len = bis.read(b)) != -1) {
bos.write(b, 0, len);
bos.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5. 关闭相应的流
if (bos != null)
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
if (bis != null)
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

缓冲流实现文件的复制操作,较节点流速度要快。

转换流

转换流提供了在字节流和字符流之间的转换,Java API 提供了两个转换流:

  • InputStreamReader
    输入时,实现字节流到字符流的转换,提高操作的效率(前提是,数据是文本文件)===>解码:字节数组—>字符串
  • OutputStreamWriter
    输出时,实现字符流到字节流的转换。 ===>编码:字符串—->字节数组

字节流中的数据都是字符时,转成字符流操作更高效。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class TestOtherStream {
@ Test
public void test() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 解码
File file = new File("dbcp.txt");
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis, "GBK");
br = new BufferedReader(isr);
// 编码
File file1 = new File("dbcp2.txt");
FileOutputStream fos = new FileOutputStream(file1);
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
bw = new BufferedWriter(osw);
String str;
while ((str = br.readLine()) != null) {
bw.write(str);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bw != null)
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
if (br != null)
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

标准的输入输出流

System.inSystem.out 分别代表了系统标准的输入和输出设备。默认输入设备是键盘,输出设备是显示器。System.in 的类型是 InputStreamSystem.out 的类型是 PrintStream,其是 OutputStream 的子类 FilterOutputStream 的子类。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void systemIn() {
BufferedReader br = null;
try {
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String str;
while (true) {
System.out.println("请输入字符串: ");
str = br.readLine();
if (str.equals("e") || str.equals("exit")) {
break;
}
String res = str.toUpperCase();
System.out.println(res);
}
} catch (IOException e) {
e.printStackTrace();
}
if (br != null)
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}

打印流

分类:

  • PrintStream(字节打印流)
  • PrintWriter(字符打印流)

特点:

  • 提供了一系列重载的 print 和 println 方法,用于多种数据类型的输出
  • PrintStream 和 PrintWriter 的输出不会抛出异常
  • PrintStream 和 PrintWriter 有自动 flush 功能
  • System.out 返回的是 PrintStream 的实例
  • 可以使用 System.setOut(PrintStream p)重新设置一下输出的位置。

声明方式:

PrintStream p = new PrintStream(new FileOutputStream(“hello.txt”),true);

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void printStreamWriter() {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("print.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
PrintStream ps = new PrintStream(fos, true);
if (ps != null) { // 把标准输出流(控制台输出)改成文件
System.setOut(ps);}
for (int i = 0; i <= 255; i++) { //输出ASCII字符
System.out.print((char)i);
if (i % 50 == 0) { //每50个数据一行
System.out.println(); // 换行
} }
ps.close();
}

数据流

为了方便地操作 Java 语言的基本数据类型的数据,可以使用数据流。
数据流有两个类:(用于读取和写出基本数据类型的数据)

  • DataInputStream
  • DataOutputStream

分别“套接”在 InputStreamOutputStream 节点流上

DataInputStream 中的方法

  • boolean readBoolean()
  • char readChar()
  • double readDouble()
  • long readLong()
  • String readUTF()
  • byte readByte()
  • float readFloat()
  • short readShort()
  • int readInt()
  • void readFully(byte[] b)

DataOutputStream 中的方法

  • 将上述的方法的 read 改为相应的 write 即可。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void dataStream() {
DataOutputStream dos = null;
try {
FileOutputStream fos = new FileOutputStream("data.txt");
dos = new DataOutputStream(fos);

dos.writeUTF("我爱你,而你却不知道!"); //写UTF字符串
dos.writeBoolean(true); //写入布尔值
dos.writeLong(1432522344); //写入长整数
System.out.println("写文件成功!");
} catch (IOException e) {
e.printStackTrace();
} finally { //关闭流对象
if (dos != null) {
// 关闭过滤流时,会自动关闭它包装的底层节点流
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

对象流

用于存储和读取对象的处理流。它的强大之处就是可以把 Java 中的对象写入到数据源中,也能把对象从数据源中还原回来。

序列化 (Serialize) :用 ObjectOutputStream 类将一个 Java 对象写入 IO 流中
反序列化 (Deserialize) :用 ObjectInputStream 类从 IO 流中恢复该 Java 对象

对象的序列化

对象序列化机制允许把内存中的 Java 对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的 Java 对象。

序列化的好处在于可将任何实现了 Serializable 接口的对象转化为字节数据,使其在保存和传输时可被还原。

序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 RMIJavaEE 的基础。因此序列化机制是 JavaEE 平台的基础。

如果需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:

  • Serializable
  • Externalizable

凡是实现 Serializable 接口的类都有一个表示序列化版本标识符的静态变量:

  • private static final long serialVersionUID;
  • serialVersionUID 用来表明类的不同版本间的兼容性
  • 如果类没有显示定义这个静态变量,它的值是 Java 运行时环境根据类的内部细节自动生成的。若类的源代码作了修改,serialVersionUID 可能发生变化。故建议,显示声明

显示定义 serialVersionUID 的用途

  • 希望类的不同版本对序列化兼容,因此需确保类的不同版本具有相同的 serialVersionUID
  • 不希望类的不同版本对序列化兼容,因此需确保类的不同版本具有不同的 serialVersionUID

实现序列化机制的对象对应的类的要求:

  • 要求类要实现 Serializable 接口
  • 同样要求类的所有属性也必须实现 Serializable 接口
  • 要求给类提供一个序列版本号:private static final long serialVersionUID;
  • 属性声明为 statictransient 的,不可以实现序列化
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package TreeSet;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.junit.Test;

public class ObjectStream {
// 对象的序列化过程:将硬盘中的文件通过 ObjectInputStream 转换为相应的对象
@ Test
public void testObjectInputStream() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(
"person.txt"));
Person p1 =(Person)ois.readObject();
System.out.println(p1);
Person p2 =(Person)ois.readObject();
System.out.println(p2);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null)
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

// 对象的序列化过程:将内存中的对象通过 ObjectOutputStream 转换为二进制流,存储在硬盘文件中
@ Test
public void testObjectOutputStream() {
Person p1 = new Person("小米", 23);
Person p2 = new Person("红米", 21);

ObjectOutputStream oos = null;
try {
FileOutputStream fos = new FileOutputStream("person.txt");
oos = new ObjectOutputStream(fos);
oos.writeObject(p1);
oos.flush();
oos.writeObject(p2);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null)
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

class Person implements Serializable {
String name;
Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;

@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}

多线程

基本概念 - 程序 - 进程 - 线程

程序(program) 是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。

进程(process) 是程序的一次执行过程,或是正在运行的一个程序。动态过程:有它自身的产生、存在和消亡的过程。

  • 如:运行中的 QQ,运行中的 MP3 播放器
  • 程序是静态的,进程是动态的

线程(thread) 是由进程进一步细化而来,是一个程序内部的一条执行路径。

  • 若一个程序可同一时间执行多个线程,就是支持多线程的

何时需要多线程

  • 程序需要同时执行两个或多个任务。
  • 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
  • 需要一些后台运行的程序时。

多线程的创建和启动

Java 语言的 JVM 允许程序运行多个线程,它通过 java.lang.Thread 类来实现。

Thread 类的特性

  • 每个线程都是通过某个特定 Thread 对象的 run() 方法来完成操作的,经常把 run() 方法的主体称为线程体
  • 通过该 Thread 对象的 start() 方法来调用这个线程

方法一 声明继承 Thread 子类

  1. 定义子类继承 Thread 类。
  2. 子类中重写 Thread 类中的 run 方法。
  3. 创建 Thread 子类对象,即创建了线程对象。
  4. 调用线程对象 start 方法:启动线程,调用 run 方法

方法二 声明实现 Runnable 接口

  1. 定义子类,实现 Runnable 接口。
  2. 子类中重写 Runnable 接口中的 run 方法。
  3. 通过 Thread 类含参构造器创建线程对象。
  4. Runnable 接口的子类对象作为实际参数传递给 Thread 类的构造方法中。
  5. 调用 Thread 类的 start 方法:开启线程,调用 Runnable 子类接口的 run 方法。

Thread 常用方法

  1. start() :启动线程并执行相应的 run() 方法
  2. run() :子线程要执行的代码放入 run() 方法中
  3. currentThread() :静态的,调取当前的线程
  4. getName() :获取此线程的名字
  5. setName() :设置此线程的名字
  6. yield() :调用此方法的线程释放当前 CPU 的执行权
  7. join() :在 A 线程中调用B 线程的 join() 方法,表示,当执行到此方法,A 线程停止执行,直到 B 线程执行完毕,A 线程再接着 join() 之后的代码执行
  8. isAlive() :判断当前线程是否还存活
  9. sleep(long l) :显示的让当前线程睡眠 l 毫秒
  10. 线程通信: wait() notify() notifyAll()

线程的分类与生命周期

分类

Java 中的线程分为两类:一种是守护线程,一种是用户线程。它们在几乎每个方面都是相同的,唯一的区别是判断 JVM 何时离开。

守护线程是用来服务用户线程的,通过在 start() 方法前调用 thread.setDaemon(true) 可以把一个用户线程变成一个守护线程。

Java 垃圾回收就是一个典型的守护线程。若 JVM 中都是守护线程,当前 JVM 将退出。

生命周期

要想实现多线程,必须在主线程中创建新的线程对象。Java 语言使用 Thread 类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:

  • 新建: 当一个 Thread 类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
  • 就绪:处于新建状态的线程被 start() 后,将进入线程队列等待 CPU 时间片,此时它已具备了运行的条件
  • 运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态, run() 方法定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
  • 死亡:线程完成了它的全部工作或线程被提前强制性地中止

线程的同步

前提:如果我们创建的多个线程,存在着共享数据,那么就有可能出现线程的安全问题:当其中一个线程操作共享数据时,还未操作完成,另外的线程就参与进来,导致对共享数据的操作出现问题。

解决方式:要求一个线程操作共享数据时,只有当其完成操作共享数据,其它线程才有机会执行共享数据。

方式一 同步代码块

1
2
3
synchronized(同步监视器){
//操作共享数据的代码
}

注:

  1. 同步监视器:俗称锁,任何一个类的对象都可以才充当锁。要想保证线程的安全,必须要求所有的线程共用同一把锁!
  2. 使用实现 Runnable 接口的方式创建多线程的话,同步代码块中的锁,可以考虑是 this。如果使用继承 Thread 类的方式,慎用 this!
  3. 共享数据:多个线程需要共同操作的变量。明确哪部分是操作共享数据的代码。

方式二 同步方法
将操作共享数据的方法声明为 synchronized。比如

1
2
3
public synchronized void show(){ 
//操作共享数据的代码
}

注:

  1. 对于非静态的方法而言,使用同步的话,默认锁为:this。如果使用在继承的方式实现多线程的话,慎用!
  2. 对于静态的方法,如果使用同步,默认的锁为:当前类本身。以单例的懒汉式为例。Class clazz = Singleton.class

互斥锁与死锁

互斥锁

Java 语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

关键字 synchronized 来与对象的互斥锁联系。当某个对象用 synchronized 修饰时,表明该对象在任一时刻只能由一个线程访问。

同步的局限性:导致程序的执行效率要降低。同步方法(非静态的)的锁为 this。同步方法(静态的)的锁为当前类本身。

死锁

死锁是指不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。

解决方法:

  • 专门的算法、原则
  • 尽量减少同步资源的定义

释放锁操作

  • 当前线程的同步方法、同步代码块执行结束;
  • 当前线程在同步代码块、同步方法中遇到 breakreturn 终止了该代码块、该方法的继续执行;
  • 当前线程在同步代码块、同步方法中出现了未处理的 ErrorException,导致异常结束;
  • 当前线程在同步代码块、同步方法中执行了线程对象的 wait() 方法,当前线程暂停,并释放锁。

不释放锁的操作

  • 线程执行同步代码块或同步方法时,程序调用Thread.sleep()Thread.yield() 方法暂停当前线程的执行;
  • 线程执行同步代码块时,其他线程调用了该线程的 suspend() 方法将该线程挂起,该线程不会释放锁(同步监视器)。应尽量避免使用 suspend()resume() 来控制线程。

死锁代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class TestDeadLock {
static StringBuffer sb1 = new StringBuffer();
static StringBuffer sb2 = new StringBuffer();

public static void main(String[] args) {
new Thread() {
public void run() {
synchronized(sb1) {
sb1.append("A");
synchronized(sb2) {
sb2.append("B");
System.out.println(sb1);
System.out.println(sb2);
}
}
}
}.start();

new Thread() {
public void run() {
synchronized(sb2) {
sb1.append("C");
synchronized(sb1) {
sb2.append("D");
System.out.println(sb1);
System.out.println(sb2);
}
}
}
}.start();
}
}

线程通信

wait() 与 notify() 和 notifyAll()

  • wait() :令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问
  • notify() :唤醒正在排队等待同步资源的线程中优先级最高者结束等待
  • notifyAll() :唤醒正在排队等待资源的所有线程结束等待

Java.lang.Object 提供的这三个方法只有在synchronized 方法或 synchronized 代码块中才能使用,否则会报 java.lang.IllegalMonitorStateException 异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class PrintNum implements Runnable {
int num = 1;

public void run() {
while (true) {
synchronized (this) {
notify();
if (num <= 100) {
System.out.println(Thread.currentThread().getName() + ":" + num);
num++;
} else {
break;
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

public class TestCommunication {
public static void main(String[] args) {
PrintNum p = new PrintNum();
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);

t1.setName("甲");
t2.setName("乙");

t1.start();
t2.start();
}
}

字符串类

String 类

字符串广泛应用在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。

构造方法

1
2
3
4
String  s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[] a);
String s4 = new String(char[] a, int startIndex, int count)

字符串的特性

String 是一个 final 类,代表不可变的字符序列。
字符串是不可变的。一个字符串对象一旦被配置,其内容是不可变的。

所以你一旦创建了 String 对象,那它的值就无法改变了。 如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。

字符串对象的操作

  • 返回字符串长度

    1
    public int length()
  • 返回在指定 index 位置的字符,index 从零开始

    1
    public char charAt(int index)
  • 比较两个字符串是否相等,相等返回 true,否则返回 false

    1
    public boolean equals(Object anObject)
  • 比较两个字符串是否相等,用于排序

    1
    public int compareTo(String anotherString)
  • 返回 s 字符串在当前字符串首次出现的位置。若没有,返回 -1startpoint 表示从哪个位置开始匹配。

    1
    2
    public int indexOf(String s)
    public int indexOf(String s ,int startpoint)
  • 返回 s 字符串在当前字符串最后一次出现的位置。若没有,返回 -1startpoint 表示从哪个位置开始匹配。

    1
    2
    public int lastIndexOf(String s)
    public int lastIndexOf(String s ,int startpoint)
  • 判断当前字符串是否以 prefix 开始

    1
    public boolean startsWith(String prefix)
  • 判断当前字符串是否以 prefix 结束

    1
    public boolean endsWith(String suffix)
  • 判断当前字符串从 firstStart 开始的子串与另一个字符串 otherotherStart 开始,length 长度的字符串是否相等

    1
    public boolean regionMatches(int firstStart,String other,int otherStart ,int length)

字符串对象的修改

  • 返回从 startpoint 开始到原字符串末尾的子字符串

    1
    public String substring(int startpoint)
  • 返回从 start 开始到 end 结束的一个左闭右开的子字符串

    1
    public String substring(int start,int end)
  • oldChar 替换为 newChar

    1
    pubic String replace(char oldChar,char newChar)
  • 将字符串字符串 old 替换为 new

    1
    public String replaceAll(String old,String new)
  • 去除当前字符串中首尾出现的空格

    1
    public String trim()
  • 连接当前字符串与 str

    1
    public String concat(String str)
  • 按照 regex 将当前字符串拆分拆分为多个字符串,整体返回一个字符串数组

    1
    public String[] split(String regex)

字符串与基本数据类型转换

  • 字符串与基本数据类型、包装类的转换

    1
    2
    3
    4
    String str = "123";
    int i = Integer.parseInt(str); // 字符串--->整型
    String str1 = i + ""; // 整型--->字符串
    String str2 = String.valueOf(i); // 整型--->字符串
  • 字符串与字节数组的转换

    1
    2
    3
    String str = "abc123";
    byte[] b = str.getBytes(); // 字符串--->字节数组
    String str3 = new String(b) // 字节数组--->字符串
  • 字符串与字符数组的转换

    1
    2
    3
    String str = "abc123中国人"
    char[] c = str.toCharArray(); // 字符串--->字符数组
    String str5 = new String(c); // 字符数组--->字符串

StringBuffer 类

java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删。很多方法与 String 相同,但 StingBuffer 是可变长度的。

StingBuffer 是一个容器。

构造方法

1.StringBuffer() 初始容量为 16 的字符串缓冲区
2.StringBuffer(int size) 构造指定容量的字符串缓冲区
3.StringBuffer(String str) 将内容初始化为指定字符串内容

常用方法

1
2
3
4
5
6
7
8
9
10
11
12
StringBuffer append(String s),  StringBuffer append(int n) ,  
StringBuffer append(Object o), StringBuffer append(char n),
StringBuffer append(long n), StringBuffer append(boolean n),
StringBuffer insert(int index, String str)
public StringBuffer reverse()
StringBuffer delete(int startIndex, int endIndex)
public char charAt(int n )
public void setCharAt(int n ,char ch)
StringBuffer replace( int startIndex ,int endIndex, String str)
public int indexOf(String str)
public String substring(int start,int end)
public int length()

总结:添加 append(); 修改 setCharAt(); 查询 charAt(int index); 插入 insert(); 反转 reverse(); 删除 delete()

StringBuilder 类

StringBuilderStringBuffer 非常类似,均代表可变的字符序列,而且方法也一样

  • String:不可变字符序列
  • StringBuffer:可变字符序列、效率低、线程安全
  • StringBuilder(JDK1.5):可变字符序列、效率高、线程不安全

日期类

System 类

System 类提供的 public static long currentTimeMillis() 用来返回当前时间与 1970 年 1 月 1 日 0 时 0 分 0 秒之间以毫秒为单位的时间差。此方法适于计算时间差。

计算世界时间的主要标准有:

  • UTC(Universal Time Coordinated)
  • GMT(Greenwich Mean Time)
  • CST(Central Standard Time)

Date 类

java.util.Date 类,表示特定的瞬间,精确到毫秒。java.sql.Date 类为其的一个子类。

构造方法

  • Date():使用 Date 类的无参数构造方法创建的对象可以获取本地当前时间。
  • Date(long date):创建指定毫秒数的 Date 对象

常用方法

  • getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
  • toString():把此 Date 对象转换为以下形式的 String:dow mon dd hh:mm:ss zzz yyyy 其中:dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat),zzz是时间标准。

代码示例

1
2
3
Data date1 = new Date();
System.out.println(date1.toString());
System.out.println(date1.getTime());

SimpleDateFormat 类

`java.text.SimpleDateFormat 类是一个不与语言环境有关的方式来格式化和解析日期的具体类。

它允许进行格式化解析 操作。格式化:日期—>文本(字符串),解析:文本(字符串)—>日期

格式化

  • SimpleDateFormat():默认的模式和语言环境创建对象
  • public SimpleDateFormat(String pattern):该构造方法可以用参数 pattern 指定的格式创建一个对象,该对象调用:
  • public String format(Date date):方法格式化时间对象 date

解析

  • public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 实例化 SimpleDateFormat:使用默认构造器
SimpleDateFormat sdf = new SimpleDateFormat();

// 格式化:日期 ---> 字符串
Date date = new Data();
System.out.println(date);
String format = sdf.format(date);
System.out.println(format);

// 解析:格式化逆过程,字符串 ---> 日期
String str = "19-12-09 上午11:55";
Date date1= sdf.parse(str);
System.out.println(date1);

// 实例化 SimpleDateFormat:使用带参构造器
SimpleDateFormat sdf1 = new SimpleDateFormat(pattern: "yyyy-MM-dd hh:mm:ss");
// 格式化
String format1 = sdf1.format(date);
System.out.println(format1);
// 解析:要求字符串必须符合 SimpleDateFormat 识别的格式
Date date2 = sdf1.parse(source:"2020-02-18 11:48:27");
System.out.println(date2);

Calendar 类

java.util.Calendar (日历)类是一个抽象基类,主用用于完成日期字段之间相互操作的功能。

获取Calendar实例的方法

  • 使用Calendar.getInstance()方法
  • 调用它的子类GregorianCalendar的构造器。

一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、MINUTE、SECOND

  • public void set(int field,int value)
  • public void add(int field,int amount)
  • public final Date getTime()
  • public final void setTime(Date date)

Math BigInteger BigDecimal

Math 类

java.lang.Math 提供了一系列静态方法用于科学计算;其方法的参数和返回值类型一般为 double 型。

  • abs 绝对值
  • acos,asin,atan,cos,sin,tan 三角函数
  • sqrt 平方根
  • pow(double a,doble b) a的b次幂
  • log 自然对数
  • exp e为底指数
  • max(double a,double b)
  • min(double a,double b)
  • random() 返回0.0到1.0的随机数
  • long round(double a) double型数据a转换为long型(四舍五入)
  • toDegrees(double angrad) 弧度—>角度
  • toRadians(double angdeg) 角度—>弧度

BigInteger 类

Integer 类作为 int 的包装类,能存储的最大整型值为 2^31−1,BigInteger 类的数字范围较 Integer 类的数字范围要大得多,可以支持任意精度的整数。
构造器

  • BigInteger(String val)
    常用方法
  • public BigInteger abs()
  • public BigInteger add(BigInteger val)
  • public BigInteger subtract(BigInteger val)
  • public BigInteger multiply(BigInteger val)
  • public BigInteger divide(BigInteger val)
  • public BigInteger remainder(BigInteger val)
  • public BigInteger pow(int exponent)
  • public BigInteger[] divideAndRemainder(BigInteger val)

BigDecimal 类

一般的 Float 类和 Double 类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到 java.math.BigDecimal 类。BigDecimal 类支持任何精度的定点数。
构造器

  • public BigDecimal(double val)
  • public BigDecimal(String val)
    常用方法
  • public BigDecimal add(BigDecimal augend)
  • public BigDecimal subtract(BigDecimal subtrahend)
  • public BigDecimal multiply(BigDecimal multiplicand)
  • public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
坚持原创技术分享,您的支持将鼓励我继续创作!