## 1. 类抽象与封装

> Class abstraction means to separate class implementation from the use of the class. The creator of the class provides a description of the class and let the user know how the class can be used. The user of the class does not need to know how the class is implemented. The detail of implementation is encapsulated and hidden from the user. 

类抽象的含义是分离类的实现细节和类的使用，这如何理解？Java类的编写者为使用该类的用户提供说明，让使用者知道如何使用该类，但是使用者并不知道类的具体实现。类的具体实现被封装和隐藏起来，使用者并不用知道。对于使用者，只需要知道如何使用该类的功能，而不用知道类是如何实现这些功能的。

利用生活当中的例子：你去修车，给修车师傅说明你需要处理什么问题（外部接口调用），修车师傅去处理你车的故障（运行封装在类内部的功能函数等），最后告知你处理结果（外部接口调用返回）。

![image-20230313180426040](img/image-20230313180426040.png)

修车师傅是一个对象，你只告诉修车师傅什么故障，剩下的事情交给他来处理，会给你一个处理结果。你并不关系修车师傅是如何修车的。这就是类的抽象与封装。

其实最常用的抽象和封装是函数，只不过类把这个概念提升到了另外一个层次；函数只是对方法（行为）进行抽象与封装，类则是把相关的数据和方法进行打包和分类，这样更便于使用。不光如此，后面将要学习的继承和接口将极大的减少代码的冗余，便于代码的重复使用。 

注：C中还有一种封装，就是静态库和动态库；是把相关函数的编译结果进行打包，用于外部调用，但是隐藏内部实现细节；不过仍然局限于函数。

其他例子：

1. Designing the Loan Class
2. The Course Class
3. StackOfIntegers Class

## 2. 封装类型 Wrapper class

回忆一下前面我们学到的基本类型（primitive 类型），这些类型包括所有的以小写字母大头的Java预定义类型。

1. byte
2. short
3. int
4. long
5. float
6. double
7. boolean
8. char

使用这些类型和C中对应的这些类型几乎完全一致，这些类型不是引用类型（不需要new 关键字来生成对象），在赋值与参数传递的时候采用的是值传递的方法。

**primitive：基本类型，也叫原始类型**

在Java中，有一句话叫做：**一切皆对象**。Java中也存在与基本类型对应的引用类型，叫做封装类型，这些类型是以大写字母开头的。

| Primitive type | Wrapper type(class) |
| -------------- | ------------------- |
| byte           | Byte                |
| short          | Short               |
| int            | **Integer**         |
| long           | Long                |
| float          | Float               |
| double         | Double              |
| boolean        | Boolean             |
| char           | **Character**       |

1.  The wrapper classes do not have no-arg constructors. 封装类型没有不带参数的构造函数；
2.  The instances of all wrapper classes are immutable. 所有封装类型的对象都是immutable。

封装类型我们前面用过一些，不过是其静态的成员函数。例如：`Integer.parseInt("1234")`,`Double.parseDouble("3.14"),等这样的函数；凡是数值类型的封装类型都有类似的函数把一个字符串转换成对应的基本类型（原始类型）。

Character类的`Character.isDigit(char)`，`Character.isLetter(char)`这些函数前面也接触到过。

### 2.1. 数值类封装类型

#### 2.1.1. 数值类封装类型的构建

既然封装类型是引用类型（类），那么就可以使用new关键字来生成一个对应的对象。

```java
		Byte b = new Byte((byte) 10); 			// 这是合法的，但是必须转换成byte类型
		Short s = new Short((short) 100);		// 这是合法的，但是必须转换成short类型
		Integer i = new Integer(200);
		Long l = new Long(999999);
		Float f = new Float(3.14);
		Double d = new Double(33.33);	
```

**注意：新版本的Java已经把通过构造函数生成数值类封装类型标记为`@Deprecated`，因此将来可能会取消，变成不合法的。新版本的Java对于数值类封装类型建议使用对应类型的静态函数valueOf()类构造。valueOf()函数有多个重载的版本，请查看对应的文档。**

数值类封装类型有静态函数valueOf，可以从相应的原始类型或者字符串来生成对应数值类封装类型的对象：

```java
		Integer i = Integer.valueOf(100);
		Integer i = Integer.valueOf("100");
```

但是这样的写法太复杂了，我们可以简单的写成：

```java
		Byte b = 10; 			// 这是合法的
		Short s = 100;
		Integer i = 200;
		Long l = 999999L;		// 字面量量缺省是int类型，需要标记成L（长整型）
		Float f = 3.14F;		// 字面量是double类型，需要标记成F（浮点类型）
		Double d = 33.33;
```

#### 2.1.2. 数值类封装类型的转换

数值类封装类型和原始类型间可以自由转换与赋值：

```java
		int a = 100;
		Integer i = a;
		i = 200;
		a = i;
```

**注意：不同的类型的数值类封装类型对象间不能赋值**

```java
		int a = 100;
		long b = a;
		a = (int) b;
		
		Integer i1 = 100;
		Long l1 = 200L;
		
		i1 = l1;				// 非法
		l1 = i1;				// 非法
```

同时原始类型的强制类型转换方式（类似C的方式）不能用在数值类封装类型中：

```java
		Integer i1 = 100;
		Long l1 = 200L;
		
		i1 = (Integer)l1;			// 非法
		l1 = (Long)i1;				// 非法
```

不同数值类封装类型间的类型转换应该使用实例函数byteValue()，shortValue()，intValue()，longValue()， floatValue()，doubleValue() 这些函数：

```java
		Integer i = 100;
		Byte b = i.byteValue();
		Short s = i.shortValue();
		long l = i.longValue();
		Float f = s.floatValue();
		double d = f.doubleValue();
```

#### 2.1.3. 数值类封装类型的常量

![image-20230311093817254](img/image-20230311093817254.png)

例如Integer和Double（其他数值类一样），都有MAX_VALUE和MIN_VALUE两个常量，且是静态的。

#### 2.1.4. 特殊值null

**在使用数值类封装类型的时候要特别注意！封装类型是引用类型，因此可能有一个特殊的值null；**

## 3. 字符串

### 3.1. join和split

关于String的大多特性前几章已经覆盖了。这一章中有一个String的split函数，在数组中给大家进行了初步的说明。

例如一个以空格分隔的字符串，我们希望把每一段切取出来，形成一个数组，这时我们使用：

```java
        String string = "AAA BBB CCC";
        string.split(" ");
```

split的参数是一个正则表达式（这个我们可以不用掌握），这里如果字符串是空格分隔，写入一个空格的字符串就可以了，标识拆分的字符串。

函数返回是一个 String\[\] 类型的数组，你得到的是 {"AAA", "BBB", "CCC" } ，注意，不包含分隔字符串。

相对的，可以使用 join 函数把一个字符串数组以一定的分隔符连接成一个新的字符串。

split 是实例函数，join是静态函数。

```java
public class Test {
	public static void main(String[] args) {
		String string = "AAA BBB CCC";
		String sAry[] = string.split(" ");
		for (String s : sAry) {
			System.out.println(s);
		}
		
		String newStr = String.join(":", sAry);
		
		System.out.println(newStr);
	}
}
```

### 3.2. 正则表达式（了解）

正则表达（regular expression）式是用来对字符串进行模糊匹配的，功能非常强大，但规则比较难一点。

You can match, replace, or split a string by specifying a pattern. This is an extremely useful and powerful feature, commonly known as regular expression. Regular expression is complex to beginning students. For this reason, two simple patterns are used in this section. Please refer to Supplement III.F, “Regular Expressions,” for further studies. 

在用到字符串对比和查找的地方都可以用到正则表达式，例如：

```java
"Java".matches("Java");					// 字符串的字面量本来就是一个字符串对象，可以在其上使用字符串的实例函数
"Java".equals("Java");
"Java is fun".matches("Java.*");
"Java is cool".matches("Java.*");
```

如果大家有兴趣，可以自己学习正则表达式。

### 3.3. StringBuilder 和 StringBuffer

String是immutable，表示其值是不能更改的；一旦给一个String类型的引用变量赋值，相当于产生了一个新的对象；这样，对于一个需要经常变化的字符串操作来说是不经济的（耗费系统资源），因此有了StringBuilder和StringBuffer。这两个类维护了一个字符串的缓冲区，且内容是可以随时进行修改的，也可以方便的转换成String类型。

例如：

```
import java.util.Scanner;

public class PalindromeIgnoreNonAlphanumeric {
	/** Main method */
	public static void main(String[] args) {
		// Create a Scanner
		Scanner input = new Scanner(System.in);

		// Prompt the user to enter a string
		System.out.print("Enter a string: ");
		String s = input.nextLine();

		// Display result
		System.out.println("Ignoring non-alphanumeric characters, \nis " + s + " a palindrome? " + isPalindrome(s));
	}

	/** Return true if a string is a palindrome */
	public static boolean isPalindrome(String s) {
		// Create a new string by eliminating non-alphanumeric chars
		String s1 = filter(s);

		// Create a new string that is the reversal of s1
		String s2 = reverse(s1);

		// Compare if the reversal is the same as the original string
		return s2.equals(s1);
	}

	/** Create a new string by eliminating non-alphanumeric chars */
	public static String filter(String s) {
		// Create a string builder
		StringBuilder stringBuilder = new StringBuilder();

		// Examine each char in the string to skip alphanumeric char
		for (int i = 0; i < s.length(); i++) {
			if (Character.isLetterOrDigit(s.charAt(i))) {
				stringBuilder.append(s.charAt(i));
			}
		}

		// Return a new filtered string
		return stringBuilder.toString();
	}

	/** Create a new string by reversing a specified string */
	public static String reverse(String s) {
		StringBuilder stringBuilder = new StringBuilder(s);
		stringBuilder.reverse(); // Invoke reverse in StringBuilder
		return stringBuilder.toString();
	}
}
```

## 
