2011-05-10 60 views
1

Creating a GUI with JFC/Swing > Perform Custom Painting : Refining the Design最終局部變量如何避免重複調用方法?

我正在閱讀上面鏈接的教程,部分示例代碼讓我感到困惑。根據該moveSquare方法中的代碼註釋,存儲位置信息作爲最終的局部變量將

「避免重複調用相同 方法」

這使得完全沒有意義,我和我希望有人能夠闡述評論的意義。 (參見上面的完整的源代碼和教程的評論鏈接)

class MyPanel extends JPanel { 

RedSquare redSquare = new RedSquare(); 

public MyPanel() { 

    setBorder(BorderFactory.createLineBorder(Color.black)); 

    addMouseListener(new MouseAdapter(){ 
     public void mousePressed(MouseEvent e){ 
      moveSquare(e.getX(),e.getY()); 
     } 
    }); 

    addMouseMotionListener(new MouseAdapter(){ 
     public void mouseDragged(MouseEvent e){ 
      moveSquare(e.getX(),e.getY()); 
     } 
    }); 

} 

private void moveSquare(int x, int y){ 

    // Current square state, stored as final variables 
    // to avoid repeat invocations of the same methods. 
    final int CURR_X = redSquare.getX(); 
    final int CURR_Y = redSquare.getY(); 
    final int CURR_W = redSquare.getWidth(); 
    final int CURR_H = redSquare.getHeight(); 
    final int OFFSET = 1; 

    if ((CURR_X!=x) || (CURR_Y!=y)) { 

     // The square is moving, repaint background 
     // over the old square location. 
     repaint(CURR_X,CURR_Y,CURR_W+OFFSET,CURR_H+OFFSET); 

     // Update coordinates. 
     redSquare.setX(x); 
     redSquare.setY(y); 

     // Repaint the square at the new location. 
     repaint(redSquare.getX(), redSquare.getY(), 
       redSquare.getWidth()+OFFSET, 
       redSquare.getHeight()+OFFSET); 
    } 
} 

public Dimension getPreferredSize() { 
    return new Dimension(250,200); 
} 

public void paintComponent(Graphics g) { 
    super.paintComponent(g);  
    g.drawString("This is my custom Panel!",10,20); 

    redSquare.paintSquare(g); 
} 
} 

回答

2

這意味着調用getX()或其他方法的結果將保存在一個變量中並重用,以便您不必每次需要X或Y時都繼續調用這些方法。

這有三個優點:

  1. 該代碼是更易讀由於變量名由於不必再次調用並再次
  2. 未來的變化是可能的方法
  3. 性能得到改進比較容易,因爲你只需要在一個地方改變方法名稱。
+2

+0:所有好東西,我經常使用最終變量出於這些原因,但我會說在這種情況下,每個計數都會失敗。 1.我不認爲CURR_W比getWidth()更清晰2.調用getWidth()/ getHeight(),但如果條件失敗,可能不會使用它們,而是浪費時間而不是幫助。他們最多使用一次,無需任何保存。 3.稍後再調用getX(),getY()等,所以你沒有太多保存。恕我直言,IDE重構應該用於重命名方法esp getter與setter。 – 2011-05-10 17:37:02

+1

@Peter,我同意,這個問題的例子是在最終變量中保存結果的一個不好的例子,但是,我試圖解釋評論背後的含義和可能的優點,但當然不是保證。 – jzd 2011-05-10 17:44:05

+0

謝謝大家的答案...我希望我可以選擇多個官方解決方案! – 2011-05-10 17:46:49

1

最終變量只能有其值設置一次。

如果您嘗試多次設置一個最終變量的值,或者編寫一個函數來設置最終成員變量的值,它會生成一個編譯器錯誤。這可以確保您不能多次設置該值,這可以避免重複調用同一方法。例如,如果您嘗試再次寫入:

CURR_X = redSquare.getX(); 

因爲您已經設置了最終變量,所以會出現錯誤。所以你要避免重複調用redSquare.getX()。在這種情況下,它實際上並沒有多大作用,但在其他對象的實現中,該方法可能會產生巨大的計算量。

+0

代碼只使用兩次值,稍後調用'redSquare.getX()'方法。 ;) – 2011-05-10 17:22:15

+0

是的,這似乎很奇怪,特別是給予評論。我不確定那是怎麼回事。 – 2011-05-10 17:27:28

+0

我希望如果寬度或高度發生變化,最後一個getX()將返回相同的代碼,只需調用'setX(x)',直到它移動後才重繪。 – 2011-05-10 17:30:43

2

使本地變量最終沒有真正的區別,因爲你懷疑。它可以幫助JVM在某些情況下優化代碼,但是現在JVM相當聰明,並且沒有多大幫助。

真正的區別在於結果存儲爲局部變量,以避免方法調用。

但是,由於方法調用可能是微不足道的getter,因此JVM可以內聯這些方法,因此性能差異可能不是很大。

如果這些變量沒有被訪問或只被訪問過一次,它們可能會損害性能。

重繪可能比這種方法貴1000倍,使這裏的變化不那麼重要。通常,我建議簡化代碼並清除編寫代碼中最重要的因素,而且JVM通常會非常有效地優化簡單明瞭的代碼。

0

這是所有關於moveSquare功能 - 這是相同的,以這樣的:

private void moveSquare(int x, int y){ 

    final int OFFSET = 1; 

    if ((redSquare.getX()!=x) || (redSquare.getY()!=y)) { 

     // The square is moving, repaint background 
     // over the old square location. 
     repaint(redSquare.getX(),redSquare.getY(),redSquare.getWidth()+OFFSET,redSquare.getHeight()+OFFSET); 

     // Update coordinates. 
     redSquare.setX(x); 
     redSquare.setY(y); 

     // Repaint the square at the new location. 
     repaint(redSquare.getX(), redSquare.getY(), 
       redSquare.getWidth()+OFFSET, 
       redSquare.getHeight()+OFFSET); 
    } 
} 

,你可以看到,通過不使用這些常數(這只是初始化一次),你最終調用的getX ()和getY()實例2多次(儘管我認爲JIT編譯器會優化它!) - 但是,通過引入這些常量保存了這兩個調用。 (這隻有在使用常量時X的值在這些代碼行中沒有變化時纔有效 - 例如,如果if ((redSquare.getX()!=x) || (redSquare.getY()!=y))之後的行更改了X或Y的值,那麼您將無法使用這些常量方法並且將調用上述函數以獲得正確的值。)