201521123091 《Java程序設計》第2周學習總結


Java 第二周總結

第二周的作業。

一個簡陋的目錄
1.本章學習總結
2.Java Q&A
3.使用碼雲管理Java代碼
4.PTA實驗
5.小任務


1.本章學習總結

基本數據類型

  • String類
  • Java的標准輸入輸出和文件輸入輸出
  • Java控制執行流程
  • Java數組的使用
  • 類管理機制:包

2.Java Q&A

1.使用Eclipse關聯jdk源代碼(截圖),並查看String對象的源代碼?簡單分析String對象的設計思路。

  1. 從“Window (菜單項目)”上選擇“Preferences (菜單項目)”
  2. 展開“Java (框線項目)”(位於“Preferences”中)
  3. 選擇“Installed JREs (框線項目)”(位於“Preferences”中)
  4. 選中當前JRE,並且點擊Edit按鈕
  5. 展開JRE系統庫的第二項,選中展開后的第一項,點擊“Source Attachment”按鈕
  6. 打開JDK目錄,選中src.zip,最后一路確定出去

  7. ctrl+鼠標左鍵選中某一個類,或者選中類之后按F3,源代碼文件彈出,第一問就搞定了

到此為止,只是這一問的第一小問結束了0.0(各位看官不急,我還在碼)

String對象的設計思路(我們可以看到在源代碼文檔里面已經有說了,所以我們要做的僅僅是翻譯一下,當然英文不好的同學(比如我這種),可以借助類似金山詞霸之類的划譯)

我們可以看到就是這點,字符串是常量,往下翻翻我們就會看到private final char value[];,用一個final修飾的字符數組來實現這個字符串的

2.為什么要盡量頻繁的對字符串的修改操作應該是用StringBuilder而不是String?
這個東西我們就有講頭了,不妨來看幾個String類自帶的方法吧。

//這是一個字符串連接的方法
public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
//這是一個替換的方法
public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

在對字符串進行相應修改(例如替換或者是連接)的時候,我們可以發現最后都返回了一個新的字符串常量。所以我們可以想見,如果有大量的字符串拼接的話,那么我們的代碼一定會new出很多的String變量,然后又會有很多的垃圾回收。這樣的話,代碼的效率就會有所降低。

這邊來看個代碼吧(當然是從Thinking in Java上抄下來的。。。)

public class Concatenation{
	public static void main(String[] args) {
		String mango = "mango";
		String s = "abc" + mango + "def" + 47;
		System.out.println(s);
	}
}

然后使用javap進行反匯編看看發生了什么。。。

Compiled from "Concatenation.java"
public class Concatenation {
  public Concatenation();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String mango
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #5                  // String abc
      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      15: aload_1
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      19: ldc           #7                  // String def
      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      24: bipush        47
      26: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      29: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore_2
      33: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      36: aload_2
      37: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      40: return
}

好了,我們看到這個編譯器自動引入了一個叫做StringBuilder的東西,,使用它來進行字符串的拼接。這當然是因為StringBuilder更好了,我們剛才說String是immutable的,那這個StringBuilder是專門為字符串修改而生的,在Java SE5引入。所以編譯器很聰明的對代碼進行了優化。那也就是說,我可以隨意使用String,等着代碼優化嗎?當然不行咯,Java編程思想又給我們舉了個反例,來看看。

哦,對了,在String的源文檔里面有這樣一句話,一樣的意思

String concatenation is implemented through the {@code StringBuilder}(or {@code StringBuffer}) class and its {@code append} method.

利用循環來進行字符串的拼接

//輸入一個n,從0-n的數字轉成字符串進行拼接
public class Main{
	public static void main(String[] args) {
		int n = 5;
		String result1 = "";
		for (int i = 0; i < n; i++) {
			result1 += i;
		}
		System.out.println(result1);
		
		StringBuilder result2 = new StringBuilder();
		for (int i = 0; i < n; i++) {
			result2.append(i);
		}
		System.out.println(result2.toString());
	}
}

我們再來反匯編(* * *大法好,雖然我不是很懂)

Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_5
       1: istore_1
       2: ldc           #2                  // String
       4: astore_2
       5: iconst_0
       6: istore_3
       7: iload_3
       8: iload_1
       9: if_icmpge     37
      12: new           #3                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      19: aload_2
      20: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      23: iload_3
      24: invokevirtual #6                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      27: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_2
      31: iinc          3, 1
      34: goto          7
      37: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      40: aload_2
      41: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      44: new           #3                  // class java/lang/StringBuilder
      47: dup
      48: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      51: astore_3
      52: iconst_0
      53: istore        4
      55: iload         4
      57: iload_1
      58: if_icmpge     74
      61: aload_3
      62: iload         4
      64: invokevirtual #6                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      67: pop
      68: iinc          4, 1
      71: goto          55
      74: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      77: aload_3
      78: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      81: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      84: return
}

代碼中9-34行是第一個循環(用String的那個),我們可以看到,每次循環開始都會new一個StringBuilder變量,58-71行是第二個循環(用StringBuilder的那個),當然是只在我們一開始new了一個。這個循環更簡短,效率當然更高。

3.比較兩個字符串的值是否相等?為什么不能用==直接進行比較?

因為用進行比較並不能保證結果總是正確的(假設下面的情況字符串的內容都是相同的),比較的是兩個對象的引用

  • 首先如果兩個字符串都是以 String xxx = "xxxxx";的方式創建出來的,在第一個字符串如此創建時,JVM就會在字符串池中維護這么一個String的實例,那么以后只要有內容完全相同的字符串,就直接指向這個實例,所以引用會相同

  • 只要有一個是以new的方式創建新的實例,就會創建一個新的對象,當然就有不一樣的引用,所以這時候==的兩邊是不同的引用,當然會返回false

綜上所述,我們要對兩個字符串進行內容的比較的話,我們要選用一種不是==的方法,那就是equals()方法,看下面的具體實現,沒毛病

 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;
}

但是不是所有的equals()方法都是比較內容,我們這邊可以舉個小小的反例

class Value{
	int i;
}



public class EqualsMethod2 {
	public static void main(String[] args) {
		Value v1 = new Value();
		Value v2 = new Value();
		v1.i = v2.i = 100;
		System.out.println(v1.equals(v2));
	}
}

輸出結果是false,這是因為equals()的默認行為是比較引用,只是Java類庫當中的許多類都已經自己實現了equals()方法,顯然我們這邊並沒有重寫這個equals()的方法,所以這邊還是只是比較引用

4.嘗試使用字符串池的概念解釋如下程序段輸出結果,並回答這段代碼創建了幾個字符串對象:

String str1 ="hi", str2="hi";
String str3 = new String(str1);
System.out.println(str1==str2);

最后輸出true
分析在前面已經說過了,一共會有兩個對象,str1創建的時候,字符串池里面會有一個,也就是str2直接指向字符串池中的那個實例。
然后str3在字符串池外面又new了個

5.Integer i = 100;//100是基本類型,i是引用類型,為什么可以將100賦值給i

public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        100
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: return
}

同樣看到反匯編,我們就可以看到只是調用了Integer類的valueOf的方法而已,然后這個方法是public static Integer valueOf(int i)這樣子的,返回一個Integer

6.嘗試分析下面代碼輸出結果

Integer i1 = 127;Integer i2 = 127;
i1 == i2;//true of false?
Integer i1 = 128;Integer i2 = 128;
i1 == i2;//true of false

輸出結果分別是truefalse
上回我們剛剛談到,我們用到了valueOf()這個方法,去給這個Integer進行賦值,so我們需要研究一下這個方法,貼上JDK源碼。

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

!這是什么東西,對於不同的范圍還區別對待?
是這樣的,這個IntegerCache,整數緩存是?再貼源代碼(截取部分)

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

好了,這樣我們就知道了,這個IntegerCache是通過Cache數組來實現的,然后-128-127這256個數就被放在了這個數組里,當我valueOf()方法的參數在這個范圍內的話,我就將數組中的值返回去,也就是說一開始i1和i2都指向了數組的同一位置,所以當然是相等的咯
然后這個128就相當的尷尬了,因為他正好就在這個范圍之外了,所以我們用最朴素的方法創建這個Integer對象,那么就像我們之前所說,通過new來創建的對象具有不同的引用,so傳回了false

7.package與javac、 java、 -classpath、 -d
在 com.ibm包中編寫 StringUtil類,內有一方法

public static void foo1(){
 System.out.println(StringUtil.class+" method:foo1");
}
  • 嘗試用命令行進行編譯並運行,截圖使用javac -d. StringUtil.java使用-d編譯選項,建立了相應的文件,將生成的字節碼放在了\com\ibm下面

編寫Main.java,在第一行加上package edu.jmu,編譯后再次生成相應字節碼文件
然后再用java命令執行,結果如截圖

  • 將生成的StringUtil.class放到d:\lib正確的目錄結構下,將Main.class在d:\test正確的目錄結構,嘗試在命令行下運行,並截圖。
    目錄結構如下所示:
    • D
      • lib
        • com
          • ibm
            • StringUtil.class
      • test
        • edu
          • jmu
            • Main.class

之前用powershell搞了很久,懟不出來。最后換成cmder就成功了

  • Eclipse中源代碼放在哪個目錄、class文件放在哪個目錄。在Eclipse項目中按一下ctrl+f11就可以直接運行Main,嘗試分析背后實現的原理

源代碼放在src里面,class放在bin文件夾中。

8.自己在這門課的目標與計划

  • 請描述一下你的技術基礎(會什么語言,都寫了多少行代碼)

    • C 有上萬嗎,可能有,可能沒有吧
    • Matlab 上一千行,應該是有了
    • Python 上百行
  • 一周准備花多少時間在這門課上?一周准備寫多少行代碼?采用怎樣的學習方式?遇到困難打算怎樣解決?

    • 具體多長時間不清楚,畢竟還得顧着我的藍橋杯
    • 一周寫個一百多行什么的,還是可以的吧,具體的代碼量同樣還是不清楚
    • 遇到困難
      • 百度、谷歌……
      • 看書
      • 問老師
      • 放棄,我不搞了,開玩笑的
  • 關於這門課的smart目標
    首先這個是SMART

S pecific:具體的,無二義性的,能描述 “成功” 是什么樣的。
M otivating: 目標能激發對目標的興趣么?實現目標對學生來說說意味着什么?他們會為之自豪么?
A chievable: 能做到么?是挾泰山以超北海?還是把牆角一堆磚頭搬走?
R elevant: 和學生來到大學的大方向、目標吻合
T rackable: 能衡量進度的,和有些資料提到的 Measurable 相似。

要不就姑且試試Java web?雖然別人說這都是套框架,可是我連框架都不會套……

這讓我想到職業規划的SWOT(S trengths, W eaknesses, O pportunities, T hreats)。那我就分門別類的說下吧。

  • 我覺得對於一門語言來說,怎么算是學成功了呢,應該就是能夠使用這門語言真的做一件有實際用途的事情,可能主要是做開發之類的吧(現在還不是很清楚)
  • 分情況,假如我剛開始學編程的時候,會打printf("%d", a + b);我都會很開心。然而我們不可能總是停留在這個層次,我們總是需要向上走
  • 至於可行性,如果暫且把目標放的低一點,做一些簡單功能的實現,我覺得還是可以的吧,不能一口吃成一個大胖子,也不能推得太慢吧。
  • 沒什么大方向,也沒什么具體的目標吧。很慚愧,感覺還是把現在的事情做好了再說。
  • 沒試過啊,進度什么的先放着吧,要是凡事都能有個進度條就好了,很可惜並不是

話再說回來,很想在這個學期繼續打牢計算機以及數學基礎。不然就可以直接去培訓機構,三個月上崗,而不用來大學了

9.選做:公交卡里應該還有多少錢?請分析原因

-0.1(元)參考騰訊新聞
可能是無符號浮點數下溢了。
不過……
新聞里說是這台閘機的問題,所以其他的閘機肯定是能正常顯示的,那至於這個為什么不對,就不清楚了。

3.使用碼雲管理Java代碼


4.PTA實驗

  • 第一題,是函數調用,就是要注意需要sort的數組需要在循環輸入選項的代碼塊外面就創建,如果在sort數組里面臨時創建,當然其它選項是找不到的啦
  • 第二題,StringBuilder類的基本使用,就是一開始的時間限制壓得很死,所以一會能A,一會又不能A。
  • 第三題,就是要自己去實現一下Comparator,然后就很流暢了
  • 第四題,for循環也可以,就是要一個二維數組,因為數據量不是很大,所以我是直接初始化了
  • 第五題,使用BigDecimal類來實現浮點數的精准計算,當然也可以用數組的方式來實現。不過既然有現成的,就用現成的好了
  • 第六題,枚舉的基本使用
  • 第七題,可以用BigInteger實現的東西,就是學會用
  • 第八題,ArrayList的基本使用,相當於數據結構中提到的鏈表

5.小任務

代碼有點丑陋……不過效果還行吧

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;

public class Main {
	//用來找第一個不是空格的字符
	private static int firstCharNotSpace(String string) {
		int i;
		for (i = 0; i < string.length(); i++) {
			if (string.charAt(i) != ' ') {
				break;
			}
		}
		return i;
	}
	//如果是ABCD或是數字啥的,那么前面有空格就要刪
	private static Boolean needToDeleteSpace(char ch) {
		if (Character.isDigit(ch) || ch >= 'A' && ch <= 'D') {
			return true;
		}
		return false;
	}
	public static void main(String[] args) throws FileNotFoundException {
		Scanner sc = new Scanner(new File("C:/Users/LJL36/Desktop/choice.txt"));
	    PrintWriter printWriter = new PrintWriter("C:/Users/LJL36/Desktop/output.txt");
	    int res = 0;//記錄有多少道題目
	    
	    //這邊很蠢的先統計了一下題目
	    while (sc.hasNextLine()) {
	    	String string = sc.nextLine();
	    	if (string.trim().length() == 0) {
	    		continue;
	    	}
	    	int index = firstCharNotSpace(string);
	    	if (Character.isDigit(string.charAt(index))) {
	    		res++;
			}
		}
	    printWriter.println(res);
	    
	    //重新打開文件
	    sc = new Scanner(new File("C:/Users/LJL36/Desktop/choice.txt"));
	    while(sc.hasNextLine()){
	    	StringBuilder stringBuilder = new StringBuilder(sc.nextLine());
	    	String string = stringBuilder.toString();
	    	//如果是空格串,就跳過
	    	if (string.trim().length() == 0) {
				continue;
			}
	    	//刪空格
	    	int index = firstCharNotSpace(string);
	    	if (needToDeleteSpace(string.charAt(index))) {
				stringBuilder.delete(0, index);
			}
	    	
	    	//將答案在后面用pta要求格式輸出
	    	index = string.lastIndexOf('。');
	    	if (index != -1 && index != string.length()) {
	    		boolean flag = false;
	    		String string2 = "@[";
	    		for (int i = index + 1; i < string.length(); i++) {
	    			if (Character.isLetter(string.charAt(i))) {
	    				flag = true;
						string2 += Character.toUpperCase(string.charAt(i));
					}
	    		}
	    		string2 += "](2)";
	    		
	    		stringBuilder.delete(index + 1, string.length());
	    		
	    		if (flag) {
	    			stringBuilder.append(string2);
				}
	    	}
	    		
	    	stringBuilder.append("  ");
	    	printWriter.println(stringBuilder.toString());
	    }
	    sc.close();
	    printWriter.close();
	}
}

下面貼一下最后的運行結果

看的不過癮的請點下面
回到頂部


最后總是要說句廢話什么的,有同學和我說我的排版太丑陋了。嗯……我只能顧上眼前的苟且了,非常感謝偷偷看我博客的同學,可是能不能粉我一下,我也會回粉你們的,謝謝~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM