Consider:
int a = 0;
int b = 3;
//Constructor 1
public ClassName (int a) {
this(a, b); //Error
//new ClassName(a, b) //No error
}
//Constructor 2
public ClassName (int a, int b) {
this.a = a;
this.b = b;
}
First question:
I get an error saying "b should be static". Why can't I use the default value (3) for b in this way?
Second question:
In the first constructor, if I use the comment outed part, I do not get an error. Is it an acceptable usage?
The use of instance variables in an explicit constructor invocation is prohibited by the JLS, Section 8.8.7.1.
An explicit constructor invocation statement in a constructor body may not refer to any instance variables or instance methods or inner classes declared in this class or any superclass, or use this or super in any expression; otherwise, a compile-time error occurs.
This prohibition on using the current instance explains why an explicit constructor invocation statement is deemed to occur in a static context (§8.1.3).
You referenced the instance variable b. The compiler didn't raise this error on a because it's a local variable, which shadows the instance variable a.
The "static context" may be why your IDE is suggesting to make b static, so it can be referenced. It makes sense; the ClassName part of the object isn't constructed yet. Replace that usage of b with something else, such as a static constant, or a literal int value.
To answer your other question, typing new ClassName(a, b) isn't an error because at this point, this instance has been constructed, and you're creating a separate, unrelated ClassName object.
First question: I get an error saying "b should be static". Why can't I use the default value (3) for b in this way?
The correct way to supply a default value for b to the other constructor is this(a, 3);. You cannot refer to instance variables until after this(...). That's just one of the rules of the language.
Second question: In the first constructor if I use the comment outed part I do not get an error. Is it an acceptable usage?
new ClassName(a, b); does something different. It creates a separate instance of the class. In my humble opinion it is probably not the best thing to do. People expect new to create one instance of a class, whereas using new ClassName in the constructor creates two.
When using variables in classes, it is important to note where that validity of scope is. You've instantiated new a,b variants of the variables there. You're tricking yourself into believing those are the same variables. Actually they're in another address space. If you want to use your class variables you'll have to take out the parameters to the functions. Then they'll sync with the class you're in, rather than isolating the arguments a, b to within the scope of your function,
Related
Consider we have classes like this:
class A {
public B b;
public void someFunc() { // called sometime
b = new B();
}
}
Class B's constructor assigns some inner variables.
Field b is not thread-safe in the sense another thread can view b not-null when B constructor hasn't finished. (during someFunc execution)
My question is the following: how can it be (from the logic perspective) that the constructor hasn't finished yet?
For me reordering of such kind is magic.
In the context of thread safety, this usually happens because of just-in-time (JIT) compilers. A JIT compiler takes Java byte code and translates it in to machine code to make it run faster. During translation, it's able to make a lot of optimizations, such as inlining various methods and constructors.
Supposing B had a constructor like this:
class B {
int x;
B(int x) { this.x = x; }
}
When a constructor is inlined, it takes Java code that's something like this:
b = new B(1);
And translates it to machine code that takes steps similar to the following:
Allocate space for a B object somehow.
Store the pointer to that memory in to b.
Store 1 in b.x.
In other words, code which is analogous to this (in terms of ordering):
b = new B();
b.x = 1;
But we don't actually call a constructor at all. We'd just allocate a B, however the JVM does it internally, and assign b.x directly. Calling the constructor would involve jump instructions, so it's a bit faster to inline it.
There's an example like that in the famous "Double-Checked Locking is Broken" Declaration.
A regular Java compiler would be allowed to inline constructors too, but regular Java compilers don't typically perform many optimizations.
Instance of object can "escape" from constructor, like that:
public class EscapeDemo {
static void escape(B b) {
System.out.println(b.strA);
System.out.println(b.strB); // still null in this example, even if field is final and initialized to non-null value.
}
public static void main(String[] args) {
System.out.println(new B());
}
}
class B {
final String strA;
final String strB;
B() {
strA = "some operations";
EscapeDemo.escape(this);
strB = "here";
}
}
prints:
some operations
null
B#hashcode
And in similar way that reference could escape to some code that will use it from other thread.
Like Andy Guibert added in comment: this is a bad practice to write such code - as it might be source of many weird errors and hard to trace bug - like here we have something that should not be a null, but it is a null.
And if you want to do something with object instance on creation it is much better idea to create static factory method that will create instance and then do something with (like add to some collection/registry) it and then return it.
Also if you include usage of weird code nad hacks - in bytecode java object creation is separated from constructor call, so it is possible from bytecode level to create an object, pass it somewhere and call constructor in some other place.
But otherwise field is assigned after right side expression is executed so for code
b = new B();
field b can be only null or B instance after constructor is called. Unless you would set that field from inside of B constructor like in my escape example.
If I understand your question correctly. You are asking about if you create an instance of Object A which has a field b of type B and the field b is not initialized when A is created but only some other object calls someFunc(). What will happen when some other thread tries to access this field b?
If so, when you create a new object of type B the JVM will allocate some memory for this object and then will return a reference which will be held in the field b. If other thread tries to access the field b before it got the reference of the new object, it will return null otherwise will return the reference to the newly created object.
Consider the following class hierarchy:
class A {
compute(int a) {
compute(a, 1);
}
compute(int a, int b) {
// do some things
}
}
class B extends A {
compute(int a, int b) {
// do some stuff
}
}
if I initialize a B object like following using a A reference:
A foo = new B();
if I call:
foo.compute(1)
then, inside this method call, it will call class A's compute(int, int) or call class B's compute(int, int) ?
Any citation's from official java documentation?
i would guess you are a C++ programmer. The behavior you're pointing do happen in C++ when you don't define the compute(int, int) function as virtual.
C++ designers are always looking for extreme performance, and so the non-virtual method calls of an object are defined at compile time, to avoid an additional reference to a function pointer in its vtable, aka the table of virtual functions that it has.
If that's the case, let me tell you that in Java, all methods are implicitly defined as virtual in C++ terms. That is: for a given object any method called is always the one belonging to the object that was constructed, not to the variable that references it.
I do not have any citation upfront but let me take a shot at explaining what will happen.
We have
A foo = new B();
Here the reference type of foo is A. The object being instantiated is of type B.
Note that this statement could get compiled only if object B satisfies the is-a relationship with A. Since B extends A, B satisfies the is-a relationship with A.
The methods that could be invoked by foo are based on the reference type. Hence, foo can only invoke methods which are declared/defined in type of A. The actual method being invoked is based on the object type. Since the object referenced by foo is of type B, the method on object B is invoked. Hence, it is B.compute(int,int) that is being invoked.
The method invoked will be B.compute(int, int), which you can easily find by trying it.
Since you asked for documentation describing why this is, I will provide it. But it's not very easy to follow.
This is described in JLS Sec 15.12.4. Run-Time Evaluation of Method Invocation.
Recall that the method invocation in question is compute(a, 1);
15.12.4.1. Compute Target Reference (If Necessary)
The method invocation is of the form MethodName, and it is non-static, so the following case applies:
Otherwise, let T be the enclosing type declaration of which the method is a member, and let n be an integer such that T is the n'th lexically enclosing type declaration of the class whose declaration immediately contains the method invocation. The target reference is the n'th lexically enclosing instance of this.
So we know our target reference. This is a long-winded way of saying that we're going to invoke the method on this.
15.12.4.2. Evaluate Arguments
This is trivial, since the arguments are ints.
15.12.4.3. Check Accessibility of Type and Method
Yeah, the type and method are accessible.
15.12.4.4. Locate Method to Invoke
The invocation mode is virtual, as described in Sec 15.12.3. Hence this applies:
If the invocation mode is interface or virtual, then S is initially the actual run-time class R of the target object.
Notice that if you were to write System.out.println(getClass()) immediately before the compute(a, 1) line, it would print out B, not A when invoked in the way shown in the question. Hence the run-time class R is B, so S is B also.
Also:
Let X be the compile-time type of the target reference of the method invocation.
X is A.
Then:
class S contains a declaration for a method named m with the same descriptor
and
the invocation mode is virtual, and the declaration in S overrides X.m (§8.4.8.1), then the method declared in S is the method to be invoked, and the procedure terminates.
So, the method declared in B is invoked.
This is pretty heavy reading, and, quite honestly, you don't need to know it in this much detail. This is the first time I've actually bothered to pick through that bit of the spec.
The simple rule to remember is: if the method is overridden in a subclass, that's the one that gets invoked.
This question already has answers here:
Is there a difference in setting fields inside or outside the constructor?
(8 answers)
Closed 8 years ago.
This is probably a 'duplicate', but I'm not sure how to search for this question...
I am initializing a non-static member variable at the declaration line:
public class A
{
private B b = new B();
...
}
I am doing it instead of initializing this variable inside the default constructor:
public class A
{
private B b;
public A()
{
b = new B();
}
...
}
Is there any difference between the two, except (perhaps) the former not being "ANSI Java" or something like that?
I am getting two different byte-codes (i.e., two different 'class' files) for the two implementations above, which leads me to believe that there might be run-time differences.
So I would like to know if I have any reason to expect anything different during run-time.
Thanks
The first one is a declaration and initialization at the same time .
In the second example instead you have the declaration of the b variable not initialized and then in the constructor you initialize the variable ...
The functional difference can come at the moment that you add another constructor, in that case the b variable should be initialized even in that constructor or if not, there will be a huge difference .
In the first case you have the variable initialized no matter how many constructor you implement ...
Honestly I don't understand how can you pretend to have the same bytecode, writing two different things as for this case .
No different in general (mean that declare outside and inside a constructor will behave something different). Just remind that initialize outside will run first, before come into some specific constructor. For example:
class A {
int a = 3;
public A() {
a = 4; // now a = 4. not 3
}
}
But, I often use them with different purpose :
Initialize variables inside constructor make it clearer and help you initialize something more complex. for example, put some logic code, put a loop to add items, ... that you cannot do when initialize outside of constructor scope.
When you have many overloading constructors, and some variables always declare same. Simple "state variable" such as isExist isEmpty ... I often initialize outside of constructor scope. So, all other constructors don't do the same thing.
There are no difference, both codes work well. I personally prefer the second way for a big class, meanwhile the first is preferd for small classes.
There is one small difference between this approaches!
When variable is declared inside constructor, there is chance that after some time second constructor will be created and this variable will be uninitialized. For fighting this declare this variable as final - if this is possible of course ;)
Other differences not exists :)
public class A
{
private B b;
public A() {
b = new B();
}
public A(int value) { // second constructor
}
...
}
After using A a = new A(5); field b is null.
The main difference is the order of function calls:
In the 1st case, method B() is called before method A().
In the 2nd case, method A() is called before method B().
An additional difference is what has been suggested in all other answers...
When a non-default constructor which does not initialize variable b exists:
In the 1st case, variable b will be initialized even when that constructor is used.
In the 2nd case, variable b will not be initialized whenever that constructor is used.
class A
{
int i=10;
void show()
{
System.out.println("class A");
}
}
class B extends A
{
int i=5;
public void show()
{
System.out.println("class B");
}
}
class M
{
public static void main(String s[])
{
A a=new B();
a.show();
System.out.println(a.i);
}
}
OUTPUT= class B
10
If class A method is overridden by class B method then why not the variable 'i'?
Because variables are not virtual, only methods are.
It is not overwritten, but hidden. In your output you specifically requested the value of a.i, not ((B)a).i.
This is a "feature" of the implementation. In memory, this looks like so:
a:
pointer to class A
int i
b:
pointer to class B
int i (from A)
int i (from B)
When you access i in an instance of B, Java needs to know which variable you mean. It must allocate both since methods from class A will want to access their own field i while methods from B will want their own i (since you chose to create a new field i in B instead of making A.i visible in B). This means there are two i and the standard visibility rules apply: Whichever is closer will win.
Now you say A a=new B(); and that's a bit tricky because it tells Java "treat the result from the right hand side as if it were an instance of A".
When you call a method, Java follows the pointer to the class (first thing in the object in memory). There, it finds a list of methods. Methods overwrite each other, so when it looks for the method show(), it will find the one defined in B. This makes method access fast: You can simply merge all visible methods in the (internal) method list of class B and each call will mean a single access to that list. You don't need to search all classes upwards for a match.
Field access is similar. Java doesn't like searching. So when you say B b = new B();, b.i is obviously from B. But you said A a = new B() telling Java that you prefer to treat the new instance as something of type A. Java, lazy as it is, looks into A, finds a field i, checks that you can see that field and doesn't even bother to look at the real type of a anymore (because that would a) be slow and b) would effectively prevent you from accessing both i fields by casting).
So in the end, this is because Java optimizes the field and method lookup.
Why no field overrides in Java though?
Well, because instance field lookups in Java happen at compile time: Java simply gives you the value of the field at a given offset in object's memory (based on the type information at hand during compilation: in this case a is declared to be of type A).
void foo() {
A a = new B();
int val = a.i; // compiler uses type A to compute the field offset
}
One may ask "Why didn't compiler use type B since it knows that a is in fact an instance of B? Isn't it obvious from the assignment just above?". Of course, in the case above, it's relatively obvious and compiler may try to be smarter and figure it out.
But that's compiler design "rat hole", what if a "trickier" piece of code is encountered, like so:
void foo(A a) {
int val = a.i;
}
If compiler were "smarter", it would become its job to look at all invocations of foo() and see what real type was used, which is an impossible job since compiler can not predict what other crazy things may be passed to foo() by unknown or yet unwritten callers.
It's a design decision by the developers of Java, and is documented in the Java Language Specification.
A method with the same method signature as a method in its parent class overrides the method in its parent class.
A variable with the same name as a variable in its parent class hides the parent's variable.
The difference is that hidden values can be accessed by casting the variable to its parent type, while overridden methods will always execute the child class's method.
As others have noted, in C++ and C#, to get the same override behavior as Java, the methods need to be declared virtual.
a is an instance of A. You call the constructor B(). But it is still a A class.
That is why i equals 10;
The override from the method will be succeded.
Note a class starts not with
public class A()
but with;
public class A { ... }
Tip: You can use setters and getters to make sure of what data-members you use.
Or: You simply can set the values at the constructor instead of the class declaration.
Because by default the variables are private. You must declare it as "protected", then will be properly inherited.
I have something unclear concerning casting reference variable in Java.
I have two classes A and B. A is the super class of B.
If I have the two objects, and then the print statement:
A a = new A(); //superclass
B b = new B(); //subclass
System.out.println ((A)b);
then what exactly is happening when the println method is executed?
I know that because B is a subclass of A, I am allowed to make the following cast:
A a2 = (A)b;
I also know that when println takes a reference variable as argument, then the toString() method of the class, which has created the object-argument, is invoked (implicitly). This is so, because the method println() is looking for an argument of type String, and the toString() method represent the object as a string. And even if we don't write toString(), the method is invoked - implicitly. So, the following two statements are equivalent:
System.out.println (b);
System.out.println (b.toString());
So, my question is: what is the implicit action taken when we have
System.out.println ((A)b);
?
I suppose that the type of the reference variable b is automatically changed from B to A. The variable should still be pointing to the same object - the one created with
B b = new B();
but just the type of b would be now changed. Is this correct?
Another question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?
Thanks a lot.
Regards
The cast has no impact in this case.
The System.out.println(XXX) takes parameters of different types (multiple overloaded versions) but in this case you would get the version that takes Object. Since every object in Java supports toString(), toString is invoked on the actual argument, no matter what it is.
Now, since all methods in Java are dispatched dynamically, the version that runs is the version that corresponds to the dynamic type. Casting an object of B to A only changes the static (declared) type of the expression. The dynamic type (what's really in there) is still a B. Therefore, the version in B gets invoked.
There are many declarations of println(...) in the PrintStream class (which is the type of System.out).
Two of them are:
void println(String x)
void println(Object x)
When you call println((A)b) the compiler chooses to call println(Object) because A is not String (or any of the other types that println supports). When you call println(b.toString()), the compiler chooses println(String) because you are passing a String.
In your case, casting b to A has no effect since println() doesn't have a declaration for either A or B types. But the cast will still occur (because you asked for it), or maybe it won't because the compiler optimises it away as it knows it is redundant and it can't fail and has no effect.
It is not idiomatic to write:
A a2 = (A)b;
as this is redundant since B is a subclass of A. It may be that the compiler will optimise away the cast (which is a run-time operation to check whether an object is of a particular type, never to change it's type).
Once an object of type B is constructed, it's type never changes. It is always a B:
class B extends/implements A {...}
B b = new B(); // construct a B
A a = b; // assign a B to an A variable, it's superclass
A a = (A) b // as above including check to see that b is an A (redundant, may be optimised away).
B b = a; // Syntax error, won't compile
B b = (B) a // Will check whether a is of type B then assign to variable b
In the last case, since B is a subclass of A, it may be that a holds an instance of B and the cast will succeed. Or it may be that a holds an instance of some other class that extends/implements/is A and isn't a B and you'll get a ClassCastException.
So since an object of type B always retains it's identity (it's "B"-ness) then any (instance-) methods called on that object will always call B's implementation regardless of whether the variable through which you access the object was declared as A or B.
Remember, you can only call methods that are declared in the class that the variable is defined as.
So for example, if B declares a method b_only() then the compiler won't allow you to write a.b_only(); you could write ((B)a).b_only() though.
Since Java methods all have dynamic dispatch, which function gets called doesn't depend on the static type of the reference. Therefore, the results will be the same with or without the cast. [The results could be different if you were downcasting - the casting version could throw an exception]
Is this correct?
Sort of. The result of the casting expression would be of the A type. The type of the 'b' variable will always remain of type B.
Another question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?
The instance methods of the underlying object will be called. Example:
class Foo {
public static void main(String[] args) {
B b = new B();
assert "B".equals(((A) b).m());
}
}
class A {
String m() { return "A"; }
}
class B extends A {
String m() { return "B"; }
}
Always think of your object as the type it's instantiated as (B in your case). If it's upcast to A think of it as--hmm--think of it as B putting on A clothes. It may look like an A, and you may not be able to do any of the nice B things you want to do, but inside the clothes it's still a B--the clothes don't change the underlying object at all.
So the summary would be--you can only call the methods in A, but when you call it, it goes straight through and executes it as it would if it was a B.
I think when we use reference variable in java and by using this variable we can assign a object of any class type. most of the cases we create a reference variable of Interface and abstract class because we can't create the object of interface and abstract class so assign the object of class in reference variable of Interface or abstract class.
Ex-
Interface X {
public abstract void xx();
public abstract void yy();
}
Class XXX implements X {
...........
}
Class XY extends XXX {
X xy = new XXX();
}
here xy is a reference of Interface X and assign the object of Class XXX in the reference of Interface.
so according to my point of view by using reference variable we can also use interface to participate in Object creation.
The casting, as has been mentioned, is irrelevant in this case due to overridden methods being dynamically bound. Since the toString is present in all objects it meets this condition and thus the object type and method to call are determined at runtime.
Please note though, this is NOT the case with all methods since only overridden methods are dynamically bound. Overloaded methods are statically bound. Many of the answers here mention that java methods are always dynamically bound, which is incorrect.
See this question for a more detailed explanation.
question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?
in this case the method of subclass b is called ; to convincingly understand why; you may relate to the following real world scenario
consider a parent class Father exhibiting a behaviour(method): height
defined as
the father is tall ;height = 6'2"
Son is a child class inheriting the height behavior from Father ;as a result he is also tall; height being 6' clearly overriding the behaviour
whenever your subclass Son calls the behavior height on his name he displays the overridden behavior i.e his own height 6' .