【问题标题】:Java: Why aren't my variables passed to the constructor usable by my method?Java:为什么我的变量不能传递给我的方法可用的构造函数?
【发布时间】:2013-06-26 10:30:03
【问题描述】:

所以我在 main 中声明了一些变量并创建了一个新对象;将变量作为参数传递给构造函数。现在,当我在类中调用一个方法时,我会认为这些变量可以被该方法访问,而不必将它们作为参数传递给它。不是这样吗?

代码如下:

import java.util.Scanner;

public class Step2_lab11 {

    public static void main(String[] args) {

        final int TAO = 50;
        final double DELTA_MINUTES = 0.1;

        System.out.println("VINETS AVKYLNINGSTID \n");
        System.out.println("Ange vinets temperatur:");

        Scanner userIn = new Scanner(System.in);
        double wineTemp = userIn.nextDouble();

        System.out.println("Vinets önskade temperatur:");
        double preferredTemp = userIn.nextDouble();

        System.out.println("Kylens/frysens temperatur:");
        double chillTemp = userIn.nextDouble();

        WineChiller wineChiller = new WineChiller(wineTemp, preferredTemp, chillTemp);

    }

}

这是 WineChiller.java 类:

public class WineChiller {

    public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
        getChillingTime();

    }

    public void getChillingTime() {

        while(wineTemp>preferredTemp)
        {
            elapsedTime += DELTA_MINUTES;
            double dT = (wineTemp - chillTemp) * DELTA_MINUTES  / TAO;
            wineTemp -= dT;
        }
        System.out.println(Math.round(elapsedTime));

    }

}

为什么 getChillingTime 不能将 wineTemp 等解析为变量?

编辑添加:非常感谢指点家伙。但是还有一个额外的警告!这些说明似乎暗示 WineChiller 类应该只包含构造函数和方法 getChillingTime,并且 getChillingTime 不应该带参数!作业纸上有错字吗?

【问题讨论】:

  • 简单...getChillingTime方法没有输入参数。
  • 传递给构造函数的东西只是构造函数可以使用的东西,它不会存储它们,它可能会对它们执行一些数学运算,或者将它们标准化然后存储它们。它完全取决于构造函数如何处理它们,而你的构造函数决定对它们不做任何事情。请注意,您可以在大多数优秀的 IDE 中根据对象字段自动生成构造函数(例如,在 netbeans 中,Atl+insert 会显示该选项)
  • 按照你想象的方式行事会导致真正的问题;拥有多个构造函数可能非常有用,但它会是一个真正的大杂烩(对您和编译器而言),基于多个构造函数将不同的变量全部协商以将其变量作为字段来准确确定对象字段是什么。然后保证该类肯定具有运行其任何方法所需的一切,而不管调用了哪个构造函数
  • 作为一个非常简单的示例,构造函数可能很乐意采用 Vector3d、Vector3f 或双精度数组(大小为 3)。在每种情况下,它(如果需要)在存储之前将其转换为首选的 Vector3d 格式。如果构造函数只是猜测它可能会存储所有 3 种格式,除了 1 之外的所有格式都为空,具体取决于您调用的构造函数

标签: java class methods


【解决方案1】:

虽然这在 Scala 或 Ceylon 等语言中可能是可能的(见下文),但在 Java 中,您必须将构造函数参数显式分配给实例变量。因此:

public class WineChiller {

    double wineTemp;
    double preferredTemp;
    double chillTemp;

    public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
        this.wineTemp = wineTemp;
        this.preferredTemp = preferredTemp;
        this.chillTemp = chillTemp;

        getChillingTime();
    }

构造函数参数仅在构造函数范围内可见。构造函数调用您的 getChillingTime() 的事实无关紧要。如果您希望它们在 WineChiller 实例的范围内可见,则必须在该类中创建成员。然后该类的所有方法都可以访问实例成员。

无论如何,我强烈建议您通读 Java 教程。这是一个:

http://docs.oracle.com/javase/tutorial

其他 JVM 语言的构造函数

我认为您主要是在与 Java 的冗长作斗争,您必须将构造函数参数显式复制到实例字段中才能实现 encapsulation。其他语言更优雅地解决了这个问题,构造函数可以与类本身一起隐式定义。但是,它们仍会转换为与上述 Java 代码等效的内容。例如:

斯卡拉:

class Greeter(message: String) {
    def SayHi() = println(message)
}

val greeter = new Greeter("Hello world!")
greeter.SayHi()

此处的示例:http://joelabrahamsson.com/learning-scala-part-four-classes-and-constructors/

锡兰

class Point(Float x, Float y) { ... }
object origin extends Point(0.0, 0.0) {}

此处的示例:http://ceylon-lang.org/documentation/1.0/spec/html_single/

【讨论】:

  • @Benjamin 我认为这些说明试图强迫您使用字段(方法中的无参数强烈暗示了这一点)。这并不让我感到惊讶,因为不熟悉面向对象编程的人经常会尝试传递函数需要完成其工作的所有内容。阅读“不应该包含其他任何东西”和“没有函数参数”会使问题变得不可能,除非字段被豁免。这也是一个奇怪的问题
  • 这会让我吃惊,因为长期而言,空的 getChillingTime () 方法是正确的方法。问题的要求是为您指明正确的方向,并将所有内容传递给该函数在技术上是可行的,但这样做的方法是错误的
  • @Benjamin 如果我完全没有限制地做到这一点,我会创建preferedTemp 和chillTemp 字段,因为它们是冷却器的属性,但我会让函数将酒温度作为争论,因为这会因瓶子而异。
  • 我很确定您应该使用字段。如果这是关于学习 Java,那么这是处理封装的一种非常标准的方式,因此是此类课程的一个很好的例子。
  • 事实上,如果你不使用字段,你可能根本不去创建一个对象;只需对所有需要他们需要的参数的东西使用静态方法。 (这将是一个坏主意,并且完全颠覆了 java 不要这样做
【解决方案2】:

传递给方法的变量范围是方法本身

换句话说,一旦方法执行结束,传递给方法的变量就会被销毁(收集垃圾)。

构造函数是一种特殊的方法,用于创建该类型的实例。

由于您还没有创建传递给类型构造函数的变量的副本,因此它们丢失了,因此出现了错误。

要使您的代码正常工作,请在您的类中声明 字段

public class WineChiller {

    private double wineTemp;
    private double preferredTemp;
    private double chillTemp;

    public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
        this.wineTemp = wineTemp;
        this.preferredTemp = preferredTemp;
        this.chillTemp = chillTemp;
        getChillingTime();

    }

    public void getChillingTime() {

        while(wineTemp>preferredTemp)
        {
            elapsedTime += DELTA_MINUTES;
            double dT = (wineTemp - chillTemp) * DELTA_MINUTES  / TAO;
            wineTemp -= dT;
        }
        System.out.println(Math.round(elapsedTime));

    }

}

【讨论】:

    【解决方案3】:

    为什么 getChillingTime 不能将 wineTemp 等解析为变量?

    局部变量不是这样工作的。 wineTemp 仅限制在 WineChiller constructor 内部。您要么必须将其作为参数传递给 getChillingTime() 方法并使用它,要么将其设为类的实例变量

     public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
            getChillingTime(wineTemp);
        }
     public void getChillingTime(double wineTemp) {
    

    或:

    public class WineChiller {
    private double wineTemp;
        public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
            this.wineTemp = wineTemp;
            getChillingTime();
        }
    

    我推荐第二种方法,这是标准方法。

    【讨论】:

      【解决方案4】:

      您在构造函数中使用的wineTemp 需要设置在某个位置,以便可以在getChillingTime 方法中访问。

      建议修复

          public class WineChiller {
      
              private double wineTemp;
              public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
                  this.wineTemp = wineTemp;
                  ...
              }
      
              ...
      

      【讨论】:

        【解决方案5】:

        在你的主函数里有这样的

        WineChiller wineChiller = new WineChiller();
        wineChiller.getChillingTime(wineTemp, preferredTemp, chillTemp);
        

        在你的 WineChiller 类中有获取这些输入的方法

        public void getChillingTime(double wineTemp, double preferredTemp, double chillTemp)
        {
        //do something
        }
        

        【讨论】:

          【解决方案6】:

          或者,传递参数,因为参数的范围不会超出方法本身

          public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
              getChillingTime(wineTemp, preferredTemp, chillTemp); // pass the arguments
          }
          
          public void getChillingTime(
                      double wineTemp, double preferredTemp, double chillTemp) {
              // ...
          }
          

          或者,将它们保存为 instance 成员字段(推荐),这些字段可以从每个 instance 方法自动访问

          public class WineChiller {
          
              // instance member fields
              private double wineTemp;
              private double preferredTemp;
              private double chillTemp;
          
              public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
                  this.wineTemp = wineTemp;
                  this.preferredTemp = preferredTemp;
                  this.chillTemp = chillTemp;
          
                  getChillingTime();
              }
          
              public void getChillingTime() {
                  // ...
              }
          }
          

          【讨论】:

            【解决方案7】:

            作为参数传递给方法的变量仅对该方法是本地的。如果您希望在其他方法中使用它们,则必须将它们存储为实例变量或再次将它们作为参数传递。

            public class WineChiller {
            
                double mWineTemp;
                double mPreferredTemp;
                double mChillTemp;
            
                public WineChiller(double wineTemp, double preferredTemp, double chillTemp) {
            
                    mWineTemp = wineTemp;
                    mPreferredTemp = preferredTemp;
                    mChillTemp = chillTemp;
            
                    getChillingTime();
            
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-03-29
              • 2019-03-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多