2011-05-10 88 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的值,那么您将无法使用这些常量方法并且将调用上述函数以获得正确的值。)