我应该使用静态方法还是实例方法?

时间:2015-08-31 05:19:14

标签: java variables methods static instance

我真的对静态与实例方法的概念感到困惑。我创建了一个BMR计算器。我使用不同的类从计算中分离了GUI。

public class Calculations {

/**
 * If user input is correct, this method will calculate the BMR value of the user given their input and measurement choices.
 * 
 * @param userAge, userHeight, userWeight
 * @return BMR Value as a string
 */
public static int calcBMR(int age, String gender, double height, double weight) {

    // This is the body of the calculations - different formulas used depending on gender. Conversions to kg and cm done earlier so no conversions needed here.
    if (gender.equals("M")) { // Uses male bmr formula if genderMale radiobutton is selected
        return (int) (Math.round((10 * weight) + (6.25 * height) - (5 * age) + 5)); // This is the Miffin St-Jeor formula, calculations done in cm/kg
    } else { // else gender.equals("F") - there are only 2 options for gender, M or F.
        return (int) (Math.round((10 * weight) + (6.25 * height) - (5 * age) - 161));
    }
}


/**
 * If the user selects the TDEE option, this method will be executed after the calcBMR() method. 
 * A value from the calcBMR() method will be passed down to this method, and is multiplied
 * by the activity level parameter passed into this method.
 * 
 * @param selectedActivityLevel
 * @return TDEE Value (as a string)
 */
public static int calcTDEE(double activityMultiplier, int bmr) {
    System.out.println(activityMultiplier);
    return (int) Math.round(bmr * activityMultiplier);
}

}

如您所见,这些方法是STATIC,但是传递给两个方法的变量都是实例变量。

我只通过以下几行调用这些方法:

            bmrValue = Calculations.calcBMR(userAge, userGender, userHeight, userWeight);
            bmrLabel.setText("<html><br /><font size=4>You have a <i><font color=#ce0000>BMR</font></i> of: " + "<font color=#59AF0E>" +  bmrValue + "</font></html>");
            if (tdeeYes.isSelected()) {
                userActivityLevel = activityMap.get(activityLevelBox.getSelectedItem());
                // Looks up selected item from combo box, which is the KEY. Then looks up the value to this key from the map - this value is the TDEE multiplier.
                tdeeLabel.setText("<html><br /><font size=4>You have a <i><font color=#ce0000>TDEE</font></i> of: " + "<font color=#59AF0E>" + Calculations.calcTDEE(userActivityLevel, bmrValue) + "</font></html>");
                }

变量定义为:

HashMap<String, Double> activityMap;
String[] activityLevels = {"Sedentary", "Lightly Active", "Moderately Active", "Very Active", "Extra Active"};


int userAge;
String userGender;
double userHeight;
double userWeight;
double userActivityLevel;

int bmrValue;

我是否正确使用静态/实例变量?之前我将所有参数变量都设置为静态,因为我知道静态方法只能访问静态变量。直到现在我还不知道参数可能是实例变量。

任何指导都将不胜感激。

4 个答案:

答案 0 :(得分:1)

对于初学者来说,静态变量和实例变量之间的区别在于,对于类的所有实例,只存在一个静态变量,而对于该类的每个实例都存在一个实例变量。

现在,当您谈论方法时,在大多数情况下,当您尝试从另一个静态方法(例如main)调用方法时,需要将方法设为静态。

一般来说,这种做法对OOP来说是错误的,你可能应该重新考虑程序的结构。

如果您可以提供有关用于调用这些方法的代码的更多详细信息,我将能够为您提供有关如何解决此问题的更多详细信息。

编辑: 根据您提供的新信息:

1)我相信bmrMain,BMRMain和Calculations都可以合并为一个类。应该调整新类的构造函数以读取输入(以及每个变量的getter和setter以增加灵活性 - 可选)

2)关于bmr部分的计算,有很多方法可以解决这个问题,因此我将继续提出我认为最好的方法。 添加一个带有文字的按钮&#34;点击计算&#34;或类似的东西,并实现一个ActionListener。操作侦听器将依次调用(无论何时单击按钮)计算所有内容的方法,最后它将更改JLabel上的文本。

动作侦听器的示例代码:

JButton button = new JButton("Text Button");
button.addActionListener(new ActionListener()
{
  public void actionPerformed(ActionEvent e)
  {
    //Call the methods for the calculation
    // bmr and tdee are temporary variables to store the results from the methods
    //handle them properly, or remove them if not needed (I just wrote a sample)
    int bmr = calcBMR(...); //pass the correct variables as arguments here
    int tdee;
    if(userHasPickedTDEE) {  tdee = calcTDEE(...); }  //and here
    label.setText(....);

  }
}); 

这两个步骤将照顾你的&#34;静态&#34;问题。

我建议您对event-driven programming

进行一些研究

这里有一些关于Action Listeners

的额外和更深入的阅读

如果您需要进一步的帮助或澄清,请告诉我:)

EDIT2:

通常,是的,为了保持代码的可管理性,将类分开是一个好习惯。但在这种情况下,我认为仅为2种方法创建一个新类有点多余。 然而,如果你想保持当前的结构,那么修复&#34;静态&#34;是: 1)从2种计算方法中删除静态。 2)第332行应

Calculations c = new Calculations();
bmrValue = c.calcBMR(userAge, userGender, userHeight, userWeight);

FINAL_EDIT:

嗯,这些问题很容易转移到他们自己的线程中。但是这里有一个有用的链接来自我刚刚做的快速谷歌搜索,这将有助于破坏静态关键字:

Static keyword in Java

答案 1 :(得分:0)

我使用静态变量的拇指规则有点像这样:

  1. 请勿使用static
  2. 当需要使用static时,请参阅(1)
  3. 对于大多数情况,上述拇指规则有效。但是,我们有JDK,apache-commons库推广的标准习语。调查它们你会发现:

    1. 可以使用包含所有静态方法的实用程序类。
    2. 可以使用类中的static字段创建常量。但是,使用Enum使用Calculations可能是更好的选择。
    3. 在同一个班级上工作的一个实用工具函数就可以了。
    4. 至于代码的重组,你应该看看谁拥有这些数据。在这种情况下,Calculations类的两个方法都使用来自另一个类的数据。将方法移到另一个类中。

      import datetime as dt StartDate = dt.date(2008,1,1) EndDate = dt.date(2015,8,1) dfIndex = pd.date_range(start=StartDate,end=EndDate,freq='H') dfColumns = ['C1','C2','C2'] df = pd.DataFrame(index=dfIndex,columns=dfColumns) 类存在的唯一原因应该是,如果您使用的是其他多个不相关的类的方法。如果它们是相关的,你会尝试建模它们之间的关系并看看这些方法的去向。

答案 2 :(得分:0)

每当我的类被用来调用那些方法时,我就会使用static(即我的main方法调用静态方法来设置主类中的变量等)。我相信这是KDM提到的“实用”类。我使用静态或实用程序类的一个小例子:

class Utility {
  public static int add(int a, int b) {
    // You would, of course, put something besides simple addition here
    return a + b;
  }
}

class Main {
  public static void main(String[] args) {
    int a = 2, b = 3;
    int sum = Utility.add(a, b);
    System.out.println(sum);
  }
}

另一方面,如果你有一个更接近实际对象的类,具有自己的属性,请远离静态。如果使用static,那么您希望成为单独对象的类的每个实例将以相同的值结束。

根据您的类的名称和功能,您似乎有一个实用程序类。静态应该没问题,但可能没有必要。但是,假设你想将这个类用于计算BMR的多个“人”类实例(每个实例都是唯一的),那么我会将calcBMR()放在一个人类中并使其成为非静态,以便每个人都有自己的calcBMR()

编辑:也许这也会有所帮助:

实例 - &gt;实例化:new Calculations().instanceMethod();

静态 - &gt;类本身,类的“状态”:Calculations.staticMethod();

答案 3 :(得分:0)

如果您认为,我想要实例方法或静态方法,您将会迷失方向。 Java不是面向方法的,它是面向对象的。因此,对于您的功能,决定您是想要一个对象还是一个纯函数(其中纯函数意味着没有依赖性,没有副作用,它严格地说是一个给出这个函数的函数)。

将此模型作为对象进行建模可能会很好,因为您有描述用户某些方面的信息,将它们组合在一起可能是有意义的:

public class User {
    private int age;
    private String gender; // todo: use an Enum
    private double height;
    private double weight;
    private String activityLevel; // todo: use an Enum

    public User(int age, String gender, double height, double weight,
        String activityLevel) {
        this.age = age;
        this.gender = gender;
        this.height = height;
        this.weight = weight;
        this.activityLevel = activityLevel;
    }

    public double calculateBmr() {
        int offset = gender.equals("M") ? 5 : -161;
        return (int) (Math.round((10 * weight) 
            + (6.25 * height) - (5 * age) + offset));
    }
}

等。这样我们就不必在变量前面加上&#34; user&#34;,它们全部放在一个对象中。对象是用于收集相关信息的组织方案,实例方法是使用对象信息的函数。

另一种方法是创建一个实用程序类:

public final class UserCalcUtil {
    private UserCalcUtil() {} // no point instantiating this

    public static int calculateBmr(String gender, double height, 
    double weight, int age) {
        int offset = gender.equals("M") ? 5 : -161;
        return (int) (Math.round((10 * weight) 
            + (6.25 * height) - (5 * age) + offset));            
    }
}

在这里,您需要单独跟踪用户数据,并在想要计算某些内容时将其传递给静态方法。实用程序类是单独静态方法的转储点(您可以将其视为函数)。

是否要使用对象或实用程序类取决于您希望如何组织数据并对其进行计算。如果您始终对单个对象进行计算,或者将计算移动到实用程序类中,如果您需要多个不相关的类,那么将用户的数据与对该数据起作用的方法一起打包可能会更方便做计算。由于Java对面向对象的构造有更多的支持,因此采用对象方法通常是有意义的。

你可以使用静态方法,但是除了常量之外的任何东西都要避免使用静态变量(public static final,其类型是不可变的)。