How can I fix errors in my Java Complex Number Class Homework?

In summary: String converty1() { return ...}In summary, in this conversation, we discussed the creation of a class for complex numbers. The class contains instance variables for the complex number, a constructor to initialize these variables, methods to return the real and imaginary parts of the complex number, a method to compute the magnitude of the complex number, a method to convert the complex number to a string, and two static methods to perform operations on complex numbers. We also provided suggestions for improving the code, such as using this keyword appropriately, declaring accessibility of variables and methods, and returning values instead of passing in unnecessary variables.
  • #1
CAF123
Gold Member
2,948
88

Homework Statement


Create a class which contains the following:
a)instance variables for the complex number. For x+yi, x and y are the variables.
b)constructor to initialize these variables.
c)methods to return the real and imaginary parts of the complex number
d)method to compute the magnitude of the complex number
e)method to convert complex number to a string (so it can be printed in form {x,y})
f)static method to take 2 complex numbers and return the sum as another complex number
g)static method to take 2 complex numbers, a and b, and return a*b as a third complex number.

The Attempt at a Solution


I have attempted steps a) - d) so far. My method for d) returns errors in the terminal so it is not correct. I don't really understand what e) means.
Code:
class Complex {

	double x;
	double y; //instance variables for the complex number

	Complex() {
	        this.x = "";
		this.y = "";
}

	Complex(double x, double y) {
		this.x = x;
		this.y = y; //constructor to initialise these variables

}

	double getX() {
		return this.x; //getter method for x, the real component of the complex number
}
	double getY() {
		return this.y; //getter method for y, the imaginary part of the complex number.
}

	double mag;

	void magnitude(double mag) {
	    this.mag = this.Math.sqrt(Math.pow(double x,2) + Math.pow(double y,2)); //method to compute magnitude of number	
    }

}
 
Physics news on Phys.org
  • #2
Both of your constructors are incorrect. For the first one, you cannot assign string values to a double. For the second one, java is getting confused because of your parameters. Switch it to :

Code:
	public Complex(double _x, double _y) {
		x = _x;
		y = _y; //constructor to initialize these variables
	}

Also, you don't need to call double mag; outside of the magnitude function. Delete it.

You should make the return type of your magnitude function a double. So you can make this happen :

Code:
	public double magnitude() {
		return Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
	}

Should work after that.

e) Is also pretty straightforward. Think about returning a string this time.
 
  • #3
Personally, I wouldn't use "Math.pow" to find a square: just use x*x. Also, I see not reason for the "double" in front of x and y if you have already declared them to be double. But the main thing I do not understand is your use of "double mag" as a parameter for the magnitude function. Rather, return it as a value:

Double magnitude() {
return Math.sqrt(this.x*this.x+ this.y*this.y);
}

Personally, I wouldn't use "this" as you have. You are working in "complex" so those should be understood. Of course, that means that you should not use "x" and "y" as parameters in a constructor: I would have said
Complex(){
//default constructor
x= 0.0;
y= 0.0;
}
and
Complex(Double u, Double v){
x= u; y= v; }

If your compiler really allows you to say ' this.x= "" ' when you have declared x and y as "Double", okay but that seems very strange to me!
 
  • #4
I see that other have also answered but I will leave this as I wrote it even though it duplicates the other posts in places.

Your example has several errors and does not compile. One of the main problems is that you do not seem to understand what "this" is used for. It is a reference to the instance of the class object and is usually only necessary when you need to distinguish between a class level variable and a method level variable that have the same name - like the case for the Complex(double x, double y) constructor. Otherwise, using this.x or this.y throughout the code is overkill. Similarly, this.Math and [STRIKE]this.mag[/STRIKE] doesn't work. They are not class level variables.

Do not pass in the variable type when calling a method. I.E. Math.pow(double x,2) should just be Math.pow(x, 2). If x started as a float and you were trying to cast it to a double, you would write Math.pow( (double)x, 2). But, it's not necessary to cast it in this case because it's already a double.

As for your method to calculate the magnitude, you are passing in a magnitude [STRIKE]and then immeadiately overwriting the value with a calculation using the class level variables of x and y[/STRIKE] that isn't used. What would be the purpose of passing in a variable into a method that isn't used for anything?

If a method is desired to calculate a result, it's usually desirable to return the result. The method should return the values that you're calculating. It would also be less confusing to name the method something like getMagnitude.


EDIT: Didn't see the declaration for mag right above the method.
 
Last edited:
  • #5
Another note. You should get in the habit of declaring the accessibility of your variables and methods as public, private, protected, etc. By not declaring them, you allow access to them from other classes and can accidently modify data from outside of the class. This can make for some really painful debugging when you have another class accidentally modifying a variable because you didn't make it private. Similarly, there are times when you only want to call a method from within your class because it may be performing intermediate calculations for you.
 
  • #6
Many thanks for your responses. I have followed your advice and put in changes to the code in the OP:
Code:
public class Complex {

	double x;
	double y; //instance variables for the complex number

	public Complex() {
	        x = 0;
		y = 0; //default number
}

	public Complex(double x_, double y_) {
		x = x_;
		y = y_; //constructor to initialise these variables

}

	public double getX() {
		return x; //getter method for x, the real component of the complex number
}
	public double getY() {
		return y; //getter method for y, the imaginary part of the complex number.
}

	

	public double getMagnitude() {
	    return Math.sqrt(Math.pow(x,2) + Math.pow(y,2)); //method to compute magnitude of number	
    }

	public String convertx() {
		return String.valueOf(x);
}
	public String converty() {
		return String.valueOf(y);
}
	public static double sum(Complex c1, Complex c2) {
		double x1 = c1.getX() + c2.getX();
		double x2 = c1.getY() + c2.getY();
}
	public String convertx1() {
		return  String.valueOf(x1);
}
	public String convertx2() {
		return  String.valueOf(x2);
}

}
When I compile, x1 (and x2) is not being recognized when I convert it to a string. I have defined what x1 is in the previous method, so why is this?
 
  • #7
You are defining x1 and x2 in the sum method. They are only accessible within that method.
 
  • #8
Borg said:
You are defining x1 and x2 in the sum method. They are only accessible within that method.

This had crossed my mind, but the method was made public, so shouldn't I be able to access it throughout the class?

How should I convert the double to string then? I think I need to make two separate methods to return x1 and x2. I tried something like this before:
Code:
public static String sum(Complex c1, Complex c2) {
double x1 = ..;
double x2 = ..;

return String.valueOf(x1);
return String.valueOf(x2);
When I compiled, however, the second return statement was 'unreachable'.
 
  • #9
CAF123 said:
This had crossed my mind, but the method was made public, so shouldn't I be able to access it throughout the class?
Making the method public makes the method available to other classes. Variables that are defined within the method only exist within the method and are not available to other methods within the class.
CAF123 said:
How should I convert the double to string then? I think I need to make two separate methods to return x1 and x2. I tried something like this before:
Code:
public static String sum(Complex c1, Complex c2) {
double x1 = ..;
double x2 = ..;

return String.valueOf(x1);
return String.valueOf(x2);
When I compiled, however, the second return statement was 'unreachable'.
The return instructs the code to leave the method and return to the code that called it. You can have multiple returns within a method but only if they are within things like if statements where there is a possibility of reaching one or the other return.

For your sum method, why do you think that it needs two Complex class values passed in? For what you want, delete c1 and c2, create a new variable within the method to get the sum and then return the String value of that.
 
  • #10
What point are you at in your Java class? You are clearly having difficulty with what is available and where it's available. I could put together some examples that might help but I don't want to cover more than you've been taught yet. Have you covered class inheritance? How about public, private, protected and/or abstract?
 
  • #11
Borg said:
For your sum method, why do you think that it needs two Complex class values passed in?
I thought I needed two instances of the class so that I could then find their sum.

For what you want, delete c1 and c2, create a new variable within the method to get the sum and then return the String value of that.

I am having difficulty here because the sum is not a double, it is another complex number. If I delete the c1 and c2, I believe I should also delete 'static' from the method too?
 
  • #12
Borg said:
What point are you at in your Java class? You are clearly having difficulty with what is available and where it's available. I could put together some examples that might help but I don't want to cover more than you've been taught yet. Have you covered class inheritance? How about public, private, protected and/or abstract?

I have heard of class inheritance, public, private. I am happy with the procedural programming but the object oriented side I am having some difficulty with.

My notes are somewhat vague and what I don't get is that there have been things said in this thread which contradict what it says in my notes. If you would be happy to put together some examples, that would be great. Alternatively, if you have any recommendations for good JAVA introductory textbooks that I could look into, that would also be great.

Thanks.
 
  • #13
CAF123 said:
I have heard of class inheritance, public, private. I am happy with the procedural programming but the object oriented side I am having some difficulty with.

My notes are somewhat vague and what I don't get is that there have been things said in this thread which contradict what it says in my notes. If you would be happy to put together some examples, that would be great. Alternatively, if you have any recommendations for good JAVA introductory textbooks that I could look into, that would also be great.

Thanks.
I have to leave for now but will try to put something together this afternoon. Hopefully some others can help in the meantime.
 
  • #14
CAF123 said:
Many thanks for your responses. I have followed your advice and put in changes to the code in the OP:
Code:
public class Complex {

	double x;
	double y; //instance variables for the complex number

	public Complex() {
	        x = 0;
		y = 0; //default number
}

	public Complex(double x_, double y_) {
		x = x_;
		y = y_; //constructor to initialise these variables

}

	public double getX() {
		return x; //getter method for x, the real component of the complex number
}
	public double getY() {
		return y; //getter method for y, the imaginary part of the complex number.
}

	

	public double getMagnitude() {
	    return Math.sqrt(Math.pow(x,2) + Math.pow(y,2)); //method to compute magnitude of number	
    }

	public String convertx() {
		return String.valueOf(x);
}
	public String converty() {
		return String.valueOf(y);
}
	public static double sum(Complex c1, Complex c2) {
		double x1 = c1.getX() + c2.getX();
		double x2 = c1.getY() + c2.getY();
}
	public String convertx1() {
		return  String.valueOf(x1);
}
	public String convertx2() {
		return  String.valueOf(x2);
}

}
When I compile, x1 (and x2) is not being recognized when I convert it to a string. I have defined what x1 is in the previous method, so why is this?

You're over complicating things a bit for part e). It's literally a one liner, but look closely at this and try to see what I'm doing :

Code:
	private String getXY() {
		return "{" + x + ", " + y + "}";
	}

So whenever you create a complex number, let's call it ##c## for now, you can call System.out.println(c.getXY()); which will return your desired {x,y} pairs. There's no need to convert the doubles to strings in this case because they can still be concatenated with strings and returned regardless.

So up until e) you should know how to return a double and return a string. For f) and g) though you have to be a bit more clever. I'll walk you through f) since you seem to be having a bit of trouble grasping the syntax, but you should be able to do g) on your own afterwards.

Notice f) asks you to return a Complex object, not a double. How do you do this you might ask? The exact same way you returned doubles and strings from before, that's how. Observe this code :

Code:
	private static Complex sum(Complex z1, Complex z2) {
		return new Complex(z1.getX() + z2.getX(), z1.getY() + z2.getY());
	}

This method returns a new complex object for you to use. Notice how it makes use of a constructor as well as two of the other methods that have been written. Also notice the private and static modifiers that have been added. Private insures protection from modifications by other classes and static allows you to reference your methods in a static fashion from anywhere in your code in any class.

Here's what your code should look like up until now, I also added a public main so you can observe some test cases and tinker with it to help your understanding :

Code:
import java.lang.Math;

public class Complex {
	private double x;
	private double y;

	//Public constructors
	public Complex() {
		x = 0;
		y = 0;
	}

	public Complex(double _x, double _y) {
		x = _x;
		y = _y;
	}
	
	//Getters & setters
	private double getX() { return x; }
	private double getY() { return y; }

	private double magnitude() {
		return Math.sqrt(x*x + y*y);
	}
	
	private String getXY() {
		return "{" + x + ", " + y + "}";
	}
	
	private static Complex sum(Complex z1, Complex z2) {
		return new Complex(z1.getX() + z2.getX(), z1.getY() + z2.getY());
	}
	
	public static void main(String[] args) {
		Complex z = new Complex(3,4);
		Complex w = new Complex(2,1);
		
		System.out.println(z.magnitude());
		System.out.println(w.magnitude());
		
		System.out.println(z.getXY());
		System.out.println(w.getXY());
		
		System.out.println(sum(z,w).getXY());
	}

}

Look over that for awhile and try to follow what the code is doing as it is doing it. Then try part g) and show me what you get.
 
Last edited:
  • Like
Likes 1 person
  • #15
OK, here you go. I want to get to some basics and then expand from there as you understand things better. In the following example, I've created two constructors. One takes no variables and the other takes two. Build this, run it and see if you can understand what's going on. I've put lots of comments into guide you along.

Code:
public class MyClassExample {

	// These are class-level variables and can be directly accessed 
	// anywhere within the class (except the main method).
	private int x = 2;
	private int y = 1;
	private int z;		

	public MyClassExample(){
		// Nothing is set, so the default values are used
		// Note that z will be 0 even though it wasn't set.
		// This normally only happens for a few primitive types.
	}

	public MyClassExample(int x, int y){
		this.x = x;	// The incoming variable x is being used to set the class level variable x
		this.y = y;	// The incoming variable y is being used to set the class level variable y
		z = x + y;	// For this class, if only x and y are supplied, then z is set to x + y
	}

	public String getAllClassLevelVariables(){
		// The only things that you can access here are class-level variables.
		return "X: " + x + ", Y: " + y + ", Z: " + z;
		// You can't access whosOnFirst, whatsOnSecond, example1 or example2 from this method.
	}

	public static void main(String... args) {
		// Create three instances of MyClassExample
		MyClassExample example1 = new MyClassExample();

		// Examine what you have as you go
		System.out.println("Example 1 variables are X: " + example1.x + ", Y: " + example1.y + ", Z: " + example1.z);

		// This is about as confusing as I can make it but the point is to see that
		// the variable names that are sent to a class or method don't have to be the same.
		int whosOnFirst = 5;
		int whatsOnSecond = 10;
		// Create a MyClassExample(int x, int y) instance
		// whosOnFirst becomes x (not this.x) and
		// whatsOnSecond becomes y (not this.y)
		// when you get to the constructor.
		MyClassExample example2 = new MyClassExample(whosOnFirst, whatsOnSecond);

		// This print statement does the same thing as the print statement above for the example 1 instance
		// Why bother?  Think about how painful it would be to create the print statement
		// if there were 100 variables to print out.  The method allows you to write it once
		// for any instance of the class.
		System.out.println("Example 2 variables are " + example2.getAllClassLevelVariables());
	}
}
And always remember, print statements are your friend.
 
  • Like
Likes 1 person
  • #16
The code for g) in the class would be:
Code:
private static Complex multiply(Complex z1, Complex z2) {
		return new Complex(z1.getX()*z2.getX() - z1.getY()*z2.getY(), z1.getX()*z2.getY() + z1.getY()*z2.getX());
	}
I have compiled the code and it runs fine. I have a question though:
Zondrina said:
Code:
import java.lang.Math;

public class Complex {
	private double x;
	private double y;

	//Public constructors
	public Complex() {
		x = 0;
		y = 0;
	}
Why do we need to include a default constructor?

Many thanks.
 
Last edited:
  • #17
CAF123 said:
The code for g) in the class would be:
Code:
private static complex multiply(complex z1, complex z2) {
		return new complex(z1.getX()*z2.getX() - z1.getY()*z2.getY(), z1.getX()*z2.getY() + z1.getY()*z2.getX());
	}
I have compiled the code and it runs fine. I have a question though:

Why do we need to include a default constructor?

Many thanks.
I'm not trying to duplicate your assignment. I'm showing you different constructors so that you get a feel for how things work. For your assignment, you are correct that you don't need a default constructor.

So, do you understand how the variables are being handled in the example?

BTW, what you're doing with the static solution for g is not going to work.
 
  • #18
Borg said:
I'm not trying to duplicate your assignment. I'm showing you different constructors so that you get a feel for how things work. For your assignment, you are correct that you don't need a default constructor.
Sorry, that post was directed at Zondrina. Why would you need a default constructor at all?

So, do you understand how the variables are being handled in the example?
I have some questions, but I will ask tomorrow - it is getting late here.

BTW, what you're doing with the static solution for g is not going to work.

I have edited 'complex' to 'Complex', thanks.
 
  • #19
CAF123 said:
I have edited 'complex' to 'Complex', thanks.
I saw that but, for some reason I was thinking that it was worse than that. My bad - changing it to Complex was all that was needed. :redface:
CAF123 said:
I have some questions, but I will ask tomorrow - it is getting late here.
I'm on the U.S. East Coast but I get up very early. We can start again whenever you're ready.
 
Last edited:
  • #20
CAF123 said:
The code for g) in the class would be:
Code:
private static Complex multiply(Complex z1, Complex z2) {
		return new Complex(z1.getX()*z2.getX() - z1.getY()*z2.getY(), z1.getX()*z2.getY() + z1.getY()*z2.getX());
	}
I have compiled the code and it runs fine. I have a question though:

Why do we need to include a default constructor?

Many thanks.

It's a convention to include the default constructor whether or not it will be needed. It makes it easier for other programmers to use your code which is vital in the industry. Simplifying accessibility in code when you work on teams of programmers is really important since other people on your team will be working on different classes than yours.

The problem with that is they might not know your code inside and out, but the power of the dot operator '.' makes it so it doesn't matter if you assign values to your objects or not through parameters when you create it. They will be able to create a quick instance of your object and assign values to it when necessary ( Presuming a decent IDE is being used... like eclipse ).

Good job with part g) :).
 
Last edited:
  • #21
Zondrina said:
It's a convention to include the default constructor whether or not it will be needed. It makes it easier for other programmers to use your code which is vital in the industry. Simplifying accessibility in code when you work on teams of programmers is really important since other people on your team will be working on different classes than yours.

The problem with that is they might not know your code inside and out, but the power of the dot operator '.' makes it so it doesn't matter if you assign values to your objects or not through parameters when you create it. They will be able to create a quick instance of your object and assign values to it when necessary ( Presuming a decent IDE is being used... like eclipse ).

Good job with part g) :).
I don't think that including a default constructor is necessarily a good convention. It really depends on whether the default constructor would provide any value and could be used to achieve the same results throughout the class. In the case of the homework assignment, leaving a default constructor would mean that the x and y variables would have to be initialized elsewhere after calling the default constructor. If another programmer doesn't realize that, they can get all kinds of errors. In general a class shouldn't need extra steps to be performed after calling the constructor before it's ready to be used.
 
  • #22
Hi Borg, I went through your example and my questions are written as the code progresses:
Borg said:
Code:
public class MyClassExample {

	// These are class-level variables and can be directly accessed 
	// anywhere within the class (except the main method).
	private int x = 2;
	private int y = 1;
	private int z;		

	public MyClassExample(){
		// Nothing is set, so the default values are used
		// Note that z will be 0 even though it wasn't set.
		// This normally only happens for a few primitive types.
	}

	public MyClassExample(int x, int y){
		this.x = x;	// The incoming variable x is being used to set the class level variable x
		this.y = y;	// The incoming variable y is being used to set the class level variable y
		z = x + y;	// For this class, if only x and y are supplied, then z is set to x + y
	}

Would it also make sense to say that 'The incoming variable x is being set to the class level variable x'?, where the 'incoming variable x' is the first argument of the constructor - (int x)

Code:
	public String getAllClassLevelVariables(){
		// The only things that you can access here are class-level variables.
		return "X: " + x + ", Y: " + y + ", Z: " + z;
		// You can't access whosOnFirst, whatsOnSecond, example1 or example2 from this method.
	}

	public static void main(String... args) {
		// Create three instances of MyClassExample
		MyClassExample example1 = new MyClassExample();

		// Examine what you have as you go
		System.out.println("Example 1 variables are X: " + example1.x + ", Y: " + example1.y + ", Z: " + example1.z);
When I run this, I see that z is still 0. But did you not set z = x+y, so I expected to see 3 here. Or is it the case that since x and y were not specified in the argument, then the default (or first) constructor is used? This would make sense.

Code:
		// This is about as confusing as I can make it but the point is to see that
		// the variable names that are sent to a class or method don't have to be the same.
		int whosOnFirst = 5;
		int whatsOnSecond = 10;
		// Create a MyClassExample(int x, int y) instance
		// whosOnFirst becomes x (not this.x) and
		// whatsOnSecond becomes y (not this.y)
		// when you get to the constructor.
		MyClassExample example2 = new MyClassExample(whosOnFirst, whatsOnSecond);//this is the instance
whosOnFirst is not this.x because you have used the variable name whosOnFirst and not x?
Code:
		// This print statement does the same thing as the print statement above for the example 1 instance
		// Why bother?  Think about how painful it would be to create the print statement
		// if there were 100 variables to print out.  The method allows you to write it once
		// for any instance of the class.
		System.out.println("Example 2 variables are " + example2.getAllClassLevelVariables());
	}
}

In example 1, there is no explicit values assigned to the argument of the constructor so in the print statement example1.x is required? Where as in example 2, the arguments are specified so we can access the method directly i.e example2.getAllClassLevelVariables?

Thanks.
 
  • #23
CAF123 said:
Would it also make sense to say that 'The incoming variable x is being set to the class level variable x'?, where the 'incoming variable x' is the first argument of the constructor - (int x)
No. The incoming variable x is never on the left side of an equation in that constructor so its value doesn't get 'set' to anything. Its value isn't changing. The class level x (i.e. this.x) does get changed though because of this line:
this.x = x;
You really have to see these as two different variables even though they appear to have the same name (x).

CAF123 said:
When I run this, I see that z is still 0. But did you not set z = x+y, so I expected to see 3 here. Or is it the case that since x and y were not specified in the argument, then the default (or first) constructor is used? This would make sense.
Yes, the default constructor is used. Whenever you call a constructor or method, the number, type, and order of variables that you pass have to match something on the receiving end. Since we didn't pass any values to create example1, the default construtor is used. And, since the default constructor doesn't assign any values to x, y, or z, the values that they were given at the top of the class (2 , 1, 0) remain the same.

To clarify what I mean by order, let's say that you have two constructors that look like this:
public MyClassExample(String , int) and public MyClassExample(int, String)

These are two completely different constructors because of the order of the variables being passed in. Only one or the other gets used depending whether you create a class instance by passing a String in the first position and int in the second position or the other way around.

CAF123 said:
whosOnFirst is not this.x because you have used the variable name whosOnFirst and not x?
This one gets to the core of what you're not seeing. In this example whosOnFirst gets passed (along with whatsOnSecond) to the constructor that takes two ints. It does not matter what the variable names are in the main method. It just matters whether there is a constructor that takes two ints. The constructor will then take the first int and rename it to x and the second one gets renamed to y (for use within the constructor or method). After that, x and y are used to set this.x, this.y and z.

CAF123 said:
In example 1, there is no explicit values assigned to the argument of the constructor so in the print statement example1.x is required? Where as in example 2, the arguments are specified so we can access the method directly i.e example2.getAllClassLevelVariables?
No, the method has nothing to do with how you constructed the class. You can use either way to print out the variables for either example. Try it. :smile:
 
Last edited:
  • #24
Things are starting to make a lot more sense now - my notes more or less consisted of single line bullet statements and so did not go into a lot of detail. Many thanks. I feel like an introductory JAVA book may be beneficial to me - do you have any recommendations?
 
  • #25
CAF123 said:
Things are starting to make a lot more sense now - my notes more or less consisted of single line bullet statements and so did not go into a lot of detail. Many thanks. I feel like an introductory JAVA book may be beneficial to me - do you have any recommendations?
Sorry, I don't have any books that I could recommend - it's been a long time since I read one. Most of what I do read is online though. I would recommend the Java Tutorials. Plus, whenever you have an error that you can't figure out, Googling the error will get you an answer most of the time.

I would like to throw another example your way to emphasize the points on constructor and method signatures. Add this constructor:
Code:
public MyClassExample(int superman, int z, int flyingPinkUnicorn) {
		// I'm purposely using odd names.  Why?  To show that variable names mean nothing and everything
		// It technically doesn't matter what you name your variables but poor names are confusing.
		x = superman;	// The incoming variable superman is being used to set the class level variable x
		y = flyingPinkUnicorn;	// The incoming variable flyingPinkUnicorn is being used to set the class level variable y
		// The incoming variable z is being used to set the class level variable this.z
		// Carefully note though where the incoming z is in the list of parameters.
		// Don't get fooled into thinking that x,y,z = 1,2,3!
		this.z = z;
	}
Add this method for printing:
Code:
public String getAllClassLevelVariables(String whatever) {
		// The only things that you can access here are class-level variables and 'whatever'.
		// But, since we're not using the variable 'whatever', this method does EXACTLY the
		// same thing as the other method above
		return "X: " + x + ", Y: " + y + ", Z: " + z;
		// You STILL can't access superman, flyingPinkUnicorn, whosOnFirst,
		// whatsOnSecond, example1, example2, or example3 from this method.
	}
And, add this to the end of your main method:
Code:
		// Create a MyClassExample(int superman, int z, int flyingPinkUnicorn) instance
		MyClassExample example3 = new MyClassExample(100, 200, 300);
		// Why is y == 300 and z == 200?
		System.out.println("Example 3 variables are " + example3.getAllClassLevelVariables("Some completely unrelated string..."));

In all of this, the main point is not to get caught up in variable names but rather to focus on method signatures. Pay particular attention to where I put z in the new constructor and how it affects the output. I purposely put it in an unusual position in the constructor's signature.
 
  • #26
Code:
why is y==300 and z==200?

The ordering of parameters in the constructor you built was int superman, int z, int flyingPinkUnicorn. The method then labeled these as x = superman; (not this.x because x is not used as a parameter in the constructor), y = flyingPinkUnicorn; (not this.y for same reason above) and this.z = z (necessarily this.z since z was used as a class level variable).

So in the main program, the example is (100, 200, 300) so x = 100, y = 300 and z = 200.

I have a question though: How does the program know to refer to the method with three parameters and not the one with two parameters? Is it simply because (100, 200, 300) has three parameters and so the only method that deals with three paramaters is (int superman, int z, int flyingPinkUnicorn) and so it must refer to this method? Does my question make sense?
 
  • #27
CAF123 said:
The ordering of parameters in the constructor you built was int superman, int z, int flyingPinkUnicorn. The method then labeled these as x = superman; (not this.x because x is not used as a parameter in the constructor), y = flyingPinkUnicorn; (not this.y for same reason above) and this.z = z (necessarily this.z since z was used as a class level variable).

So in the main program, the example is (100, 200, 300) so x = 100, y = 300 and z = 200.
Still stuck on this a bit. There is only one x or y that the compiler can see in that constructor. Since there are no variables named x or y in the constructor's signature, the compiler knows that you are referring to the class level versions of x and y (x and this.x both refer to the class level variable in this case). You have to use this.z to set the class level variable z because the signature also has a variable named z. If you just use type z, the compiler thinks that you are referring to the one in the signature. So, if you mistakenly type z = z, all you are doing is setting the incoming value to itself.

See the next post to help clarify this.

CAF123 said:
I have a question though: How does the program know to refer to the method with three parameters and not the one with two parameters? Is it simply because (100, 200, 300) has three parameters and so the only method that deals with three paramaters is (int superman, int z, int flyingPinkUnicorn) and so it must refer to this method? Does my question make sense?
You're definitely getting there with your understanding. Yes, it is simply because of the number of parameters (along with type and order). For example, if you also had this constructor:
public MyClassExample(String superman, int z, int flyingPinkUnicorn)

the compiler would know not to use it because it wants a String in the first position. Remember, even thought the names are the same as the other constructor, the names in the constructor signatures have no relationship to each other.
 
Last edited:
  • #28
All of the discussion about what variables can be seen and where is called Scope. I don't know whether your class has actually covered it as a topic but this is what we've been going over. I've been giving you examples of what the compiler knows about at specific places. I'm going to go over this a little deeper because it's your last stumbling block.

Within a class, method or constructor, there are certain rules that the compiler follows. Here is a simple list of what it knows:
  • Any constructor or method can see class level variables and any variable that has been defined up to that point in the constructor or method. It cannot go up and then look back down inside of other brackets. Constructors and methods have brackets around them.
  • Any constructor or method is allowed to reuse a variable name that has been defined at the class level so that it becomes a local level variable (i.e. only visible within that constructor or method). After that, you have to use 'this' in order to refer to the class level variable.
The constructors examples have all been reusing class level variable names to one degree or other but we've been defining them in the signature. You can also reuse the names within the constructor or method. But, that brings its own set of confusion. I'll add two lines to the last constructor to show this.
Code:
public MyClassExample(int superman, int z, int flyingPinkUnicorn) {
		// I'm purposely using odd names.  Why?  To show that variable names mean nothing and everything
		// It technically doesn't matter what you name your variables but poor names are confusing.
		x = superman;	// The incoming variable superman is being used to set the class level variable x
		String x = "Why didn't I need 'this' above?";
		{	String y = "Why don't I need 'this' below?";}
		y = flyingPinkUnicorn;	// The incoming variable flyingPinkUnicorn is being used to set the class level variable y
		this.z = z;	// The incoming variable z is being used to set the class level variable this.z
	}

In the modified constructor, I've declared x to be a String. How can that be? At the line x = superman, the compiler only knows about variables up to that line. On the following line where x is declared to be a String, I am using my one shot at reusing the class level variable name. From that point on, you have to use this.x if you want to work with the class level x. If you move x = superman below the String x... line, it won't compile because it thinks that x is a String at that point. You would have to write this.x = superman.

And, while I made the new x a String, I could have just as easily made it an int. Either way, once you reuse the class level name, the compiler will force you to use 'this' if you want to work with the class level variable. The tricky part is that if you reused x in the method and also made it an int. You wouldn't be forced to write this.x = superman to get it to compile because x is also an int. x = superman would modify the local variable and this.x would modify the class level verion.

This is no different than how int z in the method's signature reused the z name at the class level. Since it got defined in the signature, you have to write this.z if you want to refer to the class level z. Remember, as far as the compiler is concerned, they are two completely different variables even though they have the same name.

So, why doesn't the line String y = "Why don't I need 'this' below?"; force you to write this.y = flyingPinkUnicorn;? Because of the first rule in the list above. The compiler looks for variables that have already been defined up to that point in the method or constructor that you're in and at the class level. However, it can't look inside of the brackets. So, even though I defined y as a String, that's only the case inside of the brackets. Once the compiler leaves the brackets, it ceases to know about what existed inside of them. If you delete the brackets, then you would have to write this. = flyingPinkUnicorn; This is what you were confusing when you stated this:
CAF123 said:
The ordering of parameters in the constructor you built was int superman, int z, int flyingPinkUnicorn. The method then labeled these as x = superman; (not this.x because x is not used as a parameter in the constructor), y = flyingPinkUnicorn; (not this.y for same reason above) and this.z = z (necessarily this.z since z was used as a class level variable).
If the class level name isn't reused in the method, it thinks that x and this.x are the same thing (within the rules above). You're thinking, "hey, I saw an x someplace so it must be this one over in this constructor, method, etc." But, the compiler can't look up into the class and then down into other methods or constructors (i.e. brackets) so it doesn't know about those variables. Those aren't the droids (variables) you're looking for. :-p

I know that this is a lot but I tried to explain is as concisely as possible. How that it helps.
 
Last edited:
  • #29
Hi Borg,
Borg said:
In the modified constructor, I've declared x to be a String. How can that be? At the line x = superman, the compiler only knows about variables up to that line. On the following line where x is declared to be a String, I am using my one shot at reusing the class level variable name. From that point on, you have to use this.x if you want to work with the class level x. If you move x = superman below the String x... line, it won't compile because it thinks that x is a String at that point. You would have to write this.x = superman.

I am not sure what you mean by 'using my one shot at reusing the class level variable name'.

You wouldn't be forced to write this.x = superman to get it to compile because x is also an int. x = superman would modify the local variable and this.x would modify the class level verion.
I don't think I understand this paragraph fully. Does it not contradict the comments after the code:
Code:
x = superman;	// The incoming variable superman is being used to set the class level variable x
So x = superman; sets the local variable superman to the class level variable x? x = superman; sets the class level variable, (as written in the comment after the code) but above you say this.x modifies it.

So, why doesn't the line String y = "Why don't I need 'this' below?"; force you to write this.y = flyingPinkUnicorn;? Because of the first rule in the list above. The compiler looks for variables that have already been defined up to that point in the method or constructor that you're in and at the class level. However, it can't look inside of the brackets. So, even though I defined y as a String, that's only the case inside of the brackets. Once the compiler leaves the brackets, it ceases to know about what existed inside of them. If you delete the brackets, then you would have to write this. = flyingPinkUnicorn; This is what you were confusing when you stated this:
If the class level name isn't reused in the method, it thinks that x and this.x are the same thing (within the rules above). You're thinking, "hey, I saw an x someplace so it must be this one over in this constructor, method, etc." But, the compiler can't look up into the class and then down into other methods or constructors (i.e. brackets) so it doesn't know about those variables. Those aren't the droids (variables) you're looking for. :-p

Why would you put the String in between those brackets? I don't think I have grasped this part either.

I know that this is a lot but I tried to explain is as concisely as possible. How that it helps.
I appreciate your help, but I don't feel like I understood it as well as the other examples. One question that sprung to mind was why reuse variables?

Thanks.
 
  • #30
CAF, are you using any book? You should.

The subject that you seem to misunderstand is the "scope" (or "scoping"). A Java program consists of a number of scope. Scopes can be nested and can follow one another. What exists in one scope is visible only in this same scope and all the nested scopes, but not in any other scope. A scope is basically a block of code between two curly brackets. So

Code:
{
   // scope A
   
      {
       // scope B - nested in A

       {
            // scope C - nested in A nested in B
       }
    }

    {
        // scope D - nested in A
    }
}

Here, scopes B and D are nested in A; whatever variables you define inside B is invisible in D in vice versa; any variables defined in A are visible in B, C, and D. Anything defined in C is visible in C only.

Things get a little trickier when you re-use names in various scopes. For example:

Code:
{
   // scope A

   int a;
   int b;

   {
       // scope B - nested in A

       int a;

       {
            // scope C - nested in A nested in B

            int b;
       }
    }

    {
        // scope D - nested in A

        int b;
    }
}

Here, a and b are defined in scope A and are, in principle, visible in B, C and D. B, however, defines its own a, so A's a is no longer visible, but A's b still is. C defines its own b, so it cannot access A's b, but it sees B's a. Finally, D can use A's a and its own b.

To complicate matters further, you can define variable in loop statements: for (int i = 0; i < 5; ++i) ; these variables are visible only within the loop statement (and the controlled statement), so that introduces a scope without those curly things.

Now, even though I said that an outer scope's variables eclipsed by an inner scope's variables are inaccessible, there is a way to use the class scope variables by referencing them via this, but that can only be done in a non-static member function (because static members do not have this to begin with).
 
  • #31
voko said:
Code:
{
   // scope A

   int a;
   int b;

   {
       // scope B - nested in A

       int a;

       {
            // scope C - nested in A nested in B

            int b;
       }
    }

    {
        // scope D - nested in A

        int b;
    }
}
This does not compile. The a and b defined in Scope A are visible throughout and cannot be redefined.
voko said:
Now, even though I said that an outer scope's variables eclipsed by an inner scope's variables are inaccessible, there is a way to use the class scope variables by referencing them via this, but that can only be done in a non-static member function (because static members do not have this to begin with).
Not true. Static, class level variables can be accessed via 'this'. It just isn't correct to do so because the value is applicable to all of the classes that you have created and not just one particular instance. IDEs and compilers will warn you about it (Static member accessed via instance reference) but the code will compile and function properly.
CAF123 said:
I am not sure what you mean by 'using my one shot at reusing the class level variable name'.
Think of it as saying "while I'm in this method, I don't care that there is a class level variable x. I want x to be something else". If you haven't made x to "be something else", x and this.x both refer to the class level variable. Once you decide to make it something else, only this.x will refer to the class level version (within the current scope).
CAF123 said:
I don't think I understand this paragraph fully. Does it not contradict the comments after the code:
Code:
x = superman;	// The incoming variable superman is being used to set the class level variable x
So x = superman; sets the local variable superman to the class level variable x? x = superman; sets the class level variable, (as written in the comment after the code) but above you say this.x modifies it.
superman is on the right side. You aren't setting superman, you're setting x. There is no local variable x that exists at that point so x and this.x both refer the same thing (the class level x). The compiler doesn't look ahead to see that you're going to create a local version of x on the next line.

CAF123 said:
Why would you put the String in between those brackets? I don't think I have grasped this part either.
The brackets could represent anything that has brackets like an if statement, a for loop, or just a set of brackets. The brackets define a scope that is walled off from other areas. Inside the scope, the compiler knows what has been defined previously but can't look inside other bracketed areas.

CAF123 said:
I appreciate your help, but I don't feel like I understood it as well as the other examples. One question that sprung to mind was why reuse variables?
Because it makes the code easier to understand? You're not really reusing the variables, just their names. Yeah, I know that doesn't make sense yet...

Here's another example of scope within a method. I am going to ignore the whole x vs. this.x issue. For now, I'm just showing you a single method. I'm also using all new variable names because I don't want you thinking about anything previously discussed. Just try to understand what is going on with the variable u.

Let's say that we have a class level variable s that can be modified by other methods in your class and we need a method to perform different actions depending on the current value of s. In this method, I am not modifying the value of s. However, I am creating a variable t at the beginning and defining a variable u in the two sections of an if/else statement. As far as the compiler is concerned, u can be defined inside either of the brackets because it wasn't defined earlier (like t). Creating another u within the else statement isn't a problem because even though it can look back for previously defined variables, it can't peek inside the brackets. As far as the code in the else brackets is concerned, u has not been defined yet (it can't see inside of the if brackets while it's inside of the else brackets).
Code:
int s = 10;	// Some class level variable

public int someRandomMethod(){
	int t = 2;

	if (s > 100){
		int u = 2 / s;
		if(u > 250){
			return u;	// Leave the method and return the value of u
		}
		// If u <= 250 the code will leave the if/else block and continue at the EXIT POINT
	}
	else{						// If s was greater than 100, it won't go in here
		int u = (10 * t) - s;
		if(u < 25){
			return u;
		}
		// If u <= 25 the code will leave the if/else block and continue at the EXIT POINT
	}
	// EXIT POINT

	// The compiler knows about s and t
	// The compiler does not know about u at this point because it can't look up and into brackets
	return 0;
}
Do you see why the compiler doesn't know about u at the end?
 
Last edited:
  • #32
Borg said:
This does not compile. The a and b defined in Scope A are visible throughout and cannot be redefined.

Even if scope A is a class and scopes B and D are its member functions, or scope A is a member function, and B and D are nested classes, or some other interesting situation?

I mentioned that some (hopefully, good) book is needed, the rules of shadowing in Java are quite complicated. Scoping, however, is simple as a concept, and that was what I wanted to demonstrate.
 
  • #33
voko said:
Even if scope A is a class and scopes B and D are its member functions, or scope A is a member function, and B and D are nested classes, or some other interesting situation?
If scope A is a class - yes but, only in that case. If you put that block of code within a method, it breaks. For now, let's try to get CAF123 to understand scope within a method and expand from there.
 
  • #34
Borg said:
If scope A is a class - yes but, only in that case.

This is not the only case. If scope A is a member, and the member defines inner classes, the inner classes may contain variables that shadow scope A's variables. There may be some other situations as well, my knowledge of Java is, admittedly, rusty.

Let me rectify my earlier statements: scoped variables, provided the code compiles, work the way I indicated earlier: visible within the scope they are defined in, and visible in nested scopes as well, unless they are shadowed (when this is allowed) by an identically named variable defined in a nested scope, and the same rules apply to the shadowing variables.
 
  • #35
voko said:
This is not the only case. If scope A is a member, and the member defines inner classes, the inner classes may contain variables that shadow scope A's variables. There may be some other situations as well, my knowledge of Java is, admittedly, rusty.

Let me rectify my earlier statements: scoped variables, provided the code compiles, work the way I indicated earlier: visible within the scope they are defined in, and visible in nested scopes as well, unless they are shadowed (when this is allowed) by an identically named variable defined in a nested scope, and the same rules apply to the shadowing variables.
Because you didn't clarify your example as a special case that only applied where the scope of A was at the class level, I assumed that you were referring to the general case that could be used anywhere.

I'm not sure by what you mean by Scope A is a "member" of, other than being a member of a class as we've both stated. I'll bet CAF123 hasn't been introduced to inner classes yet so I really didn't want to go there.

Interesting. Even though that's what we are discussing, I never saw the term 'shadowing' before today. Never too old to learn new things.
 

Similar threads

Replies
2
Views
1K
Replies
3
Views
2K
Replies
12
Views
2K
Replies
2
Views
2K
Replies
5
Views
2K
Replies
1
Views
2K
Replies
2
Views
4K
Back
Top