【问题标题】:In Java, is there a way to make a class know that a variable in another class has changed during runtime? [duplicate]在Java中,有没有办法让一个类知道另一个类中的变量在运行时发生了变化? [复制]
【发布时间】:2020-01-07 22:42:07
【问题描述】:

我正在尝试编写一个代码,其中主类(具有 main 方法的类)需要播放音乐,而另一个类中名为“运行”的变量为真。但是如果运行时变量为假,主类中的变量仍然为真。这是我的代码的 sn-p。

public static void main(String[] args) {

    Game game = new Game("Geometry Dash", 700, 600);

    game.start();


    System.out.println(Game.running);
    do  {
            GameState.runMusic();
    }while(Game.running);


}

代码真的无关紧要。相反,我试图找到一种方法让我的主类意识到另一个类中的变量已变为假(因此已更改)。

【问题讨论】:

  • 在 Java 中没有内置的方法可以做到这一点,但你应该看看观察者模式。
  • 您需要研究“观察者模式”。你可能还想看看volatile
  • 这样做的方法不止一种,而是无数种。我会删除另一个类的需要这个词。但是有一整套原语可以做到这一点,但是要寻找的几个关键字是并发性和并行性。
  • 你可能想看看PropertyChangeSupport
  • 正如其他人指出的那样,您需要实现Observer Pattern 的东西。您可以通过定义 Java 接口并让您的“观察者”类实现它来“自己动手”。更好的是,你可以使用标准的Java类“java.util.Observable”:How to create change listener for variable?

标签: java


【解决方案1】:

问题是您想在设置标志之前播放音乐。

while (flag) {
     PlayMusic();
}

这有问题,因为即使您将标志设置为 false,它也不会工作,直到 PlayMusic() 返回。所以你需要一种方法,不仅可以接收中断,还可以停止音乐。因此,在不使用线程的情况下,一种方法是设置一个计时器,让计时器每隔一段时间(可能是 100 毫秒)继续检查flag,然后发出停止音乐的信号。

    Timer timer = new Timer(0, (ae)-> {
             if (!flag) {
                MusicOff();
                timer.stop();
             }
        });

    timer.setDelay(100);
    timer.start();

事实上,您甚至可能不需要 while 循环。这完全取决于它是如何实现的。

如何设置标志取决于您。

【讨论】:

    【解决方案2】:

    有没有办法让一个类知道另一个类中的变量在运行时发生了变化?

    类不是活动的东西......但线程是。所以我假设你实际上是指正在执行main 方法的线程。

    (另外,除非您在谈论static 变量,否则该变量属于对象(类的实例)而不是类。)


    线程可以(仅)通过两种方式“知道”变量已被另一个线程更改。

    1. 线程可以重复测试变量。这就是您的代码当前正在执行的操作。对此有一些警告;见下文。

    2. 线程可以等待另一个线程告诉它变量已更改。这可以使用Object.waitObject.notifyObject.notifyAll 方法来完成。

    重复测试一个变量可能会很昂贵,尤其是在测试间隔很小的情况下。所以你(一般来说)你可能会写这样的东西:

    while (!someObject.flag) {
        // so somthing that doesn't take a long time
        Thread.sleep(INTERVAL_MILLIS);
    }
    

    但问题是:

    • 如果INTERVAL_MILLIS 太小,这可能仍然太贵,并且
    • 如果INTERVAL_MILLIS 太大,则在检测到更改之前可能会有明显的延迟。

    第二个问题是上述方法甚至可能行不通。为了保证线程在测试时看到对flag 的更改,您的代码在读写flag 时需要同步,或者flag 需要声明为volatile。 (或者使用AtomicBoolean 作为标志。)

    所以使用waitnotify 通常是更好的选择。这是它的样子:

     public class MyClass {
    
         private boolean flag = false;    
    
         /**
          Wait for flag to become `true`.
          */
         public synchronized void await() {
             while (!this.flag) {
                 this.wait();
             }
         }
    
         public synchronized void setFlag(boolean value) {
             this.flag = value;
             this.notifyAll();
         }
     }
    

    或者,您可以只使用 CountDownLatchCyclicBarrier ...

    【讨论】:

      【解决方案3】:

      您应该实现回调或使用设计模式来观察在运行时更改的变量。例如,

      //In game class
      public class Game{
         private GameStateListener gameStateListener;
      
      
      
         public void setGameStateListener(GameStateListener gameStateListener){
            this.gameStateListener = gameStateListener;
         }
         public void stop(){
           if(this.gameStateListener != null){
                 this.gameStateListener.onStateChange(false);
           }
         }
      
      
         public interface GameStateListener{
              void onStateChange(boolean running);
         }
      }
      
      //In your main class or whenever you would like to start and stop music
      
      game.setGameStateListener(new GameStateListener() {
            void onStateChange(boolean running){
                //these code block will be executed whenever event is triggered from Game class.
                if(!running){
                  //if you implement this to stop game button
                  GameState.stopMusic();
                }else{
                  //if you implement this to start game button.
                  GameState.runMusic();
                }
            }
      });
      

      另一方面,如果您有多个无法跟踪所有事件的事件,例如开始游戏、用户得分、发送请求等。您可能需要实现其他 cmets 中提到的设计模式,例如观察者模式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-09
        • 2012-04-12
        • 2020-09-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多