文章目錄
- 1、Object類equals方法與String的equals方法
- 2、Object類的toString方法
- 3、Object類equals方法
- 4、StringBuilder類與String類的區別
- 5、String、StringBuilder、StringBuffer的區別是什麼?
- 問:String對象的intern()是指什麼?
- 6、Date類的使用
- 7、DateFormat類方法的使用
- 8、Calendar類方法的使用
- 9、System類arraycopy方法的使用
- 10、StringBuilder類的使用
- StringBuilder類的使用(reverse()方法)
- StringBuilder類的使用
- 參考資料
1、Object類equals方法與String的equals方法
一、簡述String類中的equals方法與Object類中的equals方法的不同點。
答:String類中的equals方法是用來判斷兩個對象的內容是否相同,而Object 類中的equals方法是用來判斷兩個對象是否是同一個對象,所謂同一個對象指的是內存中的同一塊存儲空間。
String的equals用來判斷兩個對象的內容是否相同,而Object的equals方法是用來判斷是否爲同一個對象。
String類中的equals 相同字符串返回爲true
JDK11源碼
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
object類中的equlas 是否是同一對象
public boolean equals(Object obj) {
return (this == obj);
}
2、Object類的toString方法
二、不運行代碼,直接說出打印結果,並解釋原因。
public class ToStringTest {
static int i = 1;
public static void main(String args[]) {
System.out.println("love " + new ToStringTest());//love java
ToStringTest a = new ToStringTest();
a.i++;
System.out.println("me " + a.i);//me 2
}
public String toString() {
System.out.print("I ");//I
return "java ";
}
}
我先運行下確認下是否和我想得一致,打印結果,爲什麼呢?不懂。。。
I先打印 I love java
I love java
me 2
爲什麼呢?
原因:當執行代碼的時候,首先加載靜態變量,然後執行main方法,由於main方法內部第一行代碼爲輸出語句,裏面new了此類對象,當執行此行代碼時會先創建了本類的對象,由於此類重寫了toString方法,會先執行toString方法的打印輸出,然後返回“java ”,再執行main方法第一行打印輸出。在Java中“System.out.println(類對象名);”實際輸出的是該對象的toString()方法返回的字符串,即括號中的內容等價於類對象名.toString(),toString方法的好處是在碰到println方法的時候會被自動調用,不用顯示的寫出來。靜態變量i++爲2。
public class ToStringTest {
static int i = 1;
public static void main(String args[]) {
System.out.println("hello world");//hello world
System.out.println("love " + new ToStringTest());//love java
ToStringTest a = new ToStringTest();
a.i++;
System.out.println("me " + a.i);//me 2
//Result
//hello world
//ToStringTest的無參構造
//I love java
//ToStringTest的無參構造
//me 2
}
public ToStringTest() {
System.out.println("ToStringTest的無參構造");
}
public String toString() {
System.out.print("I ");//I
return "java ";
}
}
執行一行輸出語句,裏面new了此類對象,當執行此行代碼時會先創建了本類的對象調用構造函數,由於此類重寫了toString方法,會先執行toString方法的打印輸出,然後返回“java ”,再執行main方法第一行打印輸出。
ToStringTest的無參構造
I love java
先new再toString
3、Object類equals方法
三、看下列程序,不運行說結果,寫出答案後,並在IntelliJ IDEA中運行看看自己給的答案與運行結果是否正確,並分析原因。
(1)
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); //false
System.out.println(s1.equals(s2)); //true
==引用類型String比較引用,String類中的equals方法是用來判斷兩個對象的內容是否相同。
s1在常量池中
s2首先指向堆中的一個字符串對象,然後堆中字符串的value數組指向常量池中常量對象的value數組
(2)
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true
(3)
String s1 = "a" + "b" + "c";
String s2 = "abc";
System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true
拼接的結果在堆還是在常量池?
因爲只有常量池中才是共享,==比較才爲true
原則:
(1)常量+常量:結果是常量池
(2)常量與變量 或 變量與變量:結果是堆
(3)拼接後調用intern方法:結果在常量池 xx.intern()
(4)
String s1 = "ab";
String s2 = "abc";
String s3 = s1 + "c";
System.out.println(s3 == s2); //false
System.out.println(s3.equals(s2)); //true
4、StringBuilder類與String類的區別
四、簡述StringBuilder類與String類的區別。
答:String類的對象內容不可改變,所以每當進行字符串拼接時,總是會在內存中創建一個新的對象,所以經常改變內容的字符串最好不要用String,因爲每次生成對象都會對系統性能產生影響。
StringBuilder又稱爲可變字符序列,是JDK5.0中新增加的一個類,它是一個類似於String的字符串緩衝區,通過某些方法調用可以改變該序列的長度和內容。即它是一個容器,容器中可以裝很多字符串,並且能夠對其中的字符串進行各種操作。它的內部擁有一個數組用來存放字符串內容,進行字符串拼接時,直接在數組中加入新內容,StringBuilder會自動維護數組的擴容。
Q1:String是最基本的數據類型嗎?
A:
不是,Java基本數據類型只有8種,byte、short、int、long、float、double、char、boolean。
String(確實最常用)
5、String、StringBuilder、StringBuffer的區別是什麼?
Q2:“String、StringBuilder、StringBuffer的區別是什麼?”
A2:
1、可變性。String不可變,StringBuilder與StringBuffer是可變的。
String類中使用只讀字符數組保存字符串,private final char value[],所以是不可變的(Java 9 中底層把 char 數組換成了 byte 數組,佔用更少的空間)。
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,char[]value,這兩種對象都是可變的。
可變性 String不可變 StringBuilder與StringBuffer是可變的
2、線程安全性。String和StrinbBuffer是線程安全的,StringBuilder是非線程安全的。
String線程安全是因爲其對象是不可變的,StringBuffer線程安全是因爲對方法加了同步鎖或者對調用的方法加了同步鎖。
StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。
線程安全性 String和StringBuffer是線程安全的
StringBuilder是非線程安全的
3、性能。
String的性能較差,因爲每次對String 類型進行改變的時候,都會生成一個新的String對象,然後將指針指向新的String 對象。
而StringBuffer/StringBuilder性能更高,是因爲每次都是對對象本身進行操作,而不是生成新的對象並改變對象引用。一般情況下StringBuilder 相比StringBuffer 可獲得10%~15% 左右的性能提升。
String StringBuilder StringBuffer
一般的答案是可變性與線程安全性的差別,但其實性能也是很重要的一個點。回答到這個點上,說明對性能比較敏感,有承擔大型網站架構的高可用、高性能方面的潛力。
如果要操作少量的數據用String;
單線程操作字符串緩衝區下操作大量數據StringBuilder;
多線程操作字符串緩衝區下操作大量數據StringBuffer;
問:String對象的intern()是指什麼?
參考答案:
intern()方法會首先從常量池中查找是否存在該常量值,如果常量池中不存在則現在常量池中創建,如果已經存在則直接返回. 比如 String s1=“aa”; String s2=s1.intern(); System.out.print(s1==s2);//返回true
6、Date類的使用
六、請用代碼實現:獲取當前的日期,並把這個日期轉換爲指定格式的字符串,如2088-08-08 08:08:08。
public class DateTest {
public static void main(String[] args) {
//獲取當前日期對象 now;
Date now = new Date();
//創建SimpleDateFormat對象 df,並制定日期格式
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//調用df的format(Date date) 方法,傳入now; 接收返回的字符串
String datestr = df.format(now);
//打印這個字符串
System.out.println(datestr);//2020-05-25 09:44:12
}
}
7、DateFormat類方法的使用
七、使用SimpleDateFormat類,把2018-03-04轉換爲2018年03月04日。
public class DateFormatTest {
public static void main(String[] args) throws ParseException {
//創建SimpleDateFormat對象df1,指定日期模式爲yyyy-MM-dd
SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
//調用df1的parse(String str)方法傳入2018-03-04,得到對應日期類型
Date date = df1.parse("2018-03-04");
//創建日期格式化對象df2,在獲取格式化對象時可以指定風格
DateFormat df2 = new SimpleDateFormat("yyyy年MM月dd日");
//調用df2的format(Date date) 傳入剛纔轉換的日期
String str = df2.format(date);
System.out.println(str);//2018年03月04日
}
}
8、Calendar類方法的使用
八、用程序判斷2018年2月14日是星期幾。
public class CalendarTest01 {
public static void main(String[] args) {
//創建Calendar對象
Calendar c = Calendar.getInstance();
//將給定的日曆字段設置到Calendar對象中
c.set(Calendar.YEAR, 2018);
c.set(Calendar.MONTH, 1);
c.set(Calendar.DATE, 14);
//設置年
int year = c.get(Calendar.YEAR);
//設置月
int month = c.get(Calendar.MONTH) + 1;
//設置日
int date = c.get(Calendar.DATE);
//設置星期
char week = getWeek(c.get(Calendar.DAY_OF_WEEK));
//輸出結果
System.out.println(year + "年" + month + "月" + date + "日是星期" + week);
//2018年2月14日是星期三
}
//定義方法,獲取星期漢字
public static char getWeek(int a) {
char[] c = {' ', '日', '一', '二', '三', '四', '五', '六'};
return c[a];
}
}
9、System類arraycopy方法的使用
九、現有一個字符數組 {‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ‘w’, ‘o’, ‘r’, ‘a’, ‘d’},請使用System類中的arraycopy()方法在控制檯輸出“helloworld”。(提示:將[2]號數組元素複製到最後的第二個位置並覆蓋原有元素。
public class ArraycopyTest {
public static void main(String[] args) {
char[] cha = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'a', 'd'};
//將cha數組中第3個元素,複製到目標數組最後的第二位數組上
System.arraycopy(cha, 2, cha, 8, 1);
//遍歷目標數組,在控制檯輸出字符串
for (int i = 0; i < cha.length; i++) {
System.out.print(cha[i]);
}
//helloworld
}
}
10、StringBuilder類的使用
10、請使用代碼實現
分別使用String的 += 和StringBuilder的append方法對字符串做100000次拼接,計算String拼接100000次花費時間與StringBuilder拼接100000次所花費時間並打印。
public class StringBuilder01 {
public static void main(String[] args) {
//使用System的currentTimeMillis()方法獲取當前操作系統的毫秒值,作用程序執行的開始時間,使用start變量接收
long start = System.currentTimeMillis();
//需要測試執行性能的代碼
//testString(); //消耗時間: 29295毫秒
testStringBuilder();//消耗時間:6毫秒
//使用System的currentTimeMillis()方法獲取當前操作系統的毫秒值,作用程序執行的結束時間,使用end變量接收
long end = System.currentTimeMillis();
//計算代碼執行花費的時間 end - start,輸出代碼執行消耗的時間
System.out.println("所花費的時間爲:" + (end - start));
}
//寫一個靜態方法: testString(),在該方法中
public static void testString() {
//定義一個字符串 str,內容隨意
String str = "hello";
//寫一個循環100000次for循環,在循環中寫上
for (int i = 0; i < 100000; i++) {
//str +=”隨機內容” ; 這裏不要寫str += (str+”xxx”) 這樣會導致堆內存溢出錯誤.
str += "world";
}
}
//寫一個靜態方法:testStringBuilder(),在方法中
public static void testStringBuilder() {
//創建一個StringBuilder對象sb,初始內容與testString()中的字符串相同
StringBuilder sb = new StringBuilder("hello");
//寫一個循環100000次for循環,在循環中寫上
for (int i = 0; i < 100000; i++) {
//調用sb.append()方法,傳入的內容與testString()方法中+=後面的內容一樣
sb.append("world");
}
//循環結束調用sb.toString()方法轉換爲字符串
String newStr = sb.toString();
}
}
StringBuilder類的使用(reverse()方法)
十、分析以下需求,並用代碼實現:
(1)定義數字字符串數組{“010”,“3223”,“666”,“7890987”,“123123”};
(2)判斷該數字字符串數組中的數字字符串是否是對稱(第一個數字和最後一個數字相等,第二個數字和倒數第二個數字是相等的,依次類推)的,並逐個輸出;
(3)如:010 是對稱的,3223 是對稱的,123123 不是對稱的;
(4)最終打印該數組中對稱字符串的個數。
注:判斷對稱可用reverse(),將此字符序列用其反轉形式取代。
public class StringBuilderTest02 {
public static void main(String[] args) throws IOException {
//定義數字字符串數組
String[] str = {"010", "3223", "666", "7890987", "123123"};
SBTest(str);
//Result
//010是對稱的
//3223是對稱的
//666是對稱的
//7890987是對稱的
//總數爲4
}
public static void SBTest(String[] str) {
int count = 0;
//遍歷定義的字符串數組
for (String string : str) {
//創建StringBuilder對象
StringBuilder sb = new StringBuilder(string);
//調用reverse()方法,將遍歷的數字進行反轉,然後用equals()方法對比是否與原數字相同
if (sb.reverse().toString().equals(string)) {
count++;
System.out.println(string + "是對稱的");
}
}
System.out.println("總數爲" + count);
}
}
StringBuilder類的使用
十一、分析以下需求,並用代碼實現:
(1)打印由7,8,9三個數組成的三位數,要求該三位數中任意兩位數字不能相同;
(2)打印格式最後的三位數字以空格分隔,如789 798 879 897 978 987。
注:要求使用StringBuilder來完成
public class StringBuilderTest03 {
public static void main(String[] args) throws IOException, Exception {
SBTest();
//789 897 978 879 798 987
}
public static void SBTest() {
//定義由7、8、9組成的字符串
String s = "789";
//創建StringBuilder對象
StringBuilder sb = new StringBuilder();
//採用嵌套for循環,遍歷字符串
for (int i = 0; i < 3; i++) {
//遍歷字符串s,把字符依次添加到StringBuilder內,組成一個元素
for (int j = 0; j < s.length(); j++) {
sb.append(s.charAt(j));
}
//當StringBuilder內元素爲一個和兩個時,
if (i != 2) {
sb.append(" ");
}
//把字符串s的第一個元素切割,添加到字符串末位,組成新的字符串
s = s.substring(1).concat(s.substring(0, 1));
}
// 把StringBuilder內元素反轉,組成新的數字
s = sb.toString() + " " + sb.reverse().toString();
System.out.println(s);
}
}
參考資料
記錄 - 搞定Java核心技術
高薪之路–Java面試題精選集
從Hello到goodbye