【Java5】String类,StringBuilder类,ArrayList类,Object类(toString,equals,hashCode)
文章目錄
- 1.String類:字符串常量在Java中不屬于基本數據類型, 而是引用/類類型
- 1.1 使用:new String(...)
- 1.2 判斷:equals函數是用來比較兩個對象是否相等
- 1.3 比較:able to重要,or e
- 1.4 獲取:.charAt,.indexOf
- 1.5 轉換:.toCharArray,.getBytes,.replace
- 1.6 分割:.split
- 1.7 模擬用戶登錄:.nextLine,.equals
- 1.8 遍歷字符串:.charAt
- 1.9 統計字符個數:&&
- 1.10 字符串拼接:+
- 1.11 字符串反轉:i- -
- 1.12 空字符串判斷:.intern()
- 2.StringBuilder類:線程不安全但速度快于stringbuffer(線程安全即每個方法上都加synchronized,效率低,拋棄)
- 2.1 構造方法:new StringBuilder(" ")
- 2.2 append方法:StringBuilder已經覆蓋重寫了Object當中的toString方法
- 2.3 toString方法:StringBuilder對象將會轉換為不可變的String對象
- 2.4 reverse方法:.reverse()
- 2.5 StringBuilder和String相互轉換:toString()
- 2.6 字符串拼接:定義一個方法將int[] arr = {1,2,3}輸出為:[1, 2, 3]
- 2.7 字符串反轉:返回值類型:String , 參數:String s
- 3.ArrayList類:ArrayList list = new ArrayList()
- 3.1 引入—對象數組:基本數據類型變量只保存基本數據類型,不能保存對象。引用數據類型變量是可保存對象,但只能保存一個對象
- 3.2 集合與數組區別:變,只對,不
- 3.3 ArrayList類使用:public ArrayList() 構造一個內容為空的集合
- 3.4 常用方法和遍歷:對于元素的操作:增、刪、查
- 4.Object類:對象都需重寫
- 4.1 toString方法:Object中的tostring方法: 對象類型包名類名 + 內存地址
- 4.2 equals方法:Object類中的equals方法是==比較內存地址
- 4.3 hashCode方法和equals方法:兩個對象hashCode方法返回值相同,那么這兩個是否equals?或者兩個對象equals,那么hashCode方法返回值是否相同?
- 4.3.1 為什么要有如上這樣的規范?牽扯到一系列hash存儲
- 4.3.2 hashCode擴展:重寫hashcode方法不會在對象頭中進行存儲,對象頭中31bit永遠是0
1.String類:字符串常量在Java中不屬于基本數據類型, 而是引用/類類型
Java中使用String這個類描述字符串這種常量數據,java.lang.String 類代表字符串。Java程序中所有的字符串文字(例如"abc" )都可以被看作是實現此類的實例。
1.字符串常量:它屬于對象,但是它不是像之前的對象通過new的方式在堆中開辟空間,而是存儲在字符串常量池中。說明:jdk1.7之前字符串常量池是位于方法區中的,而jdk1.7之后是位于堆中的。
位于堆中和之前new空間不沖突,常量池是一個單獨的空間。字符串常量池中保存的就是所有的字符串數據。只要書寫了雙引號,不管雙引號中間是什么數據,這些數據都會立刻在字符串常量池中保存,并且一直存在,不會被改變。所有在Java程序中使用雙引號引用起來的數據都是一個對象。
2.字符串不變:字符串的值在創建后不能被更改。String類中描述的是所有字符串常量,一旦書寫完成,它就是一個固定值,這個數據不能改變。
String s3="def"; s3="efg"; System.out.println(s3); // 內存中有"def","efg"兩個對象,s3從指向"def",改變指向,指向了"efg"。String對象是不可變的,所以它們可以被共享。
String s1="abc"; //定義字符串對象 //int i=3;在棧中開辟空間名稱叫做i,存值為3 String s2="abc"; //System.out.println(s1); //abc //打印的不是內存地址名,是abc常量的值 System.out.println(s1==s2);//這里比較的是內存地址名是否相等 //true如下string str 是方法中引用類型的局部變量,所以在左邊棧中。
如下main中第一行,JVM會在內部的String pool中查找有沒有字符串常量"hello",沒有的話創建"hello"對象。
第二行JVM在String pool中查找,有則返回"hello"的地址,這里雖然沒創建對象,但str1并不等于str2,因為引用的地址不一樣(str1指向堆內存地址,str2指向字符串池地址)。
第三行JVM同樣在String pool中查找,有字符串常量"hello"則不再創建。由于使用了new,JVM又在堆中創建一個"hello"對象。
1.1 使用:new String(…)
構造方法:用雙引號本身就可得到一個字符串對象。String類提供了大量的構造函數,目的是可以幫助我們將其他的數據變成字符串對象。只要使用String類的構造函數創建的對象,那么這個對象就會在堆中出現。而在創建出的字符串對象中的字符數據保存在常量池。
// 無參構造 // java.lang.String String str = new String();//構造函數// 通過字符數組構造,將參數的字符數組轉換為String類的對象 char chars[] = {'a', 'b', 'c'}; String str2 = new String(chars);// 通過字節數組構造,將參數的字節數組轉換為String類的對象 byte bytes[] = { 97, 98, 99 }; String str3 = new String(bytes);1.2 判斷:equals函數是用來比較兩個對象是否相等
public class String_Demo01 {public static void main(String[] args) {// 創建字符串對象String s1 = "hello";String s2 = "hello";String s3 = "HELLO";// boolean equals(Object obj):比較字符串的內容是否相同System.out.println(s1.equals(s2)); // trueSystem.out.println(s1.equals(s3)); // false//boolean equalsIgnoreCase(String str):比較字符串的內容是否相同,忽略大小寫System.out.println(s1.equalsIgnoreCase(s2)); // trueSystem.out.println(s1.equalsIgnoreCase(s3)); // true} }如果想比較兩個字符串相等,我們不應該使用 == (恒等符號),因為 == 是用來比較具體常量數值的。而由于字符串是對象,所以我們應該使用String類中的equals函數對兩個字符串進行比較。
1.3 比較:able to重要,or e
package com.atguigu.test05; /** java.util.Comparator:定制比較,定制順序,是對自然比較的補充* int compare(Object o1, Object o2)://接口的抽象方法(要重寫)* o1與o2比較,o1>o2,返回正整數* o1與o2比較,o1<o2,返回負整數* o1與o2比較,o1=o2,返回0* java.lang.Comparable:自然比較,自然順序,核心默認不用導包。* int compareTo(Object obj) // 接口的抽象方法(要重寫)* this與obj對象比較,this > obj,返回正整數* this與obj對象比較,this < obj,返回負整數* this與obj對象比較,this = obj,返回0*/ public class TestComparable {public static void main(String[] args) {Student s1 = new Student("楊洪強", 24, 89);Student s2 = new Student("蘇海波", 23, 100); //按成績比較,不用第三個對象了if(s1.compareTo(s2)>0){System.out.println("s1 > s2成績");}else if(s1.compareTo(s2)<0){System.out.println("s1 < s2成績");}else{System.out.println("s1 = s2成績");} } } class Student implements Comparable{ //希望學生對象本身就具備比較大小的能力。private String name;private int age;private int score;public Student(String name, int age, int score) {super();this.name = name;this.age = age;this.score = score;}public Student() {super();}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";}@Overridepublic int compareTo(Object obj) { Student other = (Student) obj; //this與obj比較,this和obj都是學生對象//例如:對于學生對象來說,最常用的是按成績排名,那么我就可以把自然順序定位成績升序/* if(this.score > other.score){return 1;}else if(this.score < other.score){return -1;}return 0;*/ return this.score - other.score;} } package com.atguigu.test05; import java.util.Arrays; /** Arrays的sort方法有兩種:(1)void sort(Object[] arr):* 根據元素的 自然順序 對指定對象數組按升序進行排序。數組中的所有元素都必須實現 Comparable 接口* (2)void sort(Object[] arr, Comparator c):* 根據“指定比較器”產生的順序對指定對象數組進行排序。數組中的所有元素都必須是通過“指定比較器”可相互比較*/ public class TestArrays {public static void main(String[] args) {Student[] all = new Student[5];all[0] = new Student("楊洪強", 24, 89);all[1] = new Student("蘇海波", 23, 100);all[2] = new Student("張三",23,88);all[3] = new Student("李四",24,44);all[4] = new Student("王五",25,45); //如果我們的學生類Student,實現了java.lang.Comparable接口,//能不能按照自然排序的規則進行排序呢?//Arrays中有這樣的方法:public static void sort(Object[] a) Arrays.sort(all);//這里面排序過程中,調用了元素本身的compareTo()方法for (int i = 0; i < all.length; i++) {System.out.println(all[i]);}} }如下按成績升序,因為Student類本身實現了Comparable接口重寫了compareTo方法。
如上結果為:[Alice,chai,hello,Hi,Java]
1.4 獲取:.charAt,.indexOf
package com.itheima.demo01; import java.lang.String;public class HelloWorld {public static void main(String[] args) {// String concat (String str):將指定的字符串連接到該字符串的末尾.String s = "helloworld";String s2 = s.concat("**hello itheima");System.out.println(s2);// helloworld**hello itheima// char charAt(int index):獲取指定索引處的字符System.out.println(s.charAt(0)); // hSystem.out.println(s.charAt(1)); // e// int indexOf(String str):獲取str在字符串對象中第一次出現的索引,沒有返回-1System.out.println(s.indexOf("l")); //2System.out.println(s.indexOf("owo")); //4System.out.println(s.indexOf("ak")); //-1// String substring(int start):從start開始截取字符串到字符串結尾System.out.println(s.substring(0)); // helloworldSystem.out.println(s.substring(5)); // world// String substring(int start,int end):從start到end截取字符串。含start,不含end。System.out.println(s.substring(0, s.length())); // helloworldSystem.out.println(s.substring(3,8)); // lowor,不含8即l} }1.5 轉換:.toCharArray,.getBytes,.replace
package com.itheima.demo01; import java.lang.String;class String_Demo03 {public static void main(String[] args) {String s = "abcde";char[] chs = s.toCharArray(); // 把字符串轉換為字符數組for(int x = 0; x < chs.length; x++) {System.out.println(chs[x]); // a b c d e}byte[] bytes = s.getBytes(); //把字符串轉換為字節數組for(int x = 0; x < bytes.length; x++) {System.out.println(bytes[x]); // 97 98 99 100 101}String str = "itcast itheima";String replace = str.replace("it", "IT");System.out.println(replace); // ITcast ITheima} }1.6 分割:.split
public class String_Demo03 {public static void main(String[] args) {String s = "aa,bb,cc";String[] strArray = s.split(","); // ["aa","bb","cc"],字符串對象拆為字符串數組for(int x = 0; x < strArray.length; x++) {System.out.println(strArray[x]); // aa bb cc}} }1.7 模擬用戶登錄:.nextLine,.equals
package com.itheima.demo01; import java.util.Scanner; // 需求:已知用戶名和密碼,用程序實現模擬用戶登錄,一共給3次機會,登陸后給出相應提示。 class StringTest01 {public static void main(String[] args) {//已知用戶名和密碼,定義兩個字符串表示即可String username = "itheima";String password = "czbk";//用循環實現多次機會,這里的次數明確,采用for循環實現,并在登錄成功的時候,使用break結束循環for(int i=0; i<3; i++) {//鍵盤錄入要登錄的用戶名和密碼,用 Scanner 實現Scanner sc = new Scanner(System.in);System.out.println("請輸入用戶名:");String name = sc.nextLine();System.out.println("請輸入密碼:");String pwd = sc.nextLine();//拿鍵盤錄入的用戶名、密碼和已知的用戶名、密碼進行比較,給出相應的提示。字符串的內容比較,用equals() 方法實現if (name.equals(username) && pwd.equals(password)) {System.out.println("登錄成功");break;} else {if(2-i == 0) {System.out.println("你的賬戶被鎖定,請與管理員聯系");} else {//2,1,0//i為0,1,2System.out.println("登錄失敗,你還有" + (2 - i) + "次機會");}}}} } class CodeDemo {public static void main(String[] args) throws IOException {String username = "ta";String password = "123";Scanner sc = new Scanner(System.in);System.out.println("請輸入用戶名:");String name = sc.nextLine(); if(name.length() == 0){System.out.println("登錄失敗");return;}System.out.println("請輸入密碼:");String pwd = sc.nextLine(); if(pwd.length() == 0){System.out.println("登錄失敗");}if (name.equals(username) && pwd.equals(password)){System.out.println("登錄成功");} else {System.out.println("登錄失敗");} }}1.8 遍歷字符串:.charAt
public class StringTest02 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("請輸入一個字符串:");String line = sc.nextLine(); for(int i=0; i<line.length(); i++) {System.out.println(line.charAt(i)); //空字符也遍歷}} }1.9 統計字符個數:&&
public class StringTest2 {public static void main(String[] args) {//鍵盤錄入一個字符串數據,統計字符串大小寫字母及數字字符個數Scanner sc = new Scanner(System.in);System.out.println("請輸入一個字符串數據:");String s = sc.nextLine();//定義三個統計變量,初始化值都是0int bigCount = 0;int smallCount = 0;int numberCount = 0;//遍歷字符串,得到每一個字符for(int x=0; x<s.length(); x++) {char ch = s.charAt(x);//拿字符進行判斷if(ch>='A'&&ch<='Z') {bigCount++;}else if(ch>='a'&&ch<='z') {smallCount++;}else if(ch>='0'&&ch<='9') {numberCount++;}else {System.out.println("該字符"+ch+"非法");}}System.out.println("大寫字符:"+bigCount+"個");System.out.println("小寫字符:"+smallCount+"個");System.out.println("數字字符:"+numberCount+"個");} }1.10 字符串拼接:+
public class StringTest1 {public static void main(String[] args) {int[] arr = {1, 2, 3};String s = arrayToString(arr);System.out.println("s:" + s); //s:[1#2#3]}/** 寫方法實現把數組中的元素按照指定的格式拼接成一個字符串* 兩個明確:返回值類型:String。 參數列表:int[] arr*/public static String arrayToString(int[] arr) {//String s = new String("[");String s="[";// 遍歷數組,并拼接字符串for (int x = 0; x < arr.length; x++) {if (x == arr.length - 1) {s = s+arr[x]+"]";} else {s = s+arr[x]+"#";}}return s;} }1.11 字符串反轉:i- -
public class StringTest05 {public static void main(String[] args) {//鍵盤錄入一個字符串,用 Scanner 實現Scanner sc = new Scanner(System.in);System.out.println("請輸入一個字符串:");String line = sc.nextLine();String s = reverse(line); //調用方法,用一個變量接收結果System.out.println("s:" + s); //輸出結果}// 兩個明確:返回值類型:String。參數:String s public static String reverse(String s) {//在方法中把字符串倒著遍歷,然后把每一個得到的字符拼接成一個字符串并返回String ss = "";for(int i=s.length()-1; i>=0; i--) {ss += s.charAt(i);}return ss;} }1.12 空字符串判斷:.intern()
/** (1)常量 + 常量 在常量池* (2)變量 +常量 在堆* (3)變量 + 變量 在堆* (4)xx.intern():在常量池* * 空字符串:(1)""* (2)new String()* (3)new String("")* * 四種判空方式:(1)if(str != null && str.length() == 0)* (2)if(str != null && str.equals("")){* (3)if("".equals(str)) 推薦* (4)if(str!=null && str.isEmpty())* /2.StringBuilder類:線程不安全但速度快于stringbuffer(線程安全即每個方法上都加synchronized,效率低,拋棄)
StringBuilder又稱為可變字符序列,它是一個類似于 String 的字符串緩沖區,通過某些方法調用可以改變該序列的長度和內容。String類(內容是不可變的),StringBuilder類(內容和長度是可變的,將任意數據都轉成字符串進行存儲)。
StringBuilder和數組最大的不同就是數組存儲完可以單獨操作每一個元素,每一個元素都是獨立的。字符串緩沖區,所有存儲的元素都會被轉成字符串,而且變成了一個更長的字符串。
2.1 構造方法:new StringBuilder(" ")
public class StringBuilderDemo {public static void main(String[] args) {StringBuilder sb1 = new StringBuilder();System.out.println(sb1); // (空白)//使用帶參構造 public StringBuilder(String str)StringBuilder sb2 = new StringBuilder("itcast");System.out.println(sb2); // itcast} }2.2 append方法:StringBuilder已經覆蓋重寫了Object當中的toString方法
append方法具有多種重載形式,可以接收任意類型的參數。任何數據作為參數都會將對應的字符串內容添加到StringBuilder中。
public class Demo02StringBuilder {public static void main(String[] args) {StringBuilder builder = new StringBuilder(); //創建對象StringBuilder builder2 = builder.append("hello");System.out.println("builder:"+builder); //builder:helloSystem.out.println("builder2:"+builder2); //builder2:helloSystem.out.println(builder == builder2); //true// 可以添加 任何類型builder.append("hello");builder.append("world");builder.append(true);builder.append(100);// 在我們開發中,會遇到調用一個方法后,返回一個對象的情況。然后使用返回的對象繼續調用方法。// 這種時候,我們就可以把代碼現在一起,如append方法一樣,代碼如下builder.append("hello").append("world").append(true).append(100); //鏈式編程System.out.println("builder:"+builder); //builder:hellohelloworldtrue100helloworldtrue100} }2.3 toString方法:StringBuilder對象將會轉換為不可變的String對象
public class Demo16StringBuilder {public static void main(String[] args) {StringBuilder sb = new StringBuilder("Hello").append("World").append("Java");String str = sb.toString();System.out.println(str); // HelloWorldJava} }2.4 reverse方法:.reverse()
public class Demo16StringBuilder {public static void main(String[] args) { //public StringBuilder reverse():返回相反的字符序列StringBuilder sb = new StringBuilder("Hello").append("World").append("Java");sb.reverse();System.out.println("sb:" + sb); //sb:avaJdlroWolleH} }2.5 StringBuilder和String相互轉換:toString()
public class StringBuilderDemo02 {public static void main(String[] args) { //111111111111111111111StringBuilder轉換為StringStringBuilder sb = new StringBuilder();sb.append("hello");//String s = sb; //這個是錯誤的做法 String s = sb.toString(); System.out.println(s); //hello//111111111111111111String轉換為StringBuilderString s = "hello";//StringBuilder sb = s; //這個是錯誤的做法StringBuilder sb = new StringBuilder(s);//public StringBuilder(String s):通過構造方法就可以實現把 String 轉換為 StringBuilderSystem.out.println(sb); //hello} }2.6 字符串拼接:定義一個方法將int[] arr = {1,2,3}輸出為:[1, 2, 3]
/*1:定義一個 int 類型的數組,用靜態初始化完成數組元素的初始化2:定義一個方法,用于把 int 數組中的數據按照指定格式拼接成一個字符串返回。返回值類型 String,參數列表 int[] arr3:在方法中用 StringBuilder 按照要求進行拼接,并把結果轉成 String 返回4:調用方法,用一個變量接收結果5:輸出結果*/ public class StringBuilderTest01 {public static void main(String[] args) { int[] arr = {1, 2, 3};//定義一個 int 類型的數組,用靜態初始化完成數組元素的初始化System.out.println(arr); //[I@14ae5a5String s = arrayToString(arr);System.out.println("s:" + s); //s:[1, 2, 3]}// 兩個明確:返回值類型:String 參數:int[] arrpublic static String arrayToString(int[] arr) {//在方法中用 StringBuilder 按照要求進行拼接,并把結果轉成 String 返回StringBuilder sb = new StringBuilder();sb.append("[");for(int i=0; i<arr.length; i++) {if(i == arr.length-1) {sb.append(arr[i]);} else {sb.append(arr[i]).append(", ");}}sb.append("]");String s = sb.toString();return s;} }2.7 字符串反轉:返回值類型:String , 參數:String s
public class StringBuilderTest02 {public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("請輸入一個字符串:");String line = sc.nextLine();String s = myReverse(line);System.out.println("s:" + s);}public static String myReverse(String s) {//在方法中用StringBuilder實現字符串的反轉,并把結果轉成String返回//String --- StringBuilder --- reverse() --- String // StringBuilder sb = new StringBuilder(s); // sb.reverse(); // String ss = sb.toString(); // return ss;return new StringBuilder(s).reverse().toString();} }3.ArrayList類:ArrayList list = new ArrayList()
3.1 引入—對象數組:基本數據類型變量只保存基本數據類型,不能保存對象。引用數據類型變量是可保存對象,但只能保存一個對象
package cn.itcast.sh.demo;public class Student {String name;int age; public Student(String name, int age) { //定義構造函數給屬性初始化值this.name = name;this.age = age;} public String getName() { //給屬性生成get和set方法return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;} } package cn.itcast.sh.demo;public class ArrayDemo {public static void main(String[] args) { Student[] arr=new Student[3]; //創建Student類型的數組 Student s1=new Student("heixuanfeng",19); //創建Student類的對象Student s2=new Student("bandao",18);Student s3=new Student("zhujiao",20); arr[0]=s1; //將學生對象存儲到數組中arr[1]=s2;arr[2]=s3;for (int i = 0; i < arr.length; i++) { Student s=arr[i]; //通過數組名和下標取出Student類的數組中的數據 arr[i]System.out.println(s.getName()+"====="+s.getAge());}} }目前只學習了2種存儲數據的容器:變量 、數組。集合容器可解決上面用數組重復代碼太多。
3.2 集合與數組區別:變,只對,不
1)長度:
數組:需要固定長度。
集合:長度可以改變,可以根據保存的數據進行擴容。
2)存儲內容:
數組:可以存儲基本類型數據,還可以存儲引用類型的數據。
集合:只能存儲引用類型的數據,也就是說集合只能存儲類的對象。
3)存儲類型:
數組:只能存儲相同類型的數據。
集合:可以存儲不同類型的數據。
3.3 ArrayList類使用:public ArrayList() 構造一個內容為空的集合
java.util.ArrayList <E> : <E> 表示一種指定的數據類型,叫做泛型。E 取自Element(元素)的首字母。在出現E 的地方,我們使用一種引用數據類型將其替換即可,表示我們將存儲哪種引用類型的元素。
ArrayList<String>,ArrayList<Student>JDK 7后,右側泛型的尖括號之內可以留空,但是<>仍然要寫。簡化格式:
ArrayList<String> list = new ArrayList<>();成員方法: public boolean add(E e) : 將指定的元素添加到此集合的尾部。參數 E e ,在構造ArrayList對象時,<E>指定了什么數據類型,那么add(E e)方法中只能添加什么數據類型的對象。
//需求:使用ArrayList類,存儲三個字符串元素 public class Test02StudentArrayList {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>(); //創建集合對象String s1 = "曹操";String s2 = "劉備";String s3 = "孫權"; System.out.println(list); //[] //打印ArrayList集合list.add(s1);list.add(s2);list.add(s3);System.out.println(list); //[曹操, 劉備, 孫權]} }3.4 常用方法和遍歷:對于元素的操作:增、刪、查
public class Demo01ArrayListMethod {public static void main(String[] args) {ArrayList<String> list = new ArrayList<String>();list.add("hello");list.add("world");list.add("java");//public E get(int index):返回指定索引處的元素System.out.println("get:"+list.get(0)); //get:helloSystem.out.println("get:"+list.get(1)); //get:worldSystem.out.println("get:"+list.get(2)); //get:java//public int size():返回集合中的元素的個數System.out.println("size:"+list.size()); //size:3//public E remove(int index):刪除指定索引處的元素,返回被刪除的元素System.out.println("remove:"+list.remove(0)); //remove:hellofor(int i = 0; i < list.size(); i++){System.out.println(list.get(i)); //world java}} }4.Object類:對象都需重寫
package com.itheima00.question;public class Demo01 {public static void main(String[] args) { // C c = new C(); // c.method02(); // 可以 //static,final修飾的方法都是可以被繼承,但不能重寫 // c.method01(); // 錯誤 //interface靜態方法不能被繼承,但是class靜態方法可以被繼承B b = new C(); //向上轉型,靜態和對象無關,屬于類的。所以面向對象三大特性和靜態無關// B b = null;這樣寫下行也一樣,因為和對象無關b.method02(); //b method02,不是c method02 (多態), 靜態 和 多態 沖突了} }//111111111111111111111111111111111111111111111111111111111111111111111111111 interface A{static void method01(){ //接口中靜態方法不能繼承,肯定不能重寫} }class B{static int i;static void method02(){//類中靜態方法可以繼承,但不能重寫(原因: 靜態方法屬于類的->重寫就多態沖突了,如上b.method02();)System.out.println("b method02");} }class C extends B implements A{static void method04(){System.out.println("c method02");}void method03(){ //如下都可以,但注意權限問題super.method02();System.out.println(i);} }4.1 toString方法:Object中的tostring方法: 對象類型包名類名 + 內存地址
package com.itheima01.object; import java.util.ArrayList; /* * Object類 : 所有類除Object本身之外(包括數組)的父類是Object * 1. String toString() 返回該對象的字符串表示。 * 2. boolean equals(Object obj) 指示其他某個對象是否與此對象“相等”。 * * toString方法: * 1. 結論: 如果直接打印對象,調用這個對象的toString方法* println(String s) : s會被直接打印* println(Object obj) 源碼* (obj == null) ? "null" : obj.toString(); 判空 : 避免空指針異常 2. 運用:* 1. 打印對象內存地址是沒有意義, 想要打印對象的屬性值 (方便測試)* 2. 解決: 這個類重寫toString方法*/ public class ObjectDemo01 {public static void main(String[] args) { // method01(); // Person p = new Person();Person p = new Person("zs",18);System.out.println(p); //com.itheima01.object.Person@1540e19d 類型包名類名+ 內存地址System.out.println(p.toString()); //同上 //類中重寫了toString方法后,p和p.toString()兩個都打印出:Person{name='zs',age=18}ArrayList<String> list = new ArrayList<>();list.add("zs");list.add("ls");list.add("ww"); //打印引用類型,如果打印的不是內存地址,說明重寫了toStringSystem.out.println(list.toString()); // [zs,ls,ww]}public static void method01(){int[] array = {1,2,3};System.out.println(array.length); //3String json = array.toString();boolean result = array instanceof Object; //驗證數組的父類是不是ObjectSystem.out.println(result); //true} }//111111111111111111111111111111111111111111111111111111111111111111 class Person{String name;int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}/* @Overridepublic String toString() { // return super.toString();String msg = "name:" + name + ",age=" + age;return msg;}*///快捷鍵: alt + insert -> toString 效果如下@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';} }4.2 equals方法:Object類中的equals方法是==比較內存地址
package com.itheima01.object; import java.util.Objects; /* * == : java只有值傳遞,所以==不管是比較基本數據類型還是引用數據類型變量,本質比較的都是值,只是引用數據 類型變量存的值是對象地址 * * 1. 比較內存地址已經有== , equals這樣設計沒有意義的 * 2. 想要比較兩個對象的屬性(包括身份證號)是否完全一致 , 實際推斷為是同一對象 * (實際含義和java內存含義不一樣,雖然各自new內存不一樣) * * 解決: 重寫equals (兩個對象逐一比較每個屬性,如果兩個對象每個屬性都相同,返回true,否則返回false) * 快捷鍵: alt + insert -> equals and hashcode。 equals最主要運用: 哈希表 */ public class ObjectDemo02 { public static void main(String[] args) {Student s1 = new Student("zs", 18);Student s2 = new Student("zs", 18);System.out.println(s1 == s2);//false:引用類型比較的是內存地址(new出來的內存地址肯定不一樣)System.out.println(s1.equals(s2)); // false同上,比較的是內存地址,如下重寫equals()后為true} }//1111111111111111111111111111111111111111111111111111111111111111111 class Student{String name;int age;public Student(String name, int age) {this.name = name;this.age = age;} @Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}/*this : s1obj : s2name ,age -> Student*//* @Overridepublic boolean equals(Object obj) {boolean result = obj instanceof Student; //如果是學生類型才繼續往下走//boolean result = this.getClass() == obj.getClass();//源碼中這樣寫,同上 if (!result){ //如果你傳入不是student類型, 兩個絕不一樣,直接return falsereturn false; //result為false時,!result為true進入if內return false} Student s2 = (Student) obj; //向下轉型: 調用子類特有屬性和方法boolean result2 = this.name.equals(s2.name); if(!result2){return false;} return this.age == s2.age;}*/@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age &&Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);} } public class test1 {public static void main(String[] args) {String a = new String("ab"); // a 為一個引用String b = new String("ab"); // b為另一個引用,對象的內容一樣String aa = "ab"; // 放在常量池中String bb = "ab"; // 從常量池中查找if (aa == bb) // trueSystem.out.println("aa==bb");if (a == b) // false,非同一對象System.out.println("a==b");if (a.equals(b)) // true //因為a為String,String中的equals方法是被重寫過(比較對象的值)System.out.println("aEQb");if (42 == 42.0) { // trueSystem.out.println("true");}} }4.3 hashCode方法和equals方法:兩個對象hashCode方法返回值相同,那么這兩個是否equals?或者兩個對象equals,那么hashCode方法返回值是否相同?
兩個方法沒有任何聯系,因為我們可隨意重寫這兩個方法如上,但是重寫這兩個方法時應該滿足下面3個規范:1.對于同一個對象,沒有任何屬性變化:則多次求hashCode返回值應該是相同的,多次和另一個對象equals比較,返回值也應相同。如下random隨機不穩定不符合規范。2.equals源碼決定。3.hashmap存儲結構決定,如下第二張圖不符合第3個規范。
4.3.1 為什么要有如上這樣的規范?牽扯到一系列hash存儲
如下以hashmap為例,在hashmap中通過hashcode計算得到出的值就是數組的下標,例如下標=1,就在1這個桶中找對于元素,1這個桶可能存儲的是鏈表或紅黑樹,假如是鏈表,就要在這個鏈式存儲中挨個查找是否是我們想要的元素,挨個查找的時候我們需要equals方法對比每個節點的key和我們需要找的key是否equals。
所以如果hashcode值不穩定,那么每次查找時就打到不同桶里面。如果兩個對象equals但hashcode不相等就會導致兩次求index下標時求得不同下標。
4.3.2 hashCode擴展:重寫hashcode方法不會在對象頭中進行存儲,對象頭中31bit永遠是0
1.無鎖對象的對象頭中有31個bit用來存儲hashcode(int是4字節是32bit),hashcode是31bit,因為缺少了一個符號位,也就是說全是正數或0。
2.java中對象的引用是4個字節的即32bit,所以hashcode返回值31bit顯然對應不了,因而hashcode返回值肯定不是對象地址。
總結
以上是生活随笔為你收集整理的【Java5】String类,StringBuilder类,ArrayList类,Object类(toString,equals,hashCode)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java4】实例初始化,类初始化,/接
- 下一篇: 【Java6】Date类/Calenda