【Java】練習 - Object類、Stringle類,一些其他類的常用API

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面試題精選集

JavaSE 練習題

從Hello到goodbye

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章