Benjamin Lindqvist
Benjamin Lindqvist

Reputation: 4610

Java: Why aren't my variables passed to the constructor usable by my method?

So I declared some variables in main and created a new object; passing the variables as arguments to the constructor. Now, when I call a method inside the class, I would have thought that these variables would be accessible by the method, WITHOUT having to pass them as arguments to it. Is this not so?

Here's the code:

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);

    }

}

Here's the class 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));

    }

}

Why can't getChillingTime resolve wineTemp etc to variables?

EDITED TO ADD: Much appreciate the pointers guys. But there's an additional caveat! The instructions seems to imply that the class WineChiller should ONLY contain the constructor and the method getChillingTime, and that getChillingTime SHOULD NOT take arguments! Is there a typo in the assignment paper?

Upvotes: 3

Views: 8371

Answers (7)

Lukas Eder
Lukas Eder

Reputation: 220762

While this would probably be possible in languages like Scala or Ceylon (see below), in Java, you have to assign constructor arguments explictly to instance variables. Thus:

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();
    }

Constructor arguments are visible only in the scope of the constructor. The fact that the constructor calls your getChillingTime() is irrelevant. If you want them to be visible within the scope of a WineChiller instance, you'll have to create members in that class. All methods of that class can then access instance members.

Anyway, I strongly suggest you thoroughly read through a Java tutorial. Here's one:

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

Constructors in other JVM languages

I think you're mainly struggling with the verbosity of Java, where you have to explicitly copy constructor arguments onto instance fields in order to implement encapsulation. Other languages have solved this more elegantly, where constructors can be implicitly defined along with the class itself. However, they would still translate to something equivalent of the above Java code. For instance:

Scala:

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

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

Example from here: http://joelabrahamsson.com/learning-scala-part-four-classes-and-constructors/

Ceylon

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

Example from here: http://ceylon-lang.org/documentation/1.0/spec/html_single/

Upvotes: 5

MaxAlexander
MaxAlexander

Reputation: 560

Variables passed as arguments to a method are local to that method only. If you wish to use them in another method, you must either store them as instance variable or pass them again as arguments.

public class WineChiller {

    double mWineTemp;
    double mPreferredTemp;
    double mChillTemp;

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

        mWineTemp = wineTemp;
        mPreferredTemp = preferredTemp;
        mChillTemp = chillTemp;

        getChillingTime();

    }

Upvotes: 0

Ravi K Thapliyal
Ravi K Thapliyal

Reputation: 51711

Either, pass the arguments because the scope of parameters does not extend beyond the method itself

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

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

Or, save them as instance member fields (recommended) which are automatically accessible from every instance method

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() {
        // ...
    }
}

Upvotes: 0

sanbhat
sanbhat

Reputation: 17622

The scope of variables passed to a method is the method itself

In other words, a variable passed to a method gets destroyed (garbage collected) once the method execution ends.

Constructors are special kind of methods, which are used to create that type's instances.

Since you haven't created a copy of the variables passed to the constructor in the type, they got lost, hence your error.

To make your code work, declare the fields in your class

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));

    }

}

Upvotes: 2

John
John

Reputation: 281

In your main function have it like this

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

IN your WineChiller class have the method to get those input

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

Upvotes: 0

Ajay George
Ajay George

Reputation: 11875

the wineTemp you take in the constructor needs to be set somewhere so that it is accessible within the getChillingTime method.

Proposed Fix

    public class WineChiller {

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

        ...

Upvotes: 0

PermGenError
PermGenError

Reputation: 46408

Why can't getChillingTime resolve wineTemp etc to variables?

Thats not how local variables work. wineTemp is only confined inside WineChiller constructor. you either have to pass it as argument to getChillingTime() method and use it or, make it an instance variable of your class.

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

OR:

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

I recommend the 2nd approach which is standard way.

Upvotes: 0

Related Questions