Why does my child class not initialize variables properly in java - java

In the code below, myString is always initialized to null. I have to manually initialize in an init() or similar. As far as I can tell it is related to superclass/subclass but I don't understand the exact mechanism
public class A extends B {
private String myString = "test";
public static void main(String[] args) {
new A();
}
public A() {
super();
}
public void c() {
System.out.println(myString);
}
}
public class B {
public B() {
c();
}
public void c() {
}
}

The issue with your code is, that myString is initialized at the begin of the constructor of class A but right after the super constructor (i.e. class B). Since you access the variable before from the constructor of class B (indirectly via call to overriden methode c) your get this behaviour.
As a rule of thumb: if you want to avoid unexpected behavior do not call overriden methods before the constructor has been executed.

Add a call to c(); overidden method right after the object has been fully created and call to superclass constructor is done.
Change your code to this ..
public class A extends B {
private String myString = "test";
public static void main(String[] args) {
new A();
}
public A() {
super();
c(); // Include the call to c(); here ...
}
public void c() {
System.out.println(myString);
}
}
public class B {
public B() {
}
public void c() {
}
}
// Output : test

Thinking in Java Second Edition by Bruce Eckel, Behavior of polymorphic methods
inside constructors (p. 337-339).

Related

Tricky order of the initialization

I'm not novice in java, but I've got an example that made me confused.
Here it is:
class A {
public A() { System.out.print("O"); }
}
class B {
{ System.out.print("A"); }
public B() { System.out.print("D"); }
}
class C {
static { System.out.print("3"); }
public C() { System.out.print("P"); }
}
public class D extends C {
private A objA = new A();
private static B objB = new B();
public D() { System.out.print("T"); }
public static void main(String[] args){
new D();
}
}
So what is the result in system.out?
We know that static members are the first, so "3" will print first cause it is in the superclass and private static B objB = new B(); will initialize after it (instance initializer and then constructor).
We get 3AD in console.
Then the main method runs and create a new instance of class D, its ok.
But since this step the order is strange:
1 Constructor of the superclass public C() { System.out.print("P"); }
3ADP in console.
2 Then field of D.class private A objA = new A();
3ADPO in console.
3 And constructor of D.class is the last, so:
3ADPOT in console.
So the question is: why does superclass constructor run before field of subclass? I thought that constructors have lowest priority. Can anyone share a link on docs plz?
Simply if we think then its easy to understand that first the subclass inherits from the super class and then only can it override the behaviour or acess the properties defined in the super class.
Whenever we create an object of a class A , first it is checked if the class is loaded, if not then it is loaded which invokes its static initilizer if it is present, then all the static fields are initilized (with default value or the values defined). After this super constructor is called, all the properties as set by the super class are set. Then all the instance fields are initilized and then finally constructor code of A is executed.
Below is the execution ordering.
public class A{
static{
// 1
}
int x = 30; // 3
public A(){
//4
}
}
public class B extends A{
static{
//2
}
private int s = 60; //5
public B(){
//6
}
}
public class Test {
public static void main(String[] args){
new B();
}
}

Java - Subclass calls supers constructor which calls subclass method instead of its own

I'll start with a code example:
class A {
public A() {
f(); //When accessed through super() call this does not call A.f() as I had expected.
}
public void f() {} //I expect this to be called from the constructor.
}
class B extends A {
private Object o;
public B() {
super();
o = new Object(); //Note, created after super() call.
}
#Override
public void f() {
//Anything that access o.
o.hashCode(); //Throws NullPointerException.
super.f();
}
}
public class Init {
public static void main(String[] args) {
B b = new B();
}
}
This program throws a NullPointerException. When the object b enters the constructor of its superclass A and makes a call to the method f() which is overridden by the class B B.f() is called, instead of A.f() which I would have expected.
I thought a superclass wasn't supposed to know if it was subclassed or not but surely this can be used by a class to tell if it's been subclassed or not? What's the reason behind this? Is there any workaround if I really want A.f() to be called instead of B.f()?
Thanks in advance.
Follow up question:
Thanks for the answers. I now understand why it is like it is, but here's a follow up question. Perhaps I'm mistaken but a principle of subtyping is that the supertype should not know that it's been subtyped. This "mechanism" lets a class know if it's been subclassed or not. Consider this code example:
class A {
private boolean isSubclassed = true;
public A() {
f(); //A.f() unsets the isSubclassed flag, B.f() does not.
if(this.isSubclassed) {
System.out.println("I'm subclassed.");
} else {
System.out.println("I'm not subclassed.");
}
}
public void f() {
this.isSubclassed = false;
}
}
class B extends A {
public B() {
super();
}
#Override
public void f() {}
}
public class Init {
public static void main(String[] args) {
new B(); //Subclass.
new A();
}
}
The output of this program is:
I'm subclassed.
I'm not subclassed.
Here A knows it's been subclassed. It's unkown by whom but that doesn't matter. How is this explained? Am I misinformed?
The NullPointerException occurs because when you construct an instance of B, the parent constructor (in A) is invoked. This constructor calls the f() method but since the actual type of the object is B, the overridden f() method in B is invoked.
#Override
public void f() {
//Anything that access o.
o.hashCode(); //Throws NullPointerException as o has not been initialised yet
super.f();
}
The lesson here is never to call a method in a constructor which can be overridden by a subclass.
This is why you shouldn't call non-private methods from constructors. There is no workaround, except making the method private.
This is the reason that override hide the own method. At the call of f() at super class constructor, it hide super class method call. Actually it is call to subclass overided method.
class A{
public A() {
f(); // It call the subclass overided method.
}
// This method is hide due to override.
public void f() {
}
}
class B extends A {
// This method is called before constructor where Object o is Null, hence you
// got NullPointerExcetion.
#Override
public void f() {
// Anything that access o.
o.hashCode(); // Throws NullPointerException.
super.f();
}
}
class A {
public A() {
System.out.println(1);
f();
// where super(),this will be called by subclass ,but subclass's o is null
}
public void f() {
System.out.println(4);
}
}

Explicitly calling a default method in Java

Java 8 introduces default methods to provide the ability to extend interfaces without the need to modify existing implementations.
I wonder if it's possible to explicitly invoke the default implementation of a method when that method has been overridden or is not available because of conflicting default implementations in different interfaces.
interface A {
default void foo() {
System.out.println("A.foo");
}
}
class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
public void afoo() {
// how to invoke A.foo() here?
}
}
Considering the code above, how would you call A.foo() from a method of class B?
As per this article you access default method in interface A using
A.super.foo();
This could be used as follows (assuming interfaces A and C both have default methods foo())
public class ChildClass implements A, C {
#Override
public void foo() {
//you could completely override the default implementations
doSomethingElse();
//or manage conflicts between the same method foo() in both A and C
A.super.foo();
}
public void bah() {
A.super.foo(); //original foo() from A accessed
C.super.foo(); //original foo() from C accessed
}
}
A and C can both have .foo() methods and the specific default implementation can be chosen or you can use one (or both) as part of your new foo() method. You can also use the same syntax to access the default versions in other methods in your implementing class.
Formal description of the method invocation syntax can be found in the chapter 15 of the JLS.
This answer is written mainly for users who are coming from question 45047550 which is closed.
Java 8 interfaces introduce some aspects of multiple inheritance. Default methods have an implemented function body. To call a method from the super class you can use the keyword super, but if you want to make this with a super interface it's required to name it explicitly.
class ParentClass {
public void hello() {
System.out.println("Hello ParentClass!");
}
}
interface InterfaceFoo {
public default void hello() {
System.out.println("Hello InterfaceFoo!");
}
}
interface InterfaceBar {
public default void hello() {
System.out.println("Hello InterfaceBar!");
}
}
public class Example extends ParentClass implements InterfaceFoo, InterfaceBar {
public void hello() {
super.hello(); // (note: ParentClass.super could not be used)
InterfaceFoo.super.hello();
InterfaceBar.super.hello();
}
public static void main(String[] args) {
new Example().hello();
}
}
Output:
Hello ParentClass!
Hello InterfaceFoo!
Hello InterfaceBar!
The code below should work.
public class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
void aFoo() {
A.super.foo();
}
public static void main(String[] args) {
B b = new B();
b.foo();
b.aFoo();
}
}
interface A {
default void foo() {
System.out.println("A.foo");
}
}
Output:
B.foo
A.foo
You don't need to override the default method of an interface. Just call it like the following:
public class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
public void afoo() {
A.super.foo();
}
public static void main(String[] args) {
B b=new B();
b.afoo();
}
}
Output:
A.foo
It depends on your choice whether you want to override the default method of an interface or not. Because default are similar to instance method of a class which can be directly called upon the implementing class object. (In short default method of an interface is inherited by implementing class)
Consider the following example:
interface I{
default void print(){
System.out.println("Interface");
}
}
abstract class Abs{
public void print(){
System.out.println("Abstract");
}
}
public class Test extends Abs implements I{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
Test t = new Test();
t.print();// calls Abstract's print method and How to call interface's defaut method?
}
}

Java Dispatching-Runtime type

I am confused with method dispatching in java. Why does the first method "a.m1(b)" call to the class A?
The calling variable is a. And its runtime type is B, isn't it?
class A {
public void m1(A a){
System.out.println("A-m1");
}
public void m1(){
System.out.println("A-m1");
}
}
class B extends A {
public void m1( B b){
System.out.println("B-m1");
}
public void m1(){
System.out.println("B-m1");
}
}
public class HelloWorld {
public static void main(String[] args) {
B b = new B();
A a = new B();
a.m1(b);//prints A-m1
a.m1();//prints B-m1
}
}
Overload resolution is done based on compile-time types. A variable of type A only exposes the methods m1() and m1(A). Because you pass in a parameter, m1(A) is invoked; or rather, the appropriate override thereof. Except that m1(B) is not an override of m1(A). (Off the top of my head, I don't know if overrides can widen argument signatures, but they certainly can't narrow them.)

Overriding a Java Method

I'm new to Java, and I've read over some tutorials on overriding methods, but an example I'm looking at isn't working the way I expect. For example, I have the code:
public class A{
public void show(){
System.out.println("A");
}
public void run(){
show();
}
public static void main( String[] arg ) {
new A().run();
}
}
public class B extends A{
#Override
public void show(){
System.out.println("B");
}
}
When I instantiate and call B.run(), I would expect to see "B" outputted. However, I see "A" instead. What am I doing wrong?
Edit: Yes, the classes are in two separate files. They're shown together for brevity.
Edit: I'm not sure how B is being instantiated, as it's being done by a third-party program using a classloader.
Edit: More info on the third-party program. It starts by calling A.main(), which I didn't initially show (sorry). I'm assuming I need to make "new A().run();" more generic to use the name of the current class. Is that possible?
That code will output B if you:
(new B()).run();
Whatever the problem is, it's not in the code you've quoted.
Updated (after your edit)
If the third-party program is calling A.main(), there's nothing (reasonable) you can do in B that will inject itself into A. As long as A.main is doing new A().run(), it's going to have an instance of A, not an instance of B. There's no "current class name" to use, or if there is (depends on your point of view), it's A, not B.
You'll have to get the third-party program to call B in some way, rather than A, or just modify A directly (e.g., getting rid of B entirely). You do not want to modify A to make it use B; that tightly binds it to a descendant and makes the separation between them largely pointless.
Hope that helps.
I tried, putting your two classes in two files, and it worked nicely, outputting "B". I called :
B b = new B();
b.run();
UPDATED : Also works as (because it is the same runtime instance):
A a = new B();
a.run();
Works for me.
Here's my code for A and B:
package so;
public class A{
public void show(){
System.out.println("A");
}
public void run(){
show();
}
}
class B extends A{
#Override
public void show(){
System.out.println("B");
}
}
Here's my entry point:
package so;
public class EntryPoint {
public static void main(String[] args) {
B b = new B();
b.run();
}
}
It prints out 'B'.
It depends of instantiating. Try this:
A v1 = new A();
A v2 = new B();
B v3 = new A();
B v4 = new B();
v1.run()
v2.run()
v3.run()
v4.run()
I tried your example and my output was B.
How are you instantiating? Here's the exact code I ran.
public class Test {
public static class A {
public void show() {
System.out.println("A");
}
public void run() {
show();
}
}
public static class B extends A {
#Override
public void show() {
System.out.println("B");
}
}
public static void main(String args[]) {
A a = new B();
a.run();
}
}
If your external program instantiates A, you will have A, not B.
But you can try something like this, using some reflection, and pass "com.mypackage.A" or "com.mypackage.B" as arguments to your program.
With this code (exception catch missing), you will be able to print "A" or "B" depending on the string parameter that you pass.
public static void main( String[] arg ) {
String className = arg[0];
Class myClass = Class.forName(className);
Constructor cons = myClass.getConstructor(new Class[0]);
A myObject = (A) cons.newInstance(new Object[0]);
myObject.show();
}

Categories

Resources