Строка возвращает null при использовании метода get

Я пытаюсь установить значение строки в другом классе, а затем получить его из третьего класса. Теперь я пытаюсь использовать методы set и get, но я не могу заставить его работать! Когда пользователь запускает программу, появляется кнопка. При нажатии кнопки тестовая строка получает значение «Hello». А затем я вызываю заданный класс и проверяю параметр. Теперь в методе set это System.out.println, и он печатает Hello, но когда я пытаюсь получить метод из моего второго класса, он печатает null. Не знаю почему! Вот мои занятия:

public class Class1 {
    public static void main(String[] args) {
        Class3 c3 = new Class3();

        c3.setFilename("Hello");

        JFrame frame = new JFrame("Action Listener");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new FlowLayout());

        JButton button = new JButton("Click me!");
        frame.add(button);

        Class2 c2 = new Class2();

        button.addActionListener(c2);

        frame.setSize(300, 100);
        frame.setVisible(true);
    }
}

Вот мой второй класс, это строка имени файла, которую я хочу иметь для следующего класса:

public class Class2 implements ActionListener {

    String filename;

    public void actionPerformed(ActionEvent e) {
        Class3 c3 = new Class3();

        filename = c3.getFilename();

        System.out.println(filename); // Prints null
    }
}

Вот третий класс:

public class Class3 {
    String filename;

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;

        System.out.println(filename); // Prints Hello
    }
}

person WeeRox    schedule 14.10.2014    source источник
comment
Что не работает? Пробовали ли вы отлаживать код с помощью отладчика вашей IDE?   -  person Mohammad Najar    schedule 14.10.2014
comment
Слишком много кода, слишком мало контекста.   -  person The Paramagnetic Croissant    schedule 14.10.2014
comment
@Mohammad Да, я пытался отлаживать его как с помощью своей IDE, так и с помощью System.out.println, и он возвращает null, когда доходит до третьего класса.   -  person WeeRox    schedule 14.10.2014
comment
@Bennyz Возвращает ноль.   -  person WeeRox    schedule 14.10.2014
comment
@WeeRox, глядя на количество голосов против, вы должны понять, что ваш вопрос либо неясен, либо слишком широк. Пожалуйста, сузьте вопрос и укажите области, в которых, по вашему мнению, происходит ошибка. То есть точная строка, значение, которое вы получаете, вывод и т. д.   -  person Mohammad Najar    schedule 14.10.2014
comment
Ваша проблема заключается не столько в том, как получить результат, хранящийся в переменной, поскольку вы уже знаете, как это сделать - используйте метод получения, такой как getFileName(). Нет, проблема заключается скорее в том, когда получить этот результат, поскольку вам нужно, чтобы один класс уведомлялся об изменении состояния одной из его переменных. Чтобы решить эту проблему, рассмотрите возможность использования какого-либо прослушивателя, чтобы Home мог получать уведомления при изменении переменной fileName. Здесь хорошо работает шаблон наблюдателя, и я часто реализовывал его с помощью PropertyChangeListeners и PropertyChangeSupport. ... continued ....   -  person Hovercraft Full Of Eels    schedule 14.10.2014
comment
Когда он доходит до третьего класса, недостаточно хорошо указывает, когда появляется ваш нулевой указатель. Классы не выполняются, выполняются методы и операторы. Нулевые указатели имеют тенденцию создавать исключения и трассировки стека; трассировка стека укажет, какие методы выполняются и в какой строке возникает ошибка. Помещение одного в вопросе — хороший способ сообщить, где что-то идет не так.   -  person arcy    schedule 14.10.2014
comment
При публикации вопроса на Stack Overflow вы должны опубликовать минимальный, но полный код, который позволит нам воспроизвести вашу проблему. Ваш текущий код нельзя использовать, потому что он не скомпилируется без класса test.   -  person Pshemo    schedule 14.10.2014
comment
... continued .... Например, ознакомьтесь с кодом в этом ответе.   -  person Hovercraft Full Of Eels    schedule 14.10.2014
comment
@Pshemo Затем я удаляю все, что связано с этим классом.   -  person WeeRox    schedule 14.10.2014
comment
Обратите внимание, что ваша строковая переменная fileName в классе homeButtonEvent имеет значение null, потому что вы никогда не присваиваете ей значение.   -  person Hovercraft Full Of Eels    schedule 14.10.2014
comment
Может кто-нибудь проверить мой ответ, пожалуйста.   -  person rert588    schedule 14.10.2014
comment
@WeeRox Не только это. Вы должны удалить из своего примера все, что не имеет ничего общего с вашей проблемой. Попробуйте начать с нуля и написать новый пример, в большинстве случаев этот метод быстрее и безопаснее, чем удаление существующего кода.   -  person Pshemo    schedule 14.10.2014
comment
Так вы не только быстрее получите ответ на свой вопрос, но и привлечете больше людей к ответу на ваши вопросы. Подумайте об этом, если бы вы увидели 3 вопроса: два коротких, с простым примером кода и один длинный, со слишком сложным примером, на какой из них вы попытались бы ответить первым?   -  person Pshemo    schedule 14.10.2014
comment
Может ли кто-нибудь проверить, верен ли мой ответ   -  person rert588    schedule 14.10.2014
comment
@ rert588: я проверил, и нет, ваш ответ недействителен.   -  person Hovercraft Full Of Eels    schedule 14.10.2014
comment
К исходному плакату: у вас происходят конфликты имен, включая переменную JButton с именем train и класс с именем train. Ради вас и особенно для нас не делайте этого! Также помните, что каждый раз, когда вы создаете новый объект Train(...)`, вы делаете именно это, создавая новый объект. , и изменение состояния нового не повлияет на другие объекты того же класса. Это, наверное, одна из ваших самых больших проблем.   -  person Hovercraft Full Of Eels    schedule 14.10.2014
comment
@Pshemo мне так лучше?   -  person WeeRox    schedule 16.10.2014
comment
@WeeRox Намного лучше. +1 за улучшение.   -  person Pshemo    schedule 16.10.2014
comment
но когда я пытаюсь получить метод из своего второго класса, он печатает null. Я не знаю почему! Обратите внимание, что при запуске метода main вы создаете новый экземпляр Class3, для которого вы вызываете метод setFilename, который выводит приветствие, но вы нигде не используете этот экземпляр. Вместо этого в методе Class2 actionPerformed вы создаете новый (отдельный) экземпляр Class3 и не передаете filename этому новому экземпляру, поэтому он остается null. Не лучше ли было бы передать Class2 экземпляр конструктора Class3, сохранить его в поле и повторно использовать в actionPerformed?   -  person Pshemo    schedule 16.10.2014
comment
@Pshemo Вы имеете в виду, что мне нужно поместить методы set и get в Class2 и удалить Class3?   -  person WeeRox    schedule 17.10.2014
comment
Не обязательно. В большинстве случаев хорошо разделить данные на несколько классов. Я имею в виду, что вместо того, чтобы создавать новые экземпляры Class3 каждый раз, когда будет нажата кнопка, вы можете повторно использовать тот, который вы создали ранее. Вам просто нужно передать его в конструктор класса 2, сохранить в каком-либо поле класса 2 и повторно использовать в методе actionPerformed. Я имею в виду что-то вроде этого: pastebin.com/u7GGz1Ns   -  person Pshemo    schedule 17.10.2014


Ответы (1)


Среди ваших проблем:

  • Вы никогда не устанавливаете имя файла класса поезда (проверьте - где вы когда-либо вызывали fileName = something?)
  • Вы создаете новые объекты поезда и ожидаете, что новый объект сможет воспринимать изменения, внесенные в другие объекты поезда. Java так не работает. Вам нужно протестировать тот же объект, который вы меняете.
  • Ваши соглашения об именах программ сбивают с толку и опасны. Помните, что имена классов начинаются с заглавной буквы. Не давайте переменным те же имена, что и несвязанному классу, например, вашему классу поезда и кнопке поезда.
  • Ваша программа имеет много ненужной сложности, такой как параллельные массивы, которые затрудняют отладку и усовершенствование.
  • Вы меняете содержимое JPanel вместо того, чтобы использовать гораздо более простой в использовании CardLayout, который сделает это за вас.

Например, вы можете инкапсулировать имена строк JButton и имена файлов в класс или перечисление. Преимущество использования класса заключается в том, что вы можете считывать данные из файла и создавать объекты класса из данных файла, что дает дополнительную гибкость, однако для целей моего примера и во избежание добавления дополнительных файлов я используйте перечисление, что-то вроде

public enum ButtonFileName {
   MONDAY("Monday", KeyEvent.VK_M, "monday_blues.jpg"), 
   TUESDAY("Tuesday", KeyEvent.VK_T, "tuesday_fun.jpg"), 
   WEDNESDAY("Wednesday", KeyEvent.VK_W, "humpday.jpg"), 
   THURSDAY("Thursday", KeyEvent.VK_H, "almost_friday.jpg");

   private String buttonText;
   private String fileName;
   private int mnemonic;

   private ButtonFileName(String buttonText, int mnemonic, String fileName) {
      this.buttonText = buttonText;
      this.mnemonic = mnemonic;
      this.fileName = fileName;
   }

   public String getButtonText() {
      return buttonText;
   }

   public int getMnemonic() {
      return mnemonic;
   }

   public String getFileName() {
      return fileName;
   }
}

Затем я могу дать своему основному классу переменную ButtonFileName, selectedButtonFileName, а затем заполнить эту переменную при нажатии кнопки. Я также могу создать свои собственные действия, по одному для каждого перечисления ButtonFileName, и использовать эти действия для установки своих кнопок. Например:

import java.awt.CardLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class Home2 extends JPanel {
   private static final String TRAIN_PANEL = "train panel";
   private static final String BTN_ROW_PANEL = "btn row panel";
   private CardLayout cardLayout = new CardLayout();
   private ButtonFileName selectedButtonFileName = null;
   private JPanel buttonRowPanel = new JPanel();
   private JPanel trainPanel = new JPanel();

   public Home2() {
      buttonRowPanel = createButtonRowPanel();
      trainPanel = createTrainPanel();

      setLayout(cardLayout);
      add(buttonRowPanel, buttonRowPanel.getName());
      add(trainPanel, trainPanel.getName());
   }

   private JPanel createButtonRowPanel() {
      JPanel btnRowPanel = new JPanel(new GridLayout(1, 0, 5, 5));
      btnRowPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      btnRowPanel.setName(BTN_ROW_PANEL);
      for (ButtonFileName btnFileName : ButtonFileName.values()) {
         JButton btn = new JButton(new RowButtonAction(btnFileName, this));
         btnRowPanel.add(btn);
      }
      return btnRowPanel;
   }

   private JPanel createTrainPanel() {
      JPanel trainPanel = new JPanel();
      trainPanel.setName(TRAIN_PANEL);
      JButton trainBtn = new JButton(new TrainAction("Train", KeyEvent.VK_T, this));
      trainPanel.add(trainBtn);
      return trainPanel;
   }

   public ButtonFileName getSelectedButtonFileName() {
      return selectedButtonFileName;
   }

   public void setSelectedButtonFileName(ButtonFileName selectedButtonFileName) {
      this.selectedButtonFileName = selectedButtonFileName;
   }

   public void nextCardLayoutView() {
      cardLayout.next(this);
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("Home2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new Home2());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

}

Опять перечисление

enum ButtonFileName {
   MONDAY("Monday", KeyEvent.VK_M, "monday_blues.jpg"), 
   TUESDAY("Tuesday", KeyEvent.VK_T, "tuesday_fun.jpg"), 
   WEDNESDAY("Wednesday", KeyEvent.VK_W, "humpday.jpg"), 
   THURSDAY("Thursday", KeyEvent.VK_H, "almost_friday.jpg");

   private String buttonText;
   private String fileName;
   private int mnemonic;

   private ButtonFileName(String buttonText, int mnemonic, String fileName) {
      this.buttonText = buttonText;
      this.mnemonic = mnemonic;
      this.fileName = fileName;
   }

   public String getButtonText() {
      return buttonText;
   }

   public int getMnemonic() {
      return mnemonic;
   }

   public String getFileName() {
      return fileName;
   }
}

Моя акция на поезд JButton

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

@SuppressWarnings("serial")
public class TrainAction extends AbstractAction {
   private Home2 home;

   public TrainAction(String name, int mnemonic, Home2 home) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.home = home;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      System.out.println("Selected File Name: "
            + home.getSelectedButtonFileName().getFileName());
      home.nextCardLayoutView();
   }
}

Мои действия для кнопок строк

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

@SuppressWarnings("serial")
public class RowButtonAction extends AbstractAction {
   private ButtonFileName btnFileName;
   private Home2 home;

   public RowButtonAction(ButtonFileName btnFileName, Home2 home) {
      super(btnFileName.getButtonText());
      putValue(MNEMONIC_KEY, btnFileName.getMnemonic());
      this.btnFileName = btnFileName;
      this.home = home;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      home.setSelectedButtonFileName(btnFileName);
      home.nextCardLayoutView();
   }
}

Что касается гибкости, скажем, я хотел добавить еще одну кнопку JButton и имя файла. Добавьте элемент Friday в перечисление, и все готово.

person Hovercraft Full Of Eels    schedule 14.10.2014