Java - нет доступа к Arraylist в другом классе

У меня есть работающий класс «TemperatureSensor», который периодически добавляет новое рандомизированное значение с плавающей запятой в список массивов TemperatureList в качестве объекта Temperature. Последний добавленный объект в массиве (индекс 0) затем отправляется от клиента RMI на сервер RMI - это происходит без проблем.

Однако, когда я нажимаю кнопку в графическом интерфейсе пользователя, чтобы отобразить размер этого массива объектов, я всегда получаю 0. Если я распечатываю размер массива из клиентского класса RMI, он показывает правильный размер.

Мой вопрос: как мне правильно получить доступ к одному и тому же массиву из нескольких классов?

Вот UML:

Java - нет доступа к Arraylist в другом классеДатчик температуры:

import java.text.DecimalFormat;
import java.util.Random;

public class TemperatureSensor implements Runnable
{
private int waitingTime;
private Model model;

public TemperatureSensor(Model model, int waitingTime)
{
    this.model = model;
    this.waitingTime = waitingTime;
}

@Override
public void run() 
{
    float temperature = 25.0f;

    while(true)
    {
        temperature = measureTemperature(temperature);
        model.addTemperatureData(temperature);
        System.out.println("Sending: " + temperature);
        waiting();          
    }       
}

private float measureTemperature(float temperature)
{
    Random rand = new Random();

    float minTempFloat = 0.1f;
    float maxTempFloat = 0.2f;

    int incrementSwitch = rand.nextInt(3-0) + 0;

    if (incrementSwitch == 0)
    {
        temperature += minTempFloat + rand.nextFloat() * (maxTempFloat - minTempFloat);
    }

    else if (incrementSwitch == 1)
    {
        //Do nothing
    }

    else if (incrementSwitch == 2)
    {
        temperature -= minTempFloat + rand.nextFloat() * (maxTempFloat - 
        minTempFloat);
    }

    return temperature;     
}

private void waiting()
{   
    try
    {
        Thread.sleep(waitingTime);
    }

    catch (InterruptedException e)
    {
        e.printStackTrace();
    }
}
}

Модель:

public interface Model
{
    public void addTemperatureData(float value);    
    public Temperature getLatestTemperatureData();
    public int getTempListSize();
}

ModelManager:

public class ModelManager implements Model
{
    private TemperatureList temperatureList;

    public ModelManager()
    {
         temperatureList = new TemperatureList();
    }

    @Override
    public void addTemperatureData(float value)
    {
        Temperature temperature = new Temperature(value);
        //this.temperatureList.clearTemperatureDataList();
        this.temperatureList.addTemperatureDataToList(temperature);
    }   

    @Override
    public Temperature getLatestTemperatureData() 
    {
         return temperatureList.getLatestTemperatureDataFromList();
    }

    @Override
    public int getTempListSize()
    {
        return temperatureList.size();
    }
}

RMIsensorClient:

import java.rmi.Naming;
import java.rmi.RemoteException;

public class RMIsensorClient 
{
private RMIserverInterface serverInterface;
private static Model model = new ModelManager();

public static void main(String[] args) throws RemoteException, InterruptedException
{                   
    TemperatureSensor tempSensor = new TemperatureSensor(model, 5000);
    Thread tempThread = new Thread(tempSensor, "TempSensor");   

    tempThread.start(); 

    RMIsensorClient sensorClient = new RMIsensorClient();
}   

public RMIsensorClient() throws RemoteException
{
    super();    

    try
    {
        serverInterface = (RMIserverInterface) Naming.lookup("rmi://localhost:1099/rmiServer");         

        while(true)
        {
            serverInterface.getTemperature(model.getLatestTemperatureData());
            System.out.println(model.getTempListSize());
            Thread.sleep(5000);
        }
    }

    catch(Exception e)
    {
        e.printStackTrace();            
    }       
}   
}

Контроллер:

public class Controller
{
    private static Model model;

    public Controller ()
    {   
        this.model = new ModelManager();
    }

    public int getNumberOfListElements()
    {
        return model.getTempListSize();
    }
}

GUI:

public class GUItemperatureController implements Initializable
{   
private Controller controller = new Controller();

@FXML
private Label tlTemperature;

@FXML
private Pane mainPane;

@FXML
private TextField tfTemperature;

@FXML
private Button btnUpdate;   

@Override
public void initialize(URL arg0, ResourceBundle arg1) 
{               
    tfTemperature.setEditable(false);
}   

@FXML
void showArraySize(ActionEvent event) 
{       
    tfTemperature.setText(Integer.toString(controller.getNumberOfListElements()));
}
}

Список температур:

import java.io.Serializable;
import java.util.ArrayList;

public class TemperatureList implements Serializable
{
private ArrayList<Temperature> temperatureList;

public TemperatureList()
{
    this.temperatureList = new ArrayList<>();
}

public void addTemperatureDataToList(Temperature temperature)
{
    temperatureList.add(0,temperature);
}

public Temperature getLatestTemperatureDataFromList()
{
    return this.temperatureList.get(0);
}

public void clearTemperatureDataList()
{
    temperatureList.clear();
}

public int size()
{
    return temperatureList.size();
}
}

Вот где я запускаю графический интерфейс:

import java.rmi.RemoteException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class userMain extends Application
{
public FXMLLoader loader;

public static void main(String[] args)
{
    launch(args);
}   

@Override
public void start(Stage primaryStage) throws Exception 
{
    loader = new FXMLLoader();
    loader.setLocation(getClass().getResource("FXML/FXMLtemperature.fxml"));
    loader.setController(new GUItemperatureController());

    Parent root = loader.load();                    
    Scene scene = new Scene(root);      

    primaryStage.setTitle("GEMS - Test");
    primaryStage.setScene(scene);
    primaryStage.show();                
}
}

Ваш пример не кажется полным. У вас есть основной метод в вашем клиентском классе, но графический интерфейс никогда не выполняется, не создается и не используется где-либо. Мой ответ должен указать вам правильное направление, но было бы лучше, если вы обновите свой пример. Я обновлю свой ответ, если потребуется.

Max Vollmer 28.03.2018 00:03

@Max Vollmer Только что добавил основной класс, из которого я запускаю графический интерфейс.

RollerMobster 28.03.2018 00:10

У него есть собственный основной метод, так что это совершенно другое приложение. Ваша проблема не в доступе к чему-то в другом классе. Ваша проблема заключается в получении информации из другого приложения. Это как пойти на кулинарный форум и спросить, как достать лук с полки, помешивая сковороду, а потом оказывается, что вы говорите о полке для лука в супермаркете в другом городе на другом континенте. Ваша проблема не в том, чтобы достать лук с полки, а в том, чтобы доставить лук из супермаркета к вам домой.

Max Vollmer 28.03.2018 00:26

Я обновил свой ответ.

Max Vollmer 28.03.2018 00:38

@MaxVollmer Спасибо за разъяснения, у меня было ощущение, что я лаю не на то дерево. Можно ли добиться этого так, как сейчас? Или мне нужно все это переделать?

RollerMobster 28.03.2018 00:38
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
5
308
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Самая очевидная проблема, которую я обнаружил (и это может быть не все), заключается в том, что ваш список массивов зависит от метода. это не статично. Это означает, что к нему можно получить доступ только с помощью метода, в котором он возник. Самое простое решение для этого - добавить статический модификатор в ваш список массивов при его создании и создать его вне методов.

Совершенно не обязательно делать поле статическим, чтобы его можно было использовать в разных частях вашего приложения. Использование статических полей - это форма глобальное состояние, которая обычно является анти-шаблоном и не обязательна для этого варианта использования.

dimo414 27.03.2018 23:56

Вы не включили свою реализацию TemperatureList, но если, как вы говорите, это ArrayList, скорее всего, вы не правильно синхронизировать доступ между потоками. Крайне важно, чтобы вы правильно синхронизировали работу между потоками, иначе вы столкнетесь с каким-то неопределенным поведением, таким как нераспространение изменений или разрушение структур данных.

В java.util.collect.concurrent есть ряд потоковобезопасных коллекций, которые вы могли бы рассмотреть, иначе вам нужно будет убедиться, что вы используете блоки или методы synchronized везде, где вы работаете с этим списком.

OP имеет два отдельных экземпляра ModelManager. Это два разных списка в клиенте и в графическом интерфейсе.

Max Vollmer 27.03.2018 23:58

@MaxVollmer хороший улов, вот и все :) хотите опубликовать ответ?

dimo414 27.03.2018 23:59

@ dimo414 Только что :)

Max Vollmer 28.03.2018 00:01
Ответ принят как подходящий

Ваша проблема не в занятиях.

Вы запускаете два отдельных приложения. Один запускает ваш RMIsensorClient, а другой - ваш GUI. Они ничего не знают друг о друге, ваш RMIsensorClient и ваш Controller имеют свои собственные отдельные экземпляры ModelManager, и у вас нет нигде кода, который бы обменивался какими-либо данными между ними.

Вам нужно как-то сделать данные, которые вы хотите отображать в вашем графическом интерфейсе, доступными.

Одним из решений может быть использование для этого сетевого интерфейса. Создайте два разных ModelManager: один открывает и слушает ServerSocket, а другой использует Разъем в getLatestTemperatureData() для подключения к другому.

Используйте первый в вашем RMIsensorClient, а второй в GUI вашего Controller.

Исследование сетей на Java.

Это очень грубое решение, но есть множество отличных руководств по работе в сети и обмену данными между несколькими приложениями Java.

Спасибо, Макс, за вашу помощь, изучит сеть Java и, надеюсь, справится с этой задачей :)

RollerMobster 28.03.2018 00:47

Другие вопросы по теме