Статический класс обновляет статические переменные, но статические методы не обновляют статические переменные

Я просмотрел несколько страниц, но у большинства, похоже, просто проблемы с пониманием того, что означает static. Проблема, с которой я столкнулся, заключается в том, что мы используем статический класс, FocusListener и ActionListener. Класс, у которого есть обработка событий, вызывает статический класс, и когда поле JText заполнено и удалено от FocusListener, мгновенно обновляет эту статическую переменную. Когда все поля JText заполнены и FocusListener обновил переменные, появляется JButton отправки. Как только кнопка нажата, статические методы вызываются для завершения любых переменных, которые вычисляются с использованием ранее обновленных переменных. Пользователь об этом не знает. Однако переменные не обновляются, и мне любопытно, неправильно ли я это реализую? Заранее спасибо.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class WellParameters extends JInternalFrame implements FocusListener, ActionListener {
    JLabel  measuredDepthL, ..., pitGainL, drillBitSizeL, 
                mudInActivePitsL, mainPanelLabel;
        JTextField  measuredDepthT, ..., pitGainT, drillBitSizeT, mudInActivePitsT;
        JPanel  mainPanel, firstPanel, secondPanel, thirdPanel, fourthPanel, submitButtonPanel;
        JButton submitButton;

        WellParameters() {  
            super("Well Parameters", true, true, false, true);
            this.setBounds(0, 0, 600, 385);
            this.setVisible(true);
            this.setLayout(new BorderLayout());

            ...//GUI Stuff

            this.add(submitButtonPanel, BorderLayout.SOUTH);
        }
    @Override
    public void focusGained(FocusEvent e) {} //Ignore this!

    @Override
    public void focusLost(FocusEvent e) {
        try {
            if(e.getSource() == measuredDepthT) {
                KillWellCalculations.measuredDepth = Integer.parseInt(measuredDepthT.getText());

              ...//Others 

            } else if(e.getSource() == mudInActivePitsT) {
                KillWellCalculations.mudInActivePits = Double.parseDouble(mudInActivePitsT.getText());
            }
        } catch (Exception ignore) {}

    }
    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            if(e.getSource() == submitButton) {
            System.out.println(KillWellCalculations.pumpEfficiency);
            KillWellCalculations.setPressureBeforeCasingBurstAndFormationFracture(); //Doesn't work
            KillWellCalculations.setCirculatingPressures();
            KillWellCalculations.setTriplexPumpCapacity();
            System.out.println(KillWellCalculations.mudInActivePits);
            System.out.println(KillWellCalculations.pumpFactor);
            System.out.println(KillWellCalculations.finalCirculatingPressure);}
        }
        catch(Exception ignore) {}
    }
}

Это был графический интерфейс, а это статический класс... Это два отдельных класса. Не в том же файле. пакет killwellsheet;

public class KillWellCalculations {

    static int measuredDepth;           //Total Depth from open hole to bottom

        ... //Tons of other variables

    static double totalStrokes;         //add strokes

    //Used to set different circulating pressures for the well
    public static void setCirculatingPressures() {
        initialCirculatingPressure = circulatingPressureKillRate + shutInDrillPipePressure;
        finalCirculatingPressure = circulatingPressureKillRate * (killMudWeight/currentMudWeight);
    }   
    //Calculates capacity of anypipe
    private static double pipeCapacity(double length, double insideDiameter) {
        return length * ((insideDiameter*insideDiameter)/1029.4);
    }
    //Calculates capacity of the annulus/open hole
    private static double annulusCapacity(double length, double insideDiameter, double outsideDiameter) {
        return length * (((insideDiameter*insideDiameter)-(outsideDiameter*outsideDiameter))/1029.4);
    } 

         ... //Other functions

    //Set the casing burst pressure
    public static void setPressureBeforeCasingBurstAndFormationFracture() {
        beforeCasingBurst = burstPressure*0.70;
        beforeFormationFracture = (0.052*casingShoeDepth)*(fracGradientMWEquivalent - currentMudWeight);
    }
    public static void bariteNeedAndVolumeIncrease() {
        bariteSacksRequired = (totalMudVolume/100)*((1099*(killMudWeight-currentMudWeight))/(28.35-killMudWeight));
        increaseInMudVolume = 0.091*bariteSacksRequired;
    }
    public static void pumpStrokes() {
        surfaceToBit = (mudInDrillString)/pumpFactor;
        bitToSurface = (mudInAnnulus)/pumpFactor;
        totalStrokes = surfaceToBit + bitToSurface;
    }
}//end class

person FossilizedCarlos    schedule 29.04.2011    source источник
comment
Я использовал эти отпечатки линий для устранения неполадок. Они показывают мне, сработали методы или нет.   -  person FossilizedCarlos    schedule 29.04.2011
comment
почему здесь статические переменные и методы? статический внутренний класс просто означает, что внутренний класс не требует существования экземпляра внешнего класса.   -  person Hovercraft Full Of Eels    schedule 29.04.2011
comment
Да, как сказал Hovercraft, здесь вообще нет смысла для статических методов и статических переменных. Это только все усложняет.   -  person Paŭlo Ebermann    schedule 29.04.2011
comment
Это два отдельных класса. Это файлы KillWellCalculations.java и WellParameters.java.   -  person FossilizedCarlos    schedule 29.04.2011
comment
@PetroEkos: я не понимаю, что ваш комментарий выше о том, что файлы представляют собой два отдельных класса, связан с нашими опасениями, что вы используете модификатор static ненадлежащим образом. Опять же, все ваши переменные и методы (кроме основных и некоторых других исключений) не должны быть статическими.   -  person Hovercraft Full Of Eels    schedule 29.04.2011
comment
Я думаю, поскольку класс был не чем иным, как вычислениями, мы подумали, что нам не нужно создавать для него какие-либо экземпляры. Вы рекомендуете просто иметь нестатический класс и создать экземпляр? Спасибо.   -  person FossilizedCarlos    schedule 29.04.2011
comment
Вы можете распечатать трассировку стека для отладки в ваших предложениях catch. Игнорирование исключений может затруднить отслеживание поведения кода.   -  person Rob Heiser    schedule 29.04.2011
comment
@Petro: но поскольку у него есть поля, кажется, что у класса есть состояние и, следовательно, это больше, чем служебный класс.   -  person Hovercraft Full Of Eels    schedule 29.04.2011
comment
@Hover Даже в качестве обычного класса и метода, вызываемого одной из переменных класса, они не обновляют значения. Нужно ли передавать параметры, даже если они глобальные? Я думаю, что моя проблема заключается в вызове моих методов, а не в том, являются ли они статическими или нет.   -  person FossilizedCarlos    schedule 29.04.2011
comment
@Petro: я не уверен. Возможно, вы захотите создать гораздо меньшую программу, которая компилируется, может выполняться, имеет один или два статических метода и демонстрирует вашу проблему. Таким образом, мы сможем запустить и изменить ваш код, увидеть проблему и, возможно, лучше предложить решение.   -  person Hovercraft Full Of Eels    schedule 29.04.2011
comment
@Petro: кроме того, откуда ты знаешь, что переменные не обновляются? Вы основываете это на том, что ваш графический интерфейс не показывает изменения в JTextFields или JLabels? Если да, то где вы устанавливаете текст этих JTextFields/JLabels? Опять же, небольшая компилируемая работающая программа очень поможет. Это называется созданием SSCCE.   -  person Hovercraft Full Of Eels    schedule 29.04.2011
comment
@Hover У меня внизу есть system.out.println(), которые показывают мне значения. Они дают мне этот вывод... 11.0 1.0 0.0 0.0 Это показывает, что 1-й два из обновления переменных из Jtextfield, а 2-й после вызова метода.   -  person FossilizedCarlos    schedule 29.04.2011
comment
Пожалуйста, не используйте изменяемую статику!!   -  person Tom Hawtin - tackline    schedule 29.04.2011


Ответы (1)


Некоторые пояснения... Читая ваш код, единственное, что я вижу, это то, что ваш класс WellParameters реализует интерфейсы FocusListener и ActionListener (а не статические классы). Насколько я могу понять из вашего кода, методы focusGained(FocusEvent e) и focusLost(FocusEvent e) реализованы из прежнего интерфейса и обновляют значения статический класс, и вы будете зависеть от тех же вычисленных значений в событии ActionListener actionPerformed(). Проблема, с которой вы сталкиваетесь здесь, - это состояние гонки относительно значений статического экземпляра.

http://java.sun.com/docs/books/performance/1st_edition/html/JPApGC.fm.html A.3.4 Недоступно

Объект переходит в недостижимое состояние, когда на него не существует более сильных ссылок. Когда объект недоступен, он является кандидатом на сбор. Обратите внимание на формулировку: тот факт, что объект является кандидатом на сбор, не означает, что он будет немедленно собран. JVM может откладывать сбор до тех пор, пока не возникнет немедленная потребность в памяти, потребляемой объектом. Важно отметить, что не любая сильная ссылка будет удерживать объект в памяти. Это должны быть ссылки, идущие по цепочке от корня сборки мусора. Корни GC — это особый класс переменных, который включает в себя

  • Temporary variables on the stack (of any thread)
  • Static variables (from any class)
  • Special references from JNI native code

  • Основываясь на этой документации по сборке мусора, я подозреваю, что ВСЕ статические ссылки вашего класса KillWellCalculations подходили для сборки мусора после вызова методов FocusEvent, и по этой причине они не доступны к моменту запуска события actionPerformed().

    Вы по-прежнему можете использовать статические методы класса KillWellCalculations в качестве служебного класса, только если этот класс используется другими классами. Если нет, вы можете преобразовать его в класс Value, который будет выполнять вычисления для вас БЕЗ статических ссылок. Поскольку вам нужно иметь ссылку на экземпляр класса, который содержит значения расчета... Например:

    public Class CalculatedValues {
         private int measuredDepth;
         private double mudInActivePits;
    
         public static CalculatedValues makeNew() {
              return new CalculatedValues();
         }
    
         public void setMeasuredDepth(String measuredDepthTString) {
               if (measuredDepthTString == null) {
                    throw new IllegalArgumentException("The measured depth must be provided.");
               }
               try {
                    this.measuredDepth = Integer.parseInt(measuredDepthTString);
               } catch(NumberFormatException nfe) {
                    throw new IllegalArgumentException("The value provided is not an interger.");
               }
         }
         public int getMeasuredDepth() {
              return measuredDepth;
         }
    
         public void setMudInActivePitsT(String mudInActivePitsTString) {
               if (mudInActivePitsTString == null) {
                    throw new IllegalArgumentException("The measured mudInActivePits must be provided.");
               }
               try {
                    this.mudInActivePits = Double.parseDouble(measuredDepthTString);
               } catch(NumberFormatException nfe) {
                    throw new IllegalArgumentException("The value provided is not an double.");
               }
         }
         public double getMeasuredDepth() {
              return mudInActivePits;
         }
    
         //...
         //...
         // MORE THE OTHER VALUES/PROPERTIES IMPORTANT/NEEDED BY THE CALCULATION. 
    
         public void doAllCalculations() {
              // YOU HAVE TO IMPLEMENT THE LOGIC FOR THOSE ONES, OPTIONALLY USING THE SAME UTILITY/HELPER STATIC METHODS FROM 
              setPressureBeforeCasingBurstAndFormationFracture();
              setCirculatingPressures();
              setTriplexPumpCapacity();
         }
    }
    

    Затем измените конструктор класса, чтобы он имел экземпляр объекта значения:

    ... 
    ...
    // THE VALUE OBJECT REFERENCE WITH THE VALUES YOU NEED TO HOLD DURING THE FORM INTERACTION
    private CalculatedValues calculatedValues;
    
    WellParameters() {  
        super("Well Parameters", true, true, false, true);
        this.setBounds(0, 0, 600, 385);
        this.setVisible(true);
        this.setLayout(new BorderLayout());
    
        ...//GUI Stuff
    
        this.add(submitButtonPanel, BorderLayout.SOUTH);
    
        // THE VALUE OBJECT REFERENCE...
        calculatedValues = CalculatedValues.makeNew();
    }
    

    Затем обновите ссылку с расчетом:

    @Override
    public void focusLost(FocusEvent e) {
        try {
            if(e.getSource() == measuredDepthT) { 
                //KillWellCalculations.measuredDepth = Integer.parseInt(measuredDepthT.getText());
                // the exceptions thrown can be caught in the catch below and you can display the error message from the value class.
                calculatedValues.setMeasuredDepth(measuredDepthT.getText());
    
              ...//Others 
    
                // collect other values as well...
    
            } else if(e.getSource() == mudInActivePitsT) {
                //KillWellCalculations.mudInActivePits = Double.parseDouble(mudInActivePitsT.getText());
                // do try/catch for the possible runtime exception and display an error message
                calculatedValues.setMudInActivePitsT(mudInActivePitsT.getText());
    
            }
        } catch (Exception ignore) { 
        }
    
    }
    

    Обновления на последнем шаге также с использованием ссылки на экземпляр:

      @Override
        public void actionPerformed(ActionEvent e) {
          try {
            if(e.getSource() == submitButton) {
            System.out.println(KillWellCalculations.pumpEfficiency);
            // THE REFERENCES THAT THIS STATIC METHOD USE WERE ALL GARBAGE-COLLECTED AT THE TIME OF THE CALL... IF SHOULD HAVE THE CALCULATED METHODS IN THE VALUE CLASS. SOMETHING LIKE THE FOLLOWING:
            // KillWellCalculations.setPressureBeforeCasingBurstAndFormationFracture(); //Doesn't work
            //KillWellCalculations.setCirculatingPressures();
            //KillWellCalculations.setTriplexPumpCapacity();
            //System.out.println(KillWellCalculations.mudInActivePits);
            //System.out.println(KillWellCalculations.pumpFactor);
            //System.out.println(KillWellCalculations.finalCirculatingPressure);}
    
            // DO THE FINAL CALCULATION IN A SINGLE METHOD IN THE VALUE OBJECT.
            calculatedValues.doAllCalculations();
    
            // HERE ARE THE GETTERS FROM THE CALCULATED VALUES OF THE DO ALL CALCULATIONS YOU HAVE TO IMPLEMENT.
            System.out.println(calculatedValues.getMudInActivePits());
            System.out.println(calculatedValues.getPumpFactor());
            System.out.println(calculatedValues.getFinalCirculatingPressure());}
    
            // CONSIDERING YOU'RE DONE WITH THE VALUES, JUST CLEAR THE INSTANCE VALUES
            // AS THIS REFERENCE IS NOT STATIC AND IT WILL NOT BE GARBAGE-COLLECTED. 
            calculatedValues.clearValues();
        }
        catch(Exception ignore) {}
      }
    

    Я проделал некоторую работу, связанную с графическим интерфейсом... Вы можете увидеть очень похожий пример по адресу http://code.google.com/p/marcellodesales-cs-research/source/browse/trunk/grad.-ste-ufpe-brazil/ptf-add-on-dev/src/br/ufpe/cin/stp/ptfaddon/view/swing/execution/JWizardInternalFrame.java

    Удачи!

    person Marcello de Sales    schedule 29.04.2011