Skip to main content
GameDev.net gamedev.net
🔒 Locked

[java] Wierdness

Started by polly Jan 28, 2005 at 9:24 AM 8 replies 1.6k views
Original Post
polly
polly
Given these two example classes, what would you say the print out would be if you run "java Child" on the command line after compiling the 2 classes? I've just found out about this wierdness and wondered if anyone else knew about it? I'll explain once the correct answer is posted..


public abstract class DaddyClass extends Object
{
	public DaddyClass(String arg)
	{
		foo(arg);
	}

	public abstract void foo(String arg);
}

public class Child extends DaddyClass
{
	private String m_stuff = null;

	public Child(String subject)
	{
		super(subject);
	}

	public void foo(String arg)
	{
		m_stuff = arg.toLowerCase();
	}
        
        public String getStuff()
        {
                return m_stuff;
        }
        
        public static void main(String[] args)
        {
                Child child = new Child("Who's your daddy?");
                System.out.println(child.getStuff());       
        }
}


Monkeyget
Monkeyget
Everybody know it will return Who's your... err null?!?
Looks like a superclass can't initialize a field in the subclass...The weirdest is that it the call to foo succeed and does initialise m_stuff but once the call to super() is over it's just discarded.
If i had to give a reason i'd say that an object is composed of it's own class, it's superclass up to Object. The variables of the Object part can only be initialized by the Object's constructor, the fields of DaddyClass can only be initialized by the DaddyClass's constructor and the fields of Child are initialized by the constructor of Child.
polly
polly
Well done Monkeyget! You got it right.

The super constructor is called, which then resolves the call to foo() and initialises the private variable to the string argument..... and then (and I stepped through this in Eclipse debug) the private variables in the child class get initialised - and in this case, it gets set back to null.

Strangely, if you take out the assignment of the private variable to null and leave it undefined, the code works as expected.

Quote:

I'd just tell the truth: Java has poor OOP capabilities, and never was a true OOP language. I've spent years telling people this but most people can't understand what's going on with java's mediocre polymorphism and fn-despatch and don't have the confidence to repeat what they've seen.

Shrug.


I know. Most of us who use Java don't have a choice about using it though. Company decision.
The Rug
The Rug
This:

private String m_stuff = null;	public Child(String subject)	{		super(subject);	}


Should not be allowed. Java should force you to initialise your variables inside the constructor. Instead it just plugs in the initialisation bit after the super() call, so in the end (according to my decompiler at least) you get this:

private String m_stuff;	public Child(String subject)	{		super(subject);                m_stuff = null;	}


So the moral of the story is avoid initialising variables outside constructors, it gives the impression they will be initialised before the body of the constructor when that is infact false >_<


(Edited in correction)

[Edited by - The Rug on January 29, 2005 10:25:05 AM]
the rug - funpowered.com
Thygrrr
Thygrrr
Quote:
Original post by The Rug
So the moral of the story is avoid initialising variables outside constructors, it gives the impression they will be initialised before the body of the constructor when that is infact false >_<


Owned. Rating++, the best Java "Heads-Up!" I've heard in a long time!
Monkeyget
Monkeyget
To make things clear to me (and you):

public class Child extends DaddyClass{	private String m_stuff = "2";//done second	public Child()	{		super();//done first (calls foo)		this.m_stuff = "3";//done last	}	public void foo()	{		m_stuff = "1";	}}

Here is the order of what is done when you call a constructor (the Child() constructor here) :
The first thing done is the call to super() (which will call foo in this example).
The second thing done is the initialization next to the declaration of the variables (private String m_stuff = "2" here) ;.
The third thing done is the code following the call to super() (this.m_stuff = "3" here)
polly
polly
Quote:
Original post by The Rug
This:

private String m_stuff = null;	public Child(String subject)	{		super(subject);	}


Should not be allowed. Java should force you to initialise your variables inside the constructor. Instead it just plugs in the initialisation bit at the end of your constructor, so in the end (according to my decompiler at least) you get this:

private String m_stuff;	public Child(String subject)	{		super(subject);                m_stuff = null;	}


So the moral of the story is avoid initialising variables outside constructors, it gives the impression they will be initialised before the body of the constructor when that is infact false >_<


Thanks for that. I've only just started using JAD on a regular basis to decompile class files to see what the hell is going on. It's very useful.

Makes me want to go back to the good old days of C...
The Rug
The Rug
Hm, slight correction, it could just be that the initialisations are indeed plugged in at the start of the constructor, but super() is done even before that (probably best to write a quick program then decompile it to make sure). Still quite confusing and still best to stay away from initialisation outside of the constructor.

Thanks for the rates++ :o)

Edit: Yeah, this:
	private String m_stuff = null;	public Child(String subject)	{		super(subject); 		System.out.println("Blah");	}


Becomes:

    public Child(String s)    {        super(s);        m_stuff = null;        System.out.println("Blah");    }


Sorry for the confusion.
the rug - funpowered.com
Thygrrr
Thygrrr
Ah yes... and that makes sense, too.

super() must happen first, for a few reasons that I can actually think of.

For example, if the father class initializes the field to something else, and would crash if a null ref was encountered. That'd require old code to be changed to use new code, which violates the principle of inheritance (old code using new code without any changes).

*thinks* But still, this way of initializing stuff is not good. I'll aways use the constructor in the future.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.