java中三個特殊的類------String類、Object類、包裝類
1.String類
1.1 String類的兩種例項化方式
- 直接賦值
String str = "hello"
- 通過構造方法例項化String類
String str = new String("hello")
1.2 字串相等比較(內容)
public boolean equals(String anotherString);
成員方法,需要通過物件呼叫
例:
str1.equals(str2);
看程式碼:
public class Test{ public static void main(String[] args){ String str1 = "hello"; String str2 = new String("hello"); System.out.println(str1 == str2); System.out.println(str1.equals(str2)); } }
輸出結果:
false
true
這裡就體現出equals()方法的作用了,str1 == str2這判斷的是這兩個字串的地址是否相同,因為str2用了new,重新開闢了一個新空間,所以和str1的地址肯定是不相同的;但equals()比較的是兩個字串的內容,str1和str2內容相同,所以返回true。
看圖:
1.3字串常量是String的匿名物件
例:"hello".equals(str2);
這裡有一個坑,如果我們使用:str.equals(“hello”),有可能會出現nullPointException(空指標異常)報錯,因為str可能是一個空字串。
所以記住,以後在開發中,如果要判斷使用者輸入的字串是否等同於特定字串,一定要將字串(String常量)寫在前面。
1.4 物件池(物件陣列)
我們先來看一段程式碼吧:
public class Test{
public static void main(String[] args){
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
}
}
我們先來猜猜這個的返回值吧。肯定好多人都認為它返回的是false吧,但不是的,為了讓你們相信,直接上圖吧。
沒錯,它返回的就算true。
肯定有疑問了吧,上邊不是說了str1 == str2比較的是地址嗎?它兩地址怎麼會相等。
那是因為JVM底層會自動維護一個字串的物件池,如果採用直接賦值
再畫圖解釋一下吧:
1.5 字串常量不可變更
字串一旦定義後不可改變。因為字串的底層實現就算字元陣列,我們都知道,陣列最大的一個缺陷就算它的長度是固定的,所以定義字串的常量時,它的內容不可改變。
我們來看看這段程式碼:
public class Test{
public static void main(String[] args){
String str = "hello";
System.out.println(str+"world");
}
}
它的輸出結果如下:
我們發現hello和world連線在了一起,不是說字串內容一旦定義就不能改變嗎?
其實這裡並沒有改變字串內容,變的是字串物件。我們來看實際的過程圖;
說這個的目的何在呢?
因為改變的是物件的引用,前邊的“hello”和"world"都成了垃圾空間,如果一直+下去,垃圾空間將會特別大。
1.6 字元與字元陣列的相互轉換
a. 將字元陣列轉為字串
public String(char[] value)
public String (char[] value, int offest, int count)//offest表示從陣列的哪個位置開始,count表示將count個字元轉為字串
例:
public class Test{
public static void main(String[] args){
char[] arr = {'h','e','l','l','o','w','o','r','l','d'};
String str1 = new String(arr);
String str2 = new String(arr, 5, 5);
System.out.println(str1);
System.out.println(str2);
}
}
b. 將字串轉為單個字元
public char charAt(int index)
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
char c = str.charAt(4);
System.out.println(c);
}
}
c. 將字串變為字元陣列
public char[] toCharArray()
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
char[] arr = str.toCharArray();
System.out.println(arr.length);
}
}
1.7 位元組(byte)與字串
a. 將位元組陣列轉為字串
public String(byte[] value)
public String(byte[] value, int offest, int count)
b.將字串轉為位元組陣列
public byte[] getBytes()
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
byte[] data = str.getBytes();
for(int i = 0; i < data.length; i++){
System.out.print(data[i]+"、");
}
System.out.println();
//將位元組陣列轉換為字串
System.out.println(new String(data));
}
}
1.8 字串比較
a. 不區分大小寫相等比較
public boolean equalsIgnoreCase(String anotherString)
例:
public class Test{
public static void main(String[] args){
String str1 = "hello world";
String str2 = "Hello World";
System.out.println(str1.equalsIgnoreCase(str2));
}
}
b. 比較兩個字串大小
public int compareTo(String anotherString)
- 返回大於0:表示大於比較物件
- 返回等於0:表示兩者相等
- 返回小於0:表示小於比較物件
例:
public class Test{
public static void main(String[] args){
String str1 = "hello world";
String str2 = "Hello World";
System.out.println(str1.compareTo(str2));
}
}
1.9 字串查詢
public boolean contains(String str):判斷str在本字串中是否存在
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
System.out.println(str.contains("ld"));
}
}
2.public boolean startsWith(String str):判斷是否以指定字串開頭
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
System.out.println(str.startsWith("e"));
}
}
3. public boolean startsWith(String str, int index):判斷指定位置是否以指定字串開頭
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
System.out.println(str.startsWith("w", 6));
}
}
4. public boolean endsWith(String str):判斷是否以指定字串結尾
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
System.out.println(str.endsWith("d"));
}
}
1.10 字串替換
public String replaceAll(String regex, String replacement):替換所有指定內容
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
System.out.println(str.replaceAll("l", "_"));
}
}
2. public String replaceFirst(String regex, String replacement):替換首個指定內容
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
System.out.println(str.replaceFirst("l", "_"));
}
}
1.11 字串拆分
3. public String[] split(String regex):將字串按照指定格式全部拆分
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
String[] result = str.split(" ");//按照空格拆分
for(String s: result){
System.out.println(s);
}
}
}
4. public String[] split(String regex, int limit):將字串按照指定格式部分拆分,陣列長度為limit
例:
public class Test{
public static void main(String[] args){
String str = "hello world haha";
String[] result = str.split(" ", 2);
for(String s: result){
System.out.println(s);
}
}
}
1.12 字串擷取
5. public String substring(int beginIndex):從指定位置開始擷取到字串結尾
例:
public class Test{
public static void main(String[] args){
String str = "hello world haha";
System.out.println(str.substring(3));
}
}
6. public String substring(int beginIndex, int endIndex):擷取部分
例:
public class Test{
public static void main(String[] args){
String str = "hello world haha";
System.out.println(str.substring(3, 9));
}
}
1.13 String類的其他方法
a. 去掉左右空格
public String trim()
例:
public class Test{
public static void main(String[] args){
String str = " hello world haha ";
System.out.println(str.trim());
}
}
b. 字串轉大小寫
public String toUpperCase()
public String toLowerCase()
例:
public class Test{
public static void main(String[] args){
String str = "hello world";
String str1 = "HELLO";
System.out.println(str.toUpperCase());
System.out.println(str1.toLowerCase());
}
}
c. 判斷字串是否為空(只能判斷是否為空字串而不是null)
public boolean isEmpty()
例:
public class Test{
public static void main(String[] args){
String str = "";
System.out.println(str.isEmpty());
}
}
1.14 兩隻sb(StringBuffer()、StringBuilder())----方便字串的修改(前邊說過String是不能修改字串的)
a. 字串修改
public StringBuffer append(各種資料型別)
例:
public class Test{
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
sb.append("hello").append("world");
fun(sb);
System.out.println(sb);
}
public static void fun(StringBuffer s){
s.append("\n").append("Calm");
}
}
b. StringBuffer與String的相互轉換
(1)String轉成StringBuffer
呼叫StringBuffer的構造方法或append()方法
(2)StringBuffer轉為String
呼叫toStrig()方法
c. 字串反轉
public StringBuffer reverse()
例:
public class Test{
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
sb.append("hello").append("world");
System.out.println(sb.reverse());
}
}
d. 刪除指定範圍的資料
public StringBuffer delete(int start, int end)
例:
public class Test{
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
sb.append("hello").append("world");
System.out.println(sb.delete(2, 5));
}
}
e. 插入資料
public StringBuffer insert(int offest, 各種資料型別)
例:
public class Test{
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
sb.append("hello").append("world");
System.out.println(sb.insert(2, "你好"));
}
}
總結
String、StringBuffer、StringBuilder的區別:
- String的內容不可以修改,而兩隻sb可修改內容(append)
- StringBuffer採用同步處理,執行緒安全,效率較低
- StringBuilder採用非同步處理,執行緒不安全,效率較高。
例:
String s = "hello";
System.out.println(s+"world");
底層會將String自動轉換為StringBuilder。
2.Object類-----接收除基本型別所有的類的物件
Object是java預設提供的類
java中,除了Object類,所有的類都存在繼承關係,預設會繼承Object父類,所有類(除了8大基本型別(byte、short、int、long、float、double、char、boolean))物件都可以通過Object類進行接收。
2.1 取得物件資訊-----toString()
直接使用物件的輸出,預設輸出一個地址編碼,但如果輸出的是String物件,此時會輸出字串的內容而不是地址,這是因為String覆寫了Object的toString()方法。
System.out.println():系統輸出預設會呼叫物件的toString(),也就算說,一旦出現System.out.println(),其實就算呼叫了toString(),輸出的是toString()裡的東西。
例:
class Person{
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
public class Test{
public static void main(String[] args){
Person person = new Person(18,"張三");
System.out.println(person);
}
}
從輸出結果可以看出,輸出的是一個地址編碼,這個地址就算Person類的地址。
現在我們想要輸出年齡和姓名的話,就需要覆寫它的toString()方法。
看程式碼:
class Person{
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class Test{
public static void main(String[] args){
Person person = new Person(18,"張三");
System.out.println(person);
}
}
我們現在再來看看輸出結果:
如果我們不想輸出地址,而要輸出本類資訊,就需要在子類中覆寫toString()方法。
2.2 物件比較-----equals()
String類物件的比較使用的是equals()方法,實際上,String類的equals()也是覆寫了Object類的equals()方法。
例:
class Person{
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object obj){
if(obj == null){
return false;
}
if(this == obj){
return true;
}
//如果obj不是Person類物件
if(!(obj instanceof Person)){
return false;
}
//向下轉型,比較屬性值
Person per = (Person) obj;
return (this.age == per.age) && (this.name.equals(per.name));
}
}
public class Test{
public static void main(String[] args){
Person person1 = new Person(18,"張三");
Person person2 = new Person(18,"張三");
System.out.println(person1.equals(person2));
}
}
2.3 接收引用資料型別
Object可以接收所有引用型別,包括:類、陣列、介面。
public class Test{
public static void main(String[] args){
//Object接收陣列物件,發生向上轉型
Object obj = new int[]{1, 4, 2, 7};
//向下轉型,需要強轉
int[] data = (int[]) obj;
for(int i : data){
System.out.print(i+"、");
}
}
}
3. 包裝類
包裝類就算將基本型別封裝到類中。
自己實現一個包裝類:
class IntDemo{
private int num;
public IntDemo(int num){
this.num = num;
}
public int intValue(){
return this.num;
}
}
public class Test{
public static void main(String[] args){
//子類物件向上轉型
Object obj = new IntDemo(78);
//向下轉型
IntDemo data = (IntDemo) obj;
//取出裡面的基本資料型別操作
System.out.println(data.intValue());
}
}
IntDemo實際上就算int型別的包裝類,使用intValue()就可以實現將基本型別變為物件的需求。
3.1 分類
a. 物件型包裝類(Object的直接子類):Boolean(boolean)、Character(char)
b. 數值型包裝類(Number的直接子類),存在數值轉換異常:Byte(byte)、Integer(int)、Short(short)、Long(long)、Double(double)、Float(float)
3.2 裝箱與拆箱-----基本資料型別與相應包裝類的資料處理
裝箱:將基本資料型別變為包裝類物件,利用每個包裝類提供的構造方法實現包裝。
Integer num = new Integer(19);
拆箱:將包裝類中包裝的基本型別值取出來,利用Number類提供的xxValue()方法實現拆箱處理。
int data = num.intValue();
在JDK1.5之後提供了自動拆裝箱處理機制。
//自動裝箱
Integer num = 34;
//自動拆箱
System.out.println(--num * 2);
包裝類物件之間的值比較依然要使用equals()方法
我們下來看一段程式碼,就知道為什麼要這樣了。
public class Test{
public static void main(String[] args){
Integer num1 = new Integer(20);
Integer num2 = new Integer(20);
System.out.println(num1 == num2);
System.out.println(num1 == new Integer(20));
System.out.println(num1.equals(new Integer(20)));
}
}
至於原因,在上邊String類裡已經解釋的很清楚了。這裡有兩個new,沒new一次就會在堆空間裡開闢一個新空間,所以num1和num2的地址不同。
public class Test{
public static void main(String[] args){
Integer num1 = new Integer(20);
Integer num2 = 20;
Integer num3 = 200;
Integer num4 = 200;
Integer num5 = 56;
Integer num6 = 56;
System.out.println(num1 == num2);
System.out.println(num3 == num4);
System.out.println(num5 == num6);
}
}
為什麼會出現上邊這種現象呢?
那是因為對於Integer來說,如果它的物件值在-128~127之間的直接賦值,Integer物件在Integer常量池產生,會複用已有物件,這個區間內的Integer值可以直接使用==判斷。除此之外,所有的資料都會在堆上產生,並不會複用已有物件。
3.3 字串與基本型別的轉換
- 將字串轉為基本型別(靜態方法)
呼叫各個包裝類.parsexx(String str)
例:
public class Test{
public static void main(String[] args){
String str = "123";
System.out.println(Integer.parseInt(str));
}
}
但如果123後邊還有字串型別的字元的話,轉換就會出錯:
2. 基本型別變為字串
a. “”+基本型別,會產生垃圾空間
b. 使用Sting類的valueOf(基本型別),此方法不會產生垃圾空間
public class Test{
public static void main(String[] args){
int num = 100;
String str = String.valueOf(num);
System.out.println(str.length());
}
}