How do I set default values for instance variables? - java

In my assignment, I'm given a Food class like this:
class Food {
private String name; // name of food
private int calPerServing; // calories per serving
// must be >= 0
// min storage temperature // must be >= 0.
// max storage temperature // must be <= 100.
private float minTemp; private float maxTemp;
int getCalories() {
return calPerServing;
}
}
And I'm having trouble with this part of the assignment:
Write a constructor method for the Food class, to set the default name to "Pie", the default calPerServing to 500, the default minTemp to 25, and the default maxTemp to 75.
How do I set default values for name, calPerServing, etc.?

(I'm surprised to get to page three of search results without finding a simple version of this question to point to.)
You have two choices for setting the default value of an instance variable (sometimes called an "instance field"):
Using an initializer on the declaration.
Using an assignment in a constructor.
Say I have a class Example and an instance variable answer whose default should be 42. I can either:
// Example of #1 (initializer)
class Example {
private int answer = 42;
// ...
}
or
// Example of #2 (assignment within constructor)
class Example {
private int answer;
Example() {
this.answer = 42;
}
}
Initializers (#1) are processed during construction just before any other logic in your constructor (but after calling the superclass constructor).
Which you use depends on the class and, to an extent, personal style. If the class is going to have multiple constructors but I want answer to default to 42 regardless of which constructor is used, using initialization makes sense because then I just put it in one place instead of putting it in every constructor. If the default for answer will vary depending on which constructor is used, or depending on a parameter the constructor(s) receives/receive, setting it in the constructor makes sense.
In your specific case, the assignment tells you to use a constructor.

If you are setting default values, you simply assign a value when you declare the variable like so:
private String name = "Pie";
private int calPerServing = 500;
and so it. If you want to overwrite those variables, you can. Alternatively, you can do it in the constructor like so:
class Food {
private String name; // name of food
private int calPerServing; //
public Food(){
this.name = "Pie";
this.calPerServing = 500;
}
}

Related

Why does javac allow fields to be defined after methods that use them in a class?

I have noticed that when you execute a statement like sum=a+b;
we need the three fields initialized prior to using them in this operation
ie
int a=1
int b=1;
int sum=0;
sum=a+b;
.
My understanding is, this is because javac works like an interpreter and reads line by line.
But when it comes to methods where we call and pass values to fields inside a class we can define the fields after method declaration.
public class Dog extends Animal{
public Dog(String name, int weight, int teeth, String coat) {
super(name, true, true, weight);
this.tail=true;
this.eyes=2;
this.teeth=teeth;
this.coat=coat;
}
private int eyes;
private boolean tail;
private int teeth;
private String coat;}
The parameters eyes, tail, teeth, and coat have been defined after they were used to pass values to the constructor.
How does javac understand that there is a variable after the method.
Is this allowed because we can only define fields and not do any operations on them in a class definition?
Javac is Java Compiler Compiles your Java code into Bytecode
JVM is Java Virtual Machine Runs/ Interprets/ translates Bytecode into Native Machine Code
This error occurs only with local variables because the compiler does not set the default value for the local variables. In the case of instance variables, the compiler sets default values, for example, 0 for integer, null for string, etc.
In the above case if you don't set values in the constructor still your instance variables will be initialized by default values.
private int eyes = 0;
private boolean tail = false;
private int teeth = 0;
private String coat = null;
But same is not true for local variables a, b or sum.
sum can be uninitialized because you are assigning the values to the sum before using it. That is the statement sum = a+b will assign value and before you use it somewhere else may be like sum2 = sum, its assured that sum has a value.
A local variable declaration (and eventual initialization) is executed together with the block it is in, and being accessed from;
an instance field declaration (and initialization) is executed when the instance is created, before the methods are executed 1.
On the other side this is not allowed:
public class Dog extends Animal {
private int total = eyes + teeth; // ERROR!
private int eyes = 2;
private int teeth = 24;
}
above code does not compile - that is intentional!
while this is valid:
public class Dog extends Animal {
private int eyes = 2;
private int teeth = 24;
private int total = eyes + teeth; // OK
}
Why ...? Short answer: it is specified that way, see Java Language Specification (JLS) - Scope of a Declaration:
The scope of a declaration of a member m declared in ... a class or interface C (§8.2, §9.2) is the entire body of C, ...
The scope of a local variable declared in a block by a local variable declaration statement (§14.4.2) is the rest of the block,...
One reasons for that is to avoid cyclic references as mentioned in the JLS, see examples on link below 1. Also explained in this answer by Hoopje.
1 - exception are references to fields in initializers, see Restrictions on Field References in Initializers
This has nothing to do with the difference between an interpreter and a compiler. It is just a rule added to language to prevent two fields to refer to each other in their initialization code. For example, what would be the initial values of the fields in the following class?
class A {
int a = b * b;
int b = a + 1;
}
Of course, the Java designers could have decided to allow forward references, and only generate an error when such cycles are detected. But they decided otherwise, and I think that that was the right decision.
There is no reason to forbid forward references to fields from within a method, because when the method is executed, the class is initialized already. Even constructors run after the fields' initializers have been evaluated.

Why am I getting the error "cannot resolve method "x" in "x""?

The purpose of this program is to create a class and tester class for a select object(in my case a monitor), with at least one overloaded method. And in the client class, I have to instantiate at least three instances of the object. So far I believe I've finished the first class with the declaration of methods, getters and setters, and constructors. The problem occurs in my tester class, where I get the error "Cannot resolve method 'MonitorV82' in 'Monitor V82'. I don't know for sure why I'm getting this error, any advice?
My first class is:
public class MonitorV82
{
private double l;
private double h;
//one parameter constructor, all private instance variables initialized
public MonitorV82(double monitor1Height) {
//2.When this gets name1(jupiter), it designates "jupiter" to the variable "n"
h = monitor1Height;
l = (monitor1Height * 1.77);
}
//two parameter constructor
public MonitorV82(double monitor1Height, double monitor1Length){
//3.When this gets name1(jupiter), and a double, it sets jupiter to "n" and the diameter to "d"
h = monitor1Height;
l = monitor1Length;
}
public double getMon1height() { return h; }
public double getMon1Length() {
return l;
}
public void setMon1height(double name) { h = name; }
public void setMon1Length(double diam) {
l = diam;
}
public String monType(int resolution)
{
String monitType = "";
if (resolution == 1080) {
monitType = "lenovo";
} else if (resolution == 4000) {
monitType = "samsung";
}
return monitType;
}
//overloaded method
public String monType(int pixLength,int pixHeight)
{
String monitType = "";
if (pixHeight == 1080) {
monitType = "lenovo";
} else if (pixHeight == 4000) {
monitType = "samsung";
}
return monitType;
}
}
My tester class(where the error is) is:
public class V8Tester {
public static void main(String[] args) {
double length1 = 32.2;
double height1 = 51.8;
double length2 = 31.8;
double height2 = 50.6;
int resolution = 0;
MonitorV82 monit1 = new MonitorV82(length1);
resolution = monit1.MonitorV82(height1);
}
}
I am still learning Java in school so please don't roast me if something seems obvious or simple. Thank you for your help.
You are getting this error because there is no method MonitorV82, only a constructor. Also you are trying to instantiate the int variable resolution with a MonitorV82 object, which is not possible, because the compiler expects an int value.
If you want the resolution that refers to the pixel count of the MonitorV82 object with known pixel height, you first need to find out it's pixel length. You can do this by using your getMon1length() method and the calculate the resolution by length * height. Ultimately what I think you are trying to do is:
int heightMonit1 = monit1.getMon1height();
int resolution = (int)length1 * (int)heightMonit1;
You need to type cast, because you want to instantiate the int variable resolution with a calculation of double values.
You could however also use your second constructor and do:
MonitorV82 monit1 = new MonitorV82(length1, height1);
int resolution = (int)monit1.getMon1height() * (int)monit1.getMon1length();
Before answering the question in the title, you need the answer to this question:
What is a constructor in Java?
A constructor in Java is a special method used to "construct" (build, instantiate, etc.) objects. A constructor follows these basic rules:
The name of the constructor should match exactly the class name. In your case, MonitorV82 is this name.
A constructor doesn't have a return type. The new operator is responsible for returning a new object matching the type of the class in which the constructor is being invoked.
Knowing this, let's address the original question: Why the error? Because in MonitorV82 there is only a constructor a with matching name, but not a regular method with the same name. Consider my example below
public class Test {
private String name = "default";
// constructor #1
public Test() {}
// constructor #2
public Test(String name) {
this.name = name;
}
// method #1
public void Test() {
System.out.println(name);
}
// method #2
public void Test(String name) {
System.out.println(name);
}
}
Notice that in the code above, I have two constructors and two methods with the same name (matching case) and same parameters. This is allowed in Java although this is STRONGLY discouraged due to how confusing it can get.
What does this mean for you?
To create monit1, you need to invoke a CONSTRUCTOR. Once you construct the object, you cannot use it to invoke a constructor. You use objects to invoke non-static, accessible methods. Based on this, the line
MonitorV82 monit1 = new MonitorV82(length1);
is totally fine. However, the set resolution line is not resolution = monit1.MonitorV82(height1); because you have no METHOD named MonitorV82 (you just have a constructor with a matching name). You fix this by creating a method in your class that does exactly that. Since method names should be descriptive of their function, creating a method named setResolution or calculateResolution should be fine. What you should not do is used an ambiguous name; especially using the same name as the constructor.
Lastly, I will leave you with this small piece of advice: Just because the language allows you to do something, that does not mean that it is correct or OK to do so. My code example (along with this lengthy explanation) should've illustrated this point.
tl;dr
You asked:
Why am I getting the error "cannot resolve method "x" in "x""?
Because your last line tries to call a method named MethodV82 which does not exist on an instance of the class named MethodV82.
Details
Firstly, you should have indicated which line of code is causing that error.
You have at least one offending line, that last line. The code monit1.MonitorV82(height1) makes no sense. That code is trying to call a method named MonitorV82 on the instance named monit1. But of course there is no such method. Thus the error « Cannot resolve method ».
I cannot follow your logic, so I cannot give a fixed replacement code snippet.
I think you are misunderstanding the use of constructors.
I guess that what you want to do with your monit1.MonitorV82(height1) is to set the height of your monit1 instance to height1.
You need to call the setter to do so, not a constructor. The constructor is not known as a class method, that is why your error occurs. Use
monit1.setMon1height(height1);
Next, I think that you are trying to retrieve a resolution from your monitor, but you have no method inside of your MonitorV82 with this aim so I suggest that you create a method for this such as
public int computeResolution() {
return this.h * this.l;
}
In your test class you end up with:
public class V8Tester {
public static void main(String[] args) {
double length1 = 32.2;
double height1 = 51.8;
double length2 = 31.8;
double height2 = 50.6;
int resolution = 0;
MonitorV82 monit1 = new MonitorV82(length1);
monit1.setMon1height(height1);
resolution = monit1.computeResolution();
}
}
Edit: Even the instantiation of your monit1 does not seem correct. The only one parameter constructor you have is based on height and you are calling it with length1
Edit2: My example of computeResolution() will probably end up with an exception as I am returning an int from a compute action on doubles. But I think that it is not the main issue here

How do I make a constructor that assigns multiple parameters?

I am really new to java and just trying to get my head around how everything works. I have a method like this:
public assignmentmarks(String name, int mark1, int mark2, int mark3)
{
}
and the question asks to create the constructor that uses all the fields (courseName, assignment1, assignment2, assignment3)
This is what I have tried
import java.util.Scanner;
public class assignmentmarks {
private String courseName;
private int assignment1;
private int assignment2;
private int assignment3;
int average;
int mark;
Scanner scanner = new Scanner(System.in);
public void AssignmentMarks(String name, int mark1, int mark2, int mark3)
{
assignment1 = mark1;
assignment2 = mark2;
assignment3 = mark3;
courseName = name;
AssignmentMarks assignmentMarks = new AssignmentMarks(mark1, mark2, mark3, name);
}
I have a method like this:
public assignmentmarks(String name, int mark1, int mark2, int mark3)
{
}
That is not a method. It is a constructor!!
A constructor is a "method-like thing" that has no return type, and the same name as the enclosing class.
All you need to do is add some statements that will assign the parameters to the fields of your class.
Having said that, assignmentmarks is a bad choice for a class name. The Java style rules say that a class name should:
Start with a capital letter
Use camel case; i.e. each embedded word should start with a capital letter.
Thus ... AssignmentMarks would be a better name.
(Yes ... this kind of stuff really does matter. Conforming to standard style makes your code readable, which makes it more maintainable, which will save you and your future colleagues time and hair-tearing.)
Also note the names (identifiers) in Java are case sensitive. So you need to be consistent. Don't use assignmentmarks in one place and AssignmentMarks in another. That is likely to lead to compilation errors ... or worse.
There are few ways to go around that.
Firstly the thing you aimed to create is called an "All-arguments-constructor" meaning you want to have a declared way to create an instance(entity) of a class and while doing so you want to have all properties(fields\parameters) of it filled with values specified on the call of the said constructor.
There is a hack way to do so using lombok and just annotating your class with #AllArgsConstructor, but I recommend you continue learning how those things are made by hand and then revisit mentioned syntaxis sugar later.
With that being said you want to create something like a method that neither has return type nor "void" written in its signature, then refers to every property(field\parameter) of an instance trough this (which literally means "I want to work with this particular entity") and then assigns them values that you passed through constructor.
In your case, it would look like that:
// We have passed all the values that we need trough constructor.
public AssignmentMarks(String name, int ass1, int ass2, int ass3, int mark, int average) {
// Now we assign them to the properties of an instance we creating.
// "courseName" of the created instance becomes "name" we passed.
this.courseName = name;
// "assignment1" of the created instance becomes "ass1" we passed
this.assignment1 = ass1;
// I bet you are getting the hang of it now.
this.assignment2 = ass2;
// And so on.
this.assignment3 = ass3;
// And so forth.
this.mark = mark;
// Until you have assigned values to all properties you want to assign in the constructor.
this.average = average;
}
Now that you have this constructor you could just simply create a new instance like so:
AssignmentMarks instance = new AssignmentMarks("programming", 1, 2, 3, 17, 20);
Where we also declared all the values we want to be assigned.
This how you could have done it with lombok:
//This is an entire class
#AllArgsConstructor
public class AssignmentMarks {
private String courseName;
private int assignment1;
private int assignment2;
private int assignment3;
int average;
int mark;
}
Now it already has "All argument constructor" because of #AllArgsConstructor annotation.
P.S. I double the previous writer on naming your class in CamelCase it is important.

How do you know what type of constructor to use?

I know this is probably a very stupid question but I've looked at a lot of different sources and I can't seem to understand the difference between the no-arg constructor and the constructors with arguments. I'm under the impression that the no-arg constructor accepts as many arguments as you want, and the constructors with, say, 2 arguments, only accepts 2.
import java.io.*; //the File class
import java.util.*; //the Scanner class
public class Distance implements Comparable<Distance>
{
private int myFeet, myInches;
public Distance()
{
myFeet = myInches = 0;
}
public Distance(int f, int i)
{
myFeet = f;
myInches = i;
}
public Distance(Distance arg)
{
myFeet = arg.getFeet();
myInches = arg.getInches();
}
}
I just don't understand why it's necessary to have both Distance(int f, int i) and Distance(Distance arg) and how you know which constructors to use. Also, what is Distance arg? Is "arg" just a placeholder variable or is it an actual Java keyword? It'd be great if I could get an explanation about constructors!
A no-arg constructor takes 0 arguments (no arguments). It just runs the code inside the constructor, and you'll often see it used to initialize values to some pre-determined defaults (like yours that just sets feet and inches both to 0). In contrast, a constructor that takes in arguments can have its values set to different values at run-time.
This constructor
public Distance(Distance arg)
is called a copy constructor. It takes in an argument of the same class and just copies its attributes into the current object under construction.
Which constructor you use is entirely based on what you need. Some classes won't have all types of constructors defined, so you're limited. Others will have several constructors defined, so you can use whichever one the situation calls for.
Short answers:
I'm under the impression that the no-arg constructor accepts as many arguments as you want, and the constructors with, say, 2 arguments, only accepts 2.
A no-arg or parameterless constructor accepts no arguments. This is for the purpose of creating a default instance of a given class. In fact, if you did not provide any constructor, Java compiler provides a default no-arg constructor for your class. If you declare a constructor with n arguments (e.g. public Person(String name, int age), then constructing an instance of that class by calling that constructor requires you to provide the correct number, type and order of those arguments (e.g. Person p = new Person("Larry", 32)).
Perhaps you are confusing this type of constructor with a vararg or variable arity method that accepts one or more arguments of a given type (there are some gory details that you should read up). Since a constructor of a class is similar to any other instance method (there are differences), you could have variable arity constructors, but they are rarely used:
class Chameleon {
private final String color;
private final String location;
private final int lifeSpanYears;
/**
* Constructs a default Chameleon that has GREEN color, is from Africa and
* has 5 years of life span.
*/
public Chameleon() {
this.color = "GREEN";
this.location = "Africa";
this.lifeSpanYears = 5;
}
/**
* Constructs a specific instance of Chameleon with given color, location
* and life span.
*/
public Chameleon(String color, String location, int lifeSpanYears) {
//validate arguments
this.color = color;
this.location = location;
this.lifeSpanYears = lifeSpanYears;
}
/* Constructs a Chameleon from given one or more string params.
If given, first argument is the color and if given, the second
argument is the location. Life span of the instance will be 5 years.
<b> Note: this is for illustration purposes only. </b>
*/
public Chameleon(String... props) {
if (props.length == 0) {
this.color = "GREEN";
this.location = "Africa";
} else if (props.length == 1) {
this.color = props[0];
this.location = "Africa";
} else {
this.color = props[0];
this.location = props[1];
}
this.lifeSpanYears = 5;
}
public Chameleon(Chameleon mold) {
this.color = mold.color;
this.location = mold.location;
this.lifeSpanYears = mold.lifeSpanYears;
}
public static void main(String[] args) {
Chameleon c = new Chameleon(); // no-arg constructor is called
System.out.println(c.color); // => GREEN
System.out.println(c.location); // => Africa
System.out.println(c.lifeSpanYears); // 5
Chameleon c2 = new Chameleon("BLACK", "Asia", 4); // specific constructor is called, right number, type and order of arguments is provided
System.out.println(c2.color); // => BLACK
System.out.println(c2.location); // => Asia
System.out.println(c2.lifeSpanYears); // 4
Chameleon c3 = new Chameleon("BROWN", "California"); // this time it should be the vararg constructor!
System.out.println(c3.color); // => BROWN
System.out.println(c3.location); // => California
System.out.println(c3.lifeSpanYears); // 5 again
Chameleon c4 = new Chameleon("BROWN"); // this time it should be the vararg constructor again!
System.out.println(c4.color); // => BROWN
System.out.println(c4.location); // => Africa
System.out.println(c4.lifeSpanYears); // 5 again
Chameleon c5 = new Chameleon(c2); // this time the _copy_ constructor is called. c5 is a copy of c2.
// although c5 is a copy of c2, it is a distinct entity; think of c5 as
// an identical twin of c2.
System.out.println(c5.color); // => BLACK
System.out.println(c5.location); // => Asia
System.out.println(c5.lifeSpanYears); // 4
}
}
I just don't understand why it's necessary to have both Distance(int f, int i) and Distance(Distance arg)
Well, it is not necessary per se. It's a convenience. The underlying mechanism that enables this is called method overloading which means you could declare two constructors (or methods) with the same name (class name in this case) in a class. Every constructor can construct an instance of a class in a way it chooses to. Ideally, all the constructors should construct properly initialized instances. If you followed some basic object oriented programming good practices, you should not go wrong here.
In this particular case, you are providing two constructors: the first that takes both feet and inches and the other that takes another instance of the same class. The second constructor embodies what is knows as a copy constructor which should create a copy of the passed argument. Thus, if you have an already available instance d of the Distance class, you can create a copy of that using:
// get d from somewhere
Distance dCopy = new Distance(d);
See the copy constructor (and its use) provided in my example code above.
and how you know which constructors to use
Here you will need to read the documentation or source of the class that you intend to use. Well-written classes like the JDK provide good documentation for you to look at.
Also, what is Distance arg?
It is an instance of the class Distance that is used as a constructor argument. Again, see the main method of the Chameleon example.
Is "arg" just a placeholder variable or is it an actual Java keyword?
Yes, the former. It's more commonly known as an argument or a formal parameter.
Constructors are used to instantiate a Class.
There can be default constructors which does not initialize any of the properties in the class.
In your code the default constructor is :
public Distance()
{
myFeet = myInches = 0;
}
A class can be instantiated in many ways, and for that constructors are needed. There can arguments in constructors. These arguments automatically set the properties of the class inside the constructors. So we don't need to set the properties individually.
For eg in your code:
public Distance(int f, int i)
{
myFeet = f;
myInches = i;
}
public Distance(Distance arg)
{
myFeet = arg.getFeet();
myInches = arg.getInches();
}
In the first constructor the properties are set individually in the constructor.
In the second case it is set from another Distance Object.
Args is not a keyword, it is the name of the object of type Distance.
If no external constructor is written then it will take its default constructor ( Which is handled by java internally ).
If for a class A , a constructor public A() is present then it will consider this one as a constructor.
Now if you have a constructor like,
public A()
{
<something>
}
Then while creation of object you have to write just,
A objectA = new A();
If you have a constructor like,
public A(int x)
{
<something>
}
then while declaring you have to write,
A objectA = new A(<any integer>);
Here you can't write,
A objectA = new A();
So when you are declaring constructor then only those will be considered.
Now in your code,
public Distance()
{
myFeet = myInches = 0;
}
public Distance(int f, int i)
{
myFeet = f;
myInches = i;
}
public Distance(Distance arg)
{
myFeet = arg.getFeet();
myInches = arg.getInches();
}
You can create the object of Distance class in three manners,
Distance distance = new Distance();
Distance distance = new Distance(1,2);
Distance distance2 = new Distance();
Distance distance = new Distance(distance2);
So in all the cases the object is created and the values are initialized. But it is written in multiple way to approve multiple type or mannered coding and to give the code more options to create the object.
Lastly arg is just a variable name.

Counter that will remember its value

I have a task to operate on complex number. Each number consists of double r = real part, double i = imaginary part and String name. Name must be set within constructor, so I've created int counter, then I'm sending its value to setNextName function and get name letter back. Unfortunately incrementing this 'counter' value works only within costructor and then it is once again set to 0. How to deal with that?Some constant value? And second problem is that I also need to provide setNextNames(char c) function that will change the counter current value.
The code :
public class Imaginary {
private double re;
private double im;
private String real;
private String imaginary;
private String name;
private int counter=0;
public Imaginary(double r, double u){
re = r;
im = u;
name = this.setNextName(counter);
counter++;
}
public static String setNextName(int c){
String nameTab[] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N",
"O","P","Q","R","S","T","U","W","V","X","Y","Z"};
String setName = nameTab[c];
System.out.println("c: "+c);
return setName;
}
public static String setNextName(char c){
//
//don't know how to deal with this part
//
}
It's hard to tell what you're doing, but I suspect this will solve your immediate problem:
private static int counter = 0;
You should make counter static.
You should also make nameTab a private static field, then in setNextName(), you can iterate through it to find the name corresponding to the given character, and get its index. (in the plain ASCII world, of course one could simply calculate the index by subtracting the numeric value of 'A' from the given character, but I am not quite sure how it would work out with Java, in Unicode, with crazy inputs - iteration is on the safe side.)
In OO languages there are typically two types of variables that go into a class:
instance variables that are unique to each instance
class variables that are shared by all instances of the class
Given a class like:
public class Person
{
// class variable
private static int numberOfEyes;
// instance variable
private String name;
// other code goes here
}
If you were to do something like:
Person a = new Person("Jane Doe");
Person b = new Person("John Doe");
and then do something like:
a.setName("Jane Foe");
the name for Person "a" would change, but the one for Person "b" would stay the same.
If you woke up one morning and decided you wanted 3 eyes:
Person.setNumberOfEyes(3);
then Person "a" and Person "b" and every other Person instance out there would suddenly have 3 eyes as well.
You want to put "static" in your counter declaration.
is your code being used by multiple threads than i would suggest that making counter static won't solve ur problem.
you need to take extra care by implementing thread synchronization use lock keyword as shown below.
private static readonly obj = new Object();
private static int counter =0;
public Imaginary(double r, double u)
{
re = r;
im = u;
lock(obj)
{
name = this.setNextName(counter);
counter++;
}
}
this will ensure thread safety also while incrementing your counter (there are another ways also to provide thread security but this one is having least code).
Because the field counter is not static, every object has its own counter.

Categories