Related
I am curious why the last two prints generated different value?
class A {
int i = 1212;
}
class B extends A {
A a;
public B(A a) {
this.a = a;
}
}
class MainClass {
public static void main(String[] args) {
A a = new A();
B b = new B(a);
System.out.println(a.i);
System.out.println(b.i);
System.out.println(b.a.i);
b.a.i = 2121;
System.out.println("--------");
System.out.println(a.i); // 2121 ??
System.out.println(b.i); // 1212 ??
}
}
When I set "i" like this:
b.a.i = 2121;
I am accessing the same reference, it means the same Object A? Object A is created only once, so how is possible to set the variable on the object and get different result depends on the way how I access this value?
UPDATE:
Debug variables in IntelliJ
In IDE it seems that class B has it's own copy of "i" that is of course untouched by changing it via "b.a.i" because the change was made on the A object. Can you please arguing against this assumption because it is still in my head and IDE debug show to me that on the Object "b" there is an "i" variable.
Here the declaration of B is referring to A's object in two different way
inheriting A directly.
storing A as a property.
So B is having two different A.
Question #1: are you referring to the same A as inheriting?
Answer: no, by b.a.i you are not referring to the inheriting A, you are simply referring to property A
object A is created once this is true partially, actually you are creating another A by creating object of B.
To refer to the inheriting A you must use b.i
The Think is, int i = 1212 is the default value of all instances of A or it's children
when you modified the value for b, you modifies it only for that instance. So the other instances keeps it's default value.
One thing I would like to point out is that it is not typical to extend a class, and then create a reference to that class inside the child class.
When class B extends class A, that means that class B already has int i = 1212;. When you extend a class, you are essentially building on top of it.
So in your case, when you create a new A object, i = 1212. And then you create a new B object and pass in a, however, because class B extends A, it already has a variable called i that equals 1212.
Your print statements make sense:
a.i will be equal to 1212 because that is what the value is set to in Class A.
b.i will be equal to 1212 because B extends A and will inherit the variable i from Class A.
b.a.i will be equal to 1212 initially because you 1.) created an A object a, 2.) created a B object b that has it's own A Object variable that you set to a.
When you call b.a.i = 2121, you are setting your B object's variable a to have an i value of 2121. But remember that the object reference in your B object points to the first A object you created. Both a and b.a point to the same object in memory.
Consider the int a variables in these classes:
class Foo {
public int a = 3;
public void addFive() { a += 5; System.out.print("f "); }
}
class Bar extends Foo {
public int a = 8;
public void addFive() { this.a += 5; System.out.print("b " ); }
}
public class test {
public static void main(String [] args){
Foo f = new Bar();
f.addFive();
System.out.println(f.a);
}
}
I understand that the method addFive() have been overridden in the child class, and in class test when the base class reference referring to child class is used to call the overridden method, the child class version of addFive is called.
But what about the public instance variable a? What happens when both base class and derived class have the same variable?
The output of the above program is
b 3
How does this happen?
There are actually two distinct public instance variables called a.
A Foo object has a Foo.a variable.
A Bar object has both Foo.a and Bar.a variables.
When you run this:
Foo f = new Bar();
f.addFive();
System.out.println(f.a);
the addFive method is updating the Bar.a variable, and then reading the Foo.a variable. To read the Bar.a variable, you would need to do this:
System.out.println(((Bar) f).a);
The technical term for what is happening here is "hiding". Refer to the JLS section 8.3, and section 8.3.3.2 for an example.
Note that hiding also applies to static methods with the same signature.
However instance methods with the same signature are "overridden" not "hidden", and you cannot access the version of a method that is overridden from the outside. (Within the class that overrides a method, the overridden method can be called using super. However, that's the only situation where this is allowed. The reason that accessing overridden methods is generally forbidden is that it would break data abstraction.)
The recommended way to avoid the confusion of (accidental) hiding is to declare your instance variables as private and access them via getter and setter methods. There are lots of other good reasons for using getters and setters too.
It should also be noted that: 1) Exposing public variables (like a) is generally a bad idea, because it leads to weak abstraction, unwanted coupling, and other problems. 2) Intentionally declaring a 2nd public a variable in the child class is a truly awful idea.
From JLS
8.3.3.2 Example: Hiding of Instance Variables This example is similar to
that in the previous section, but uses
instance variables rather than static
variables. The code:
class Point {
int x = 2;
}
class Test extends Point {
double x = 4.7;
void printBoth() {
System.out.println(x + " " + super.x);
}
public static void main(String[] args) {
Test sample = new Test();
sample.printBoth();
System.out.println(sample.x + " " +
((Point)sample).x);
}
}
produces the output:
4.7 2
4.7 2
because the declaration of x in class
Test hides the definition of x in
class Point, so class Test does not
inherit the field x from its
superclass Point. It must be noted,
however, that while the field x of
class Point is not inherited by class
Test, it is nevertheless implemented
by instances of class Test. In other
words, every instance of class Test
contains two fields, one of type int
and one of type double. Both fields
bear the name x, but within the
declaration of class Test, the simple
name x always refers to the field
declared within class Test. Code in
instance methods of class Test may
refer to the instance variable x of
class Point as super.x.
Code that uses a field access
expression to access field x will
access the field named x in the class
indicated by the type of reference
expression. Thus, the expression
sample.x accesses a double value, the
instance variable declared in class
Test, because the type of the variable
sample is Test, but the expression
((Point)sample).x accesses an int
value, the instance variable declared
in class Point, because of the cast to
type Point.
In inheritance, a Base class object can refer to an instance of Derived class.
So this is how Foo f = new Bar(); works okay.
Now when f.addFive(); statement gets invoked it actually calls the 'addFive() method of the Derived class instance using the reference variable of the Base class. So ultimately the method of 'Bar' class gets invoked. But as you see the addFive() method of 'Bar' class just prints 'b ' and not the value of 'a'.
The next statement i.e. System.out.println(f.a) is the one that actually prints the value of a which ultimately gets appended to the previous output and so you see the final output as 'b 3'. Here the value of a used is that of 'Foo' class.
Hope this trick execution & coding is clear and you understood how you got the output as 'b 3'.
Here F is of type Foo and f variable is holding Bar object but java runtime gets the f.a from the class Foo.This is because in Java variable names are resolved using the reference type and not the object which it is referring.
I was given this code:
//Class X is created, and then class Y is derived from class X:
class X
{
protected int m;
}
class Y extends X
{
private int n;
public Y (int m, int n)
{
this.m = m;
this.n = n;
}
public String toString ()
{
return m + ", " + n;
}
}
//Class Y is used in the following way:
class UseY
{
public static void main (String[] args)
{
Y y = new Y (3, 4);
System.out.println (y);
}
}
So as you can see, the code involves inheritance.
I was asked:
Which output is created when the program UseY is executed? Which variables exist in object y?
My answer:
The output is:
3,4.
The variables in object y are m and n.
But I'm not sure about my second answer. What do they mean by variables exactly? Is my answer correct?
I would say:
The object y has a nested member, called n and a derived member from its super-class, called m.
The object y of type Y contains two variables; an int "m" and an int "n"
Output: 3, 4
Your answer to the first question is correct.
What do they mean by variables exactly?
This tutorial page explains the exact meaning of variables.
The Java programming language defines the following kinds of variables:
Instance Variables (Non-Static Fields) Technically speaking, objects store their individual states in "non-static fields", that is, fields declared without the static keyword. Non-static fields are also known as instance variables because their values are unique to each instance of a class (to each object, in other words); the currentSpeed of one bicycle is independent from the currentSpeed of another.
Class Variables (Static Fields) A class variable is any field declared with the static modifier; this tells the compiler that there is exactly one copy of this variable in existence, regardless of how many times the class has been instantiated. A field defining the number of gears for a particular kind of bicycle could be marked as static since conceptually the same number of gears will apply to all instances. The code static int numGears = 6; would create such a static field. Additionally, the keyword final could be added to indicate that the number of gears will never change.
Local Variables Similar to how an object stores its state in fields, a method will often store its temporary state in local variables. The syntax for declaring a local variable is similar to declaring a field (for example, int count = 0;). There is no special keyword designating a variable as local; that determination comes entirely from the location in which the variable is declared — which is between the opening and closing braces of a method. As such, local variables are only visible to the methods in which they are declared; they are not accessible from the rest of the class.
Parameters You've already seen examples of parameters, both in the Bicycle class and in the main method of the "Hello World!" application. Recall that the signature for the main method is public static void main(String[] args). Here, the args variable is the parameter to this method. The important thing to remember is that parameters are always classified as "variables" not "fields". This applies to other parameter-accepting constructs as well (such as constructors and exception handlers) that you'll learn about later in the tutorial.
In this case, the variables present are the instance fields n and m (type 1 above). The object of type Y has n already defined in its class. Since it extends X, it inherits the class member field m as well. A subclass inherits all of the public and protected members of its parent. Therefore, the variables present in the object of type Y are members m and n.
I don't understand how exactly it works.
We have two class A and B. Class B extends A.
Class A have x attribute, and test method which modify this attribute.
Class B have x attribute, and test method which modify this attribute.
public class A {
int x;
public void test() {
this.x = 1;
System.out.println("A" + getX());
}
int getX() {return x;}
}
public class B extends A {
int x;
public void test() {
this.x = 2;
System.out.println("B" + getX());
}
int getX() {return x;}
}
public class Main {
public static void main(String[] args) {
A a = new A();
a.test();
System.out.println(a.getX());
System.out.println("point 1");
a = new B();
a.test();
System.out.println(a.x);
}
}
Output:
A1
1
point 1
B2
0
My prediction about last line of output was 2, but is 0. Why is 0?
Let's understand these lines of code:
a = new B();
a.test();
System.out.println(a.x);
You create a new object of B. It will re-initialize the variable - A.x = 0 and B.x = 0.
Then you invoke a.test(), which will call the overridden method test() in class B, which will set B.x to 2 using this.x = 2;. Note at this point, A.x is still 0.
Then you access a.x, which will access the field x in class A. The fields are not polymorphic. You don't override fields, but you hide them. The variable x in B hides the variable x in A.
If both A and B have a member named x, the one in B will block access to the one inherited from A. Remove the int x; declaration from B, or explicitly use super.x, if you want to reference the one in the parent class.
Starting from begin.
When you write
A a;
You say to JVM please reserve me in memory an address for something that fits A.
after when you do
a = new A();
You say to JVM, create a new object of class A and save the address to it under a
when you do this;
a.test();
You say to JVM, go to memory address a and from object there invoke method test().
Next thing what you do is this:
a = new B();
You say to JVM, create a new object of class B and save the address to it under a. No error here as B fits A as is a child class.
(You loose the connection with object of class A ass you changed it to B).
next operation is
a.test();
you also know this, but this time under address a is instance of class B. This time JVM search for the method in class B, if not fond then will search in class A.
I think you should start over with the Inheritance/Polymorphism concepts first.
But to make it clear: You have an object "a" which is declared as with type "A". Now, when you call the method test (which is overriden inside B in this case), the JVM calls the actual objects method. So, before "point 1" a.test calls A's test method, after "point1" it calls B's test method.
The problem is that this feature (called polymorphism) works only on methods. Whilst when you call an instance variable (as a.x) , the JVM calls the declared object variable. In this case is A. If you make a cast first, you'll get the right value: ((B)a).x
Note, the difference between actual and declared object is based on the type after the "new" operator (like new B()) and that in the object declaration
I have a couple of EXTREMELY basic Java questions that I would like to finally understand, once and for all. I have the following short piece of code:
public class VeryBasicJava{
public static void main(String[] args){
int x = 3;
int y = 4;
swapMe(x, y);
}
private void swapMe(int a, int b){
int a;
int b;
int tmp = a;
this.a = b;
this.b = a;
}
}
When I compile, I get the dreaded "non-static method swapMe(int,int) cannot be referenced from a static context" error. Also, I get "a is already defined in swapMe(int,int)" and "b is already defined in swapMe(int,int)"
What I need to finally get through my thick skull, is the "non-static method" error, how (why) it is caused, and how to avoid it.
Further, I was under the assumption that you could do what I am attempting to do with my 'a' and 'b' variables in the "swapMe" method. I thought I could pass in an 'a' and 'b', but also create new variables 'a' and 'b', and reference them with "this" keyword.
I know this is extremely basic, but these two "issues" are two of the main sticking points I have with Java, and for some reason, cannot seem to properly learn.
Thank you all, for taking the time to read this. Have a great day.
That means that the method swapMe() is an instance method and you need an instance of the VeryBasicJava class to invoke it, like this:
VeryBasicJava instance = new VeryBasicJava();
int x = 3; int y = 4;
instance.swapMe(x, y);
Alternatively, you could declare swapMe() as static, in that way you won't need to create an instance first:
private static void swapMe(int a, int b)
You have just a few minor problems. You mentioned in a comment that you have some experience with C, so I’ll try to draw some basic analogies. A static method (such as main) behaves like an ordinary C function. A non-static method, however, takes a hidden parameter: this, which refers to an object on which that method is to operate. When you write a method such as this:
private void swapMe(int a, int b) {
// ...
It really means something like this:
private void swapMe(VeryBasicJava this, int a, int b){
// ^^^^^^^^^^^^^^^^^^^^
// ...
Because the this parameter is treated specially, there is a special syntax for calling non-static methods on objects:
myInstance.swapMe(someA, someB);
// ^^^^^^^^^^ ^^^^^ ^^^^^
// this a b
And because swapMe is not declared static, it expects to be called like the above.
The fact that main is declared inside the VeryBasicJava class does not mean that you automatically have a VeryBasicJava object. Again, because main is static, it is just like an ordinary C function:
void VeryBasicJava_main(...) {
// ...
In order to create an instance of an object, you use new:
VeryBasicJava vbj = new VeryBasicJava();
This is analogous to malloc in C:
VeryBasicJava *vbj = malloc(sizeof(VeryBasicJava));
VeryBasicJava_construct(vbj);
With an instance, you can invoke a method:
vbj.swapMe(spam, eggs);
Your other issue is twofold: one of scope, and of members. Scope, as you may know, refers to where a variable exists. Take this function:
1: private void swapMe(int a, int b) {
2: int a;
3: int b;
4: int tmp = a;
5: this.a = b;
6: this.b = a;
7: }
When this method is called, the following things happen:
a and b are created, given the values specified in the call to swapMe.
A new a is created, local to swapMe, with the default value 0. This a hides the parameter a, and there is no way to differentiate them.
A new b is created, also strictly local. It too has the default 0 value, and hides the parameter b.
tmp is created, and its value is set to that of the newly declared a, so it too is 0.
[see below]
[see below]
The locals a and b cease to exist, as do the parameters a and b.
In lines 5 and 6, you attempt to use the syntax this.a to refer to the local a rather than the parameter. Though this syntax exists in Java, it does not do what you mean. Parameters are treated just the same as local variables, so rather than differentiating between those two categories, this.a differentiates between locals and members. Now, what are members? Well, say your class declaration contains variable declarations:
class VeryBasicJava {
private int a;
private int b;
// ...
}
That’s just like member declarations in a C struct:
struct VeryBasicJava {
int a;
int b;
};
What this means is that when you create an instance of VeryBasicJava:
VeryBasicJava vbj = new VeryBasicJava();
That instance has its own variables a and b, which can be used in any non-static method:
public void print() {
System.out.println("a is " + a);
System.out.println("b is " + b);
}
If you have a local variable with the same name as a member, then you must use this to explicitly state that you want to refer to the member. This complete program illustrates how to declare, use, and differentiate between members and locals.
class VeryBasicJava {
private int a;
private int b;
private int c;
public static void main(String[] args) {
VeryBasicJava vbj = new VeryBasicJava();
vbj.a = 3;
vbj.b = 4;
vbj.c = 5;
vbj.print(1);
}
public void print(int a) {
int b = 2;
System.out.println("a is " + a);
System.out.println("b is " + b);
System.out.println("c is " + c);
System.out.println("this.a is " + this.a);
System.out.println("this.b is " + this.b);
System.out.println("this.c is " + this.c);
}
}
It will produce this output:
a is 1
b is 2
c is 5
this.a is 3
this.b is 4
this.c is 5
I hope these examples and explanations are helpful.
Your problems stem from not understanding how the object-orientated paradigm works.
The idea is that you define a class, which is a "type of thing". From that class, you create instances, which are effectively examples of that type of thing.
For example, when you create a class "Wallet", that defines how your
system will treat wallets (i.e. what they can do, and what you can do
with them). You can now create multiple different instances of
wallets, that store different values, but still work the same way.
(e.g. "myWallet" and "yourWallet" are both Wallets, so you can take
money out and put money in etc, but if I check the money in
yourWallet, I get a value of 50, whereas if I check the value in
myWallet, I get a value of 20)
Now, "static" methods belong to the class. This means that they can't access members variables specific to the class. For example, if I'm keeping track of every wallet in my system, that value doesn't belong to any particular wallet in the class, but it's still involved with that class, so we make it static.
To use my example, if you have two objects of type "Wallet", and one
has its "cash" value set to 30, and the other has its cash value set
to "25", a static function can't access both values, so it can't
access either. You have to give it a particular wallet to access.
The advantage of this method over C's approach is that it ties related functionality together. For example, if you see a C array of ints, you don't really know what they are intended to represent and may do something unexpected with them. But if I give you a Java array of Wallets, you also get the methods that influence how you interact with them. (This is a really stripped down explanation of encapsulation)
One of the principle issues with Java is that it ties everything to a class. This causes a problem for the main method, which has to start the program, because it has no instances yet, but must still be part of the class. Therefore the main method must always be static. This tends to confuse new programmers, as invariably the first thing you do within the main method is create an instance of the class it's "inside".
In your example, you've got no "specific" data. Everything's inside the methods, which means you're effectively trying to write procedural code in Java. You can do this (just declare everything static), but the language will fight you, and you'll write very bad code.
When I was originally starting out with Java, I effectively treated the main() method of a class as if it wasn't part of the class. Conceptually, it helped, because you stop thinking of the non-static stuff as something that's already there (which is your main issue). But my recommendation to you is try reading through this. But there are some very good transition courses out there for learning object-orientated programming, and you may want to invest in them.
Classes are a template for OBJECTS. An instance of a class (i.e. and object) has its own version of variables and methods that are non-static.
static methods and fields are not tied to any specific instance of a class.
So it makes no sense to invoke a class instance method from a static method, without the instance on which you want to invoke the method. In your example, this is a reference to an instance, but you have no instance....
For your second question, when you create a function, it creates its own little stack for all of its variables. Its arguments are included in that stack - so, your stack looks like this:
int a; //this is the first argument
int b; //this is the second argument
int a; //this is the first line of your function
int b; //this is the second line of your function
That's why you're getting an issue - the a and b you declare after your arguments are conflicting with your arguments, not "this.a" and "this.b".
Your first question has already been answered.
As the fix's been provided, I would like to add:
static methods can only call other static methods and access only static variables directly (in java).
To call non-static methods, you have create an instance of that class and call the methods then.
swapMe needs an instance of VeryBasicJava to invoke it. Static does not.
From outside that object, you could call: VeryBasicJava.main(args).
From outside the object, you would need to do (new VeryBasicJava()).swapMe(a,b) to invoke that method.
The reason you are getting errors inside of swapMe is because you are defining those variables twice. The signature line declared them in that namespace for you. In that method, you already have an int a. Then on the first line, you declare int a again.
What you want to do in your swap is something like this:
private void swapMe(int a, int b){
int tmp = a;
a = b;
b = tmp;
}
Of course the variables a and b only exist in that method so as soon as the method ends your work is lost. If you wanted to keep it, make the variables class variables and provide getters and setters for them.