【问题标题】:Why data Shadowing with instance variables is not working in my program?为什么带有实例变量的数据阴影在我的程序中不起作用?
【发布时间】:2014-07-06 19:30:31
【问题描述】:

我有如下所示的三个类,用于游戏 GUI:-

//this is the parent class.
import javax.swing.*;
import java.awt.*;
public class GameGui extends JFrame{
      public void decorateButton(JButton aBut,Color forg,Color back){
         Font afont = new Font(Font.SANS_SERIF,Font.PLAIN,18);
         aBut.setFont(afont);
         aBut.setBackground(back);
         aBut.setForeground(forg);
      }
      public void setFrameDefault(){
         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         this.setSize(400, 475);
         this.setLocationRelativeTo(null);
         this.setResizable(false);
     }
     public void setConstraints(int x,int y,int weightx,int weighty,GridBagConstraints gbc){
         gbc.weighty=weighty;
         gbc.weightx=weightx;
         gbc.gridx=x;
         gbc.gridy=y;
     }
}

//this class is for result to be shown for the game.

import javax.swing.*;
import java.awt.*;
class Result extends GameGui{
      JPanel mainPanel = new JPanel();
      JLabel backImage = new JLabel();//I want this variable to be shadowed by the subclass variable,but it is not happening. 
      JButton continueGame = new JButton("continueGame");
      JButton exitGame = new JButton("exitGame");
      public Result(){
            this.setFrameDefault();
            backImage.setLayout(new BorderLayout());
            this.setContentPane(backImage);
            mainPanel.setLayout(new GridBagLayout());
            decorateButton(continueGame,Color.green,Color.white);
            decorateButton(exitGame,Color.green,Color.white);
            setGui();
      }
      public void setGui(){
            GridBagConstraints gbc = new GridBagConstraints();
            mainPanel.setOpaque(false);
            gbc.gridy=200;
            gbc.gridx=0;
            gbc.insets=new Insets(410,0,0,130);
            mainPanel.add(continueGame,gbc);
            gbc.gridx=GridBagConstraints.RELATIVE;
            gbc.insets = new Insets(410,0,0,0);
            mainPanel.add(exitGame,gbc);
            setFrameDefault();
            this.getContentPane().add(mainPanel);
      }

 }

 //this class is for showing the result for a Win.

 import javax.swing.*;
 import java.awt.*;
 public class Win extends Result{
        JLabel backImage = new JLabel(new ImageIcon("C:\\Users\\BSK\\Desktop\\win.png"));//Problem is here as i have declared the same named JLabel as in Result class but iam not getting the image as background.
        public static void main(String[] args) { //this main method is for testing.
            Win w = new Win();
            w.setVisible(true);
        }
 }

我在层次结构的末尾需要两个类,它们是 WinDefeat(第二个我还没有实现)。我需要这个,因为我想要胜利框架和失败框架只在图像上有所不同。
所以我的问题是,虽然我在ResultWin 两个类中都声明了与backImage 相同的JLabel,但为什么我没有在背景中获取图像?我已经通过将图像放入JLabel 来测试它backImage 属于 Result 类,然后它就可以工作了!但我想利用 data shadowing 因为在我的 Defeat 类(也扩展了 Result)中,我将命名为 JLabelbackImage同名,但设置了不同的图像。希望你明白,那么出路是什么?
提前致谢。

注意请使用您的图片进行测试。

【问题讨论】:

  • 看起来你在这里误用了继承:你在组合会更好的地方使用继承。
  • @HovercraftFullOfEels 如果你能提供一个详细的答案......很多很多thanx
  • @HovercraftFullOfEels plese if you can describe....等待你的回答。

标签: java swing inheritance scope


【解决方案1】:

阴影影响名称所指的变量。也就是说,由于子类Win 定义了它自己的backImage 实例变量,所以引用backImageWin 的方法将引用Win 中的实例变量(以及它的值)而不是超类,Result

阴影不会替换变量和其他对象指向的对象。也就是说,超类Result 仍然定义了它自己的backImage 实例变量,并且Result 的方法仍然引用那个变量(以及它的值)。所以 Win#backImage 阴影 Result#backImage 但它不会改变 Result 的工作方式。

还要注意,像JLabel backImage = ... 这样的初始化行作为类构造函数的一部分运行,而子类Win 的构造函数从运行其超类Result 构造函数开始。因此,如果子类没有声明另一个 backImage 并且它的构造函数为继承的实例变量 Result#backImage 分配了一个新值,这将在 Result 构造函数构建内容窗格之后发生,因此它不会更改显示.

您可以更改 backImage 对象的内容:

public class Win extends Result {
  public Win() {
    super();
    backImage.setIcon(new ImageIcon("C:\\Users\\BSK\\Desktop\\win.png"));
  }

  ...

Win子类修改backImage的图标。

【讨论】:

  • 请详细说明您的第一行...如果可以...谢谢
  • 详细说明。更改标签的图标后,代码可能还必须请求窗口重新布局。
  • 你是说Win类会引用它自己的JLabel,但是为什么结果不符合预期呢?
  • 没有。 Win 类不应声明其自己的 backImage 变量,也不应创建另一个 JLabel 实例。只需更改已链接到组件树的现有 JLabel 的图标即可。
  • 顺便说一句,上面的帖子回答了关于阴影做什么和不做什么的问题,并提供了最小的代码更改。更好的设计可以省略子类(这不是很好地使用子类)并添加Result 方法来更改其背景或添加Result 构造函数参数来指定背景。后一种情况可以选择有一个始终使用默认背景的无参数构造函数。
【解决方案2】:

Java 中的字段不会作为方法被覆盖,因此这对您不起作用。幸运的是,有很多解决方案。

其中之一(我绝对不是说最好的!)是使用抽象 getIcon() 方法或其他东西使您的 Result 游戏抽象,然后从您的 setGui() 方法中调用它,然后是您的赢/输类只会在其中返回不同的图标。

【讨论】:

  • 但这不是覆盖,如果我们没有在那里定义JLabelResult 类将如何使用它的其他方法?
  • JLabel 仍将在 Result 类中声明,并且 getIcon() 方法也将在其中声明,只需在 setGui() 中初始化您的背景,但不要使用特定图标,而是使用您的 @ 987654329@ 方法。然后在您的 Win 类中覆盖它以返回您实际想要的图标。
  • 虽然Win 可以覆盖Result#getIcon() 方法,但覆盖由构造函数调用的方法通常不是一个好主意,因为它在子类构造函数运行之前被调用。这可以通过在构造函数之后进行 UI 构建工作来解决。
  • aaa,真的,我想添加警告,从构造函数调用可覆盖的方法是个糟糕的主意(根据自己的经验),我没有注意到 setGui() 是从构造函数调用的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 2017-09-06
  • 2021-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多