StackOverflow 周報 - 高質量問題的問答(Java、Python)


這是 Stack Overflow 第三周周報,本周加入了 Python 的內容,原計划兩篇 Java、兩篇 Python。但明天過節所以今天就先把周報發了,兩篇 Java、一篇 Python。公眾號「渡碼」為日更,歡迎關注。

DAY1. 使用隨機數打印"hello world"

今天我們看一個有意思的例子,看看下面的代碼為什么每次運行都能輸出 "hello world"。

public static String randomString(int i) {
    Random ran = new Random(i);
    StringBuilder sb = new StringBuilder();
    while (true) {
        int k = ran.nextInt(27);
        System.out.println(k);
        if (k == 0) {
            break;
        }
        sb.append((char)('`' + k));
    }
    return sb.toString();
}

調用代碼:

System.out.println(randomString(-229985452) + " " + randomString(-147909649));

 

我們不禁會想,生成隨機數不是隨機嗎,為什么每次運行結果都一樣。

要解釋這個問題,我們需要了解 “偽隨機” 的概念。只要隨機數是由確定的算法生成的,那就是偽隨機,也就是說它的生成看似隨機但是有一定規律的。而“真隨機”需要真實的隨機事件取得,所以計算機只能生成偽隨機數。

知道了“偽隨機”概念,今天的例子就好解釋了。在之前的文章中我們看過生成隨機數的代碼,是根據當前種子(seed)通過特定的規則(算法)生成隨機數並更新種子,因此 Random 生成的隨機數是“偽隨機”數。此外我們都知道算法有個特性叫確定性,也就是說相同的輸入只能得出相同的輸出。對於生成隨機數這個算法來說,每次調用只要初始種子(seed)不變,那么一定會生成相同的隨機數。這就解釋了,為什么每次執行生成的隨機數序列都是一樣的。

最后,生成的 int 類型隨機數 k,通過 (char)('`' + k) 這行代碼轉成字符,這里用到的是 ASCII 碼相關的知識,不再贅述。

今天通過這個簡單的例子了解了偽隨機的概念。歡迎交流,關注公眾號每天分享一個知識點。

原文地址

DAY2. Java 嵌套類的兩種形式

Java 中嵌套類有兩種形式,官方定義為:如果嵌套類為靜態的,則稱為靜態嵌套類,如果是非靜態的則稱為內部類。設計嵌套類有以下的好處:

  • 代碼組織:如果我們定義的某個類只服務於當前類,而不會在其他命名空間中使用,那么將它定義在當前類的命名空間中是明智的。就像成員變量,在面向對象編程思想下,並不是所有的成員都要定義為全局的
  • 訪問權限:嵌套類可以直接訪問外部類的成員,即便是 private 修飾的
  • 便利性:沒必要為每一個類創建一個文件

下面看看這兩種類的寫法以及優勢。先看看靜態嵌套類:

class OuterClass {
     private static int a =10;
     class StaticNestedClass {
     }
}
// 用法
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

靜態類初始化時除了類前面加“外部類."外,其他的跟使用一個普通類相同。並且在 nestedObject 對象上使用跟普通對象一樣。靜態類最大的優勢在於可以直接訪問外部類私有的靜態成員。

再看看內部類:

class OuterClass {
    private int a = 10;
    class InnerClass {
    }
}
// 用法
OuterClass outerObject = new outerObject();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

與非靜態成員類似,InnerClass 都綁定在一個外部對象上。因此初始化 InnerClass 時,需要先創建 OuterClass 對象。內部類除了可以訪問外部類的靜態私有成員外,還可以直接訪問外部類的非靜態私有成員。當然,內部類使用時有個限制,不能聲明 static 成員。

原文地址

DAY3. 是 Python 的設計缺陷嗎

先看一個問題,猜猜下面代碼的輸出結果是什么?

def a():
    print("a executed")
    return []

def b(x=a()):
    x.append(5)
    print(x)

b()
b()
b()

輸出結果如下:

a executed
[5]
[5, 5]
[5, 5, 5]

可以看到,每次調用 b() 時代碼的輸出都不一樣。並且,a 函數只執行了一次。因此,我們可以確定,b 函數的默認參數是在函數定義時僅被計算了一次,而不是函數每次調用都會計算。這個問題可以這樣看:Python 中函數也是一個對象而默認參數是對象的成員,所以,它會被保存、更新。但你可能會想,這是不是 Python 的設計缺陷。答案是否定的,如今的 Python 如此流行,如果僅僅是設計缺陷這么簡單的問題,那么會很快被修復。那么,你可能還會想是不是可以讓函數執行時再確定默認參數值,這樣就可以避免上面的問題了。然而這樣同樣會有問題,看下面的例子:

fruits = ("apples", "bananas", "loganberries")

def eat(food=fruits):
    print(food)

def some_random_function():
    global fruits
    fruits = ("blueberries", "mangos")

假設,全局變量 fruits 被修改了, 然后我們調用 eat 時,她的默認參數值就跟之前的調用不一致了, 同樣會令我們疑惑。而 Python 的設計者認為這種情況給語言使用者造成的疑惑更大,因此他們采用第一種的設計方式,在函數定義時確定默認值。

其實這樣的問題不光 Python 存在,任何語言都存在, 我們下面看一個 Java的例子。

StringBuffer s = new StringBuffer("Hello World");
Map<StringBuffer,Integer> counts = new HashMap<StringBuffer,Integer>();
counts.put(s, 5);
s.append("!!!!");
for (Map.Entry<StringBuffer, Integer> entry : counts.entrySet()) {
    System.out.println(entry.getKey() + "\t" + entry.getValue());
}

我們寫入 counts 的字符串是 "Hello World",而輸出是變成了 "Hello World!!!!"。這跟我們剛剛討論的 Python 的問題類似,這里沒有對錯,無論使用什么方式,都會有人提出不同意見。到底使用哪種方式是語言的設計者考慮的問題,而每種方式有什么坑,我們作為語言的使用者應該提前了解且避免。

以上便是 Stack Overflow 的第二周周報,希望對你有用,后續會繼續更新,如果想看日更內容歡迎關注公眾號。

公眾號「渡碼」,分享更多高質量內容


免責聲明!

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



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