Java inheritance

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
User avatar
Bullet Pulse
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 89
Joined: Sun Feb 21, 2010 6:25 pm

Java inheritance

Post by Bullet Pulse »

I know this is basic stuff, but because I want some clarification on this, I'm asking you guys. :)

I have three classes:

Code: Select all

public class BalletDancer extends Dancer
{
    public void glide() { }
}

Code: Select all

public class Dancer
{
    public void leap() { }
}

Code: Select all

public class Test
{
    public static void main(String[]args)
    {
        Dancer d = new BalletDancer();  //"Slices" the BalletDancer part of the object.
        BalletDancer b = new BalletDancer();
        b.leap();
        b.glide();
        //d.glide();  would cause an error
        d.leap();
    }
}
d.glide() can't be called because the assignment of Dancer d = new BalletDancer() removes the BalletDancer members from d right?

To avoid this, you would either:
(a) Add a glide function to the Dancer class, or
(b) Cast d to a BalletDancer object.

Am I correct?
Or are there more ways?
Image
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: Java inheritance

Post by avansc »

Not sure what you are trying to do, but this is how i learnt it.
(see what happens when you make glide static)

Code: Select all


public class animal
{
	public animal(int _hp)
	{
		System.out.println("Animal Created.\n");
		this.hp = _hp;
	}
	
	public int get_HP()
	{
		return this.hp;
	}
	
	public void set_HP(int _hp)
	{
		this.hp = _hp;
	}
	
	private int hp;
}

Code: Select all

public class bird extends animal {

	public bird(int hp) {
		super(hp);
		System.out.println("Creating Bird\n");
		// TODO Auto-generated constructor stub
	}
	
	public static void fly()
	{
		System.out.println("Flying");
	}

}

Code: Select all

public class test
{
	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		// TODO Auto-generated method stub
		
		animal ani = new animal(10);
		animal dove = new bird(5);
		
		bird.fly();
		
		System.out.println("start");
	}

}
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Java inheritance

Post by Falco Girgis »

Bulletpulse, you're correct. The proper solution is to cast the reference back down the inheritance tree to the derived class.

Even though it is instantiated as a derived class, you are referring to it through a reference to the parent class--and that method is not implemented at the parent level.
User avatar
Arce
Jealous Self-Righteous Prick
Jealous Self-Righteous Prick
Posts: 2153
Joined: Mon Jul 10, 2006 9:29 pm

Re: Java inheritance

Post by Arce »

It is also worth noting that in java, all methods not declared with the keyword "final" are virtual...
<qpHalcy0n> decided to paint the office, now i'm high and my hands hurt
User avatar
christo
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 59
Joined: Sat Apr 24, 2010 7:28 am
Favorite Gaming Platforms: iPhone, PS3
Programming Language of Choice: c, java, groovy
Contact:

Re: Java inheritance

Post by christo »

I don't think casting is good form. It means you have a design problem and you are fumbling your type information. Of course it may get you over the line.

Java has static type checking which means that if you declare your dancer to be of type Dancer (which you do) then you can only call methods declared on the Dancer type. The methods are not removed they are there but the compiler will not let you call them because it deliberately enforces the declared type. You know they are there because you can call them if you cast. You can also see that they are there using reflection.

So it's the declared type which is important to the compiler and not the actual implementation.

So why is casting no good?

If you want to call glide() it implies you know you have a BalletDancer. If you find yourself getting only a Dancer somewhere in your code even though you know you have a BalletDancer, you have lost type information somewhere along the line. The parts of your program that can make do with a Dancer should accept a Dancer and the declared type they deal with can be that. But the parts of your program that need to call glide() should declare their need of a BalletDancer. Try not to lose type information in middle men (going from BalletDancer -> Dancer -> BalletDancer (via a cast). Because one day your cast will fail because you are not getting help from the compiler to ensure that you have an implementation of glide(), you're only finding out at runtime if you have a bug of that kind. And that bug will only be discovered if that cast happens to be executed. This might only be on completion of the final quest in your game!!

The introduction of Generics in Java 5 was supposed to help you keep this type information. The case of collections is the most well known because if you have a plain old List it loses all the type info and you can only get Objects out whereas if you have a List<BalletDancer> you don't need to cast to BalletDancer. Sometimes you want to use a List<? extends Dancer> and then concretely declare a type to be a List<BalletDancer> which is a specialisation of a List<? extends Dancer>.

Generics are tricky but they can usually help you keep the type information you create when you make these classes. Let the compiler save you from your future self and avoid downcasting.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Java inheritance

Post by Falco Girgis »

^

I agree. Even in C++ I think that having to cast downwards is generally a result of poor design. (though without some of the OO mechanisms that Java and .NET offer, sometimes it is unavoidable...)
User avatar
thejahooli
Chaos Rift Junior
Chaos Rift Junior
Posts: 265
Joined: Fri Feb 20, 2009 7:45 pm
Location: London, England

Re: Java inheritance

Post by thejahooli »

In C# I think you can use the 'is' keyword so you can know which type it is.

Code: Select all

if(dancerObject is BalletDancer)
{
// Code Here
}
Maybe there's something like this in Java.
I'll make your software hardware.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Java inheritance

Post by Falco Girgis »

thejahooli wrote:In C# I think you can use the 'is' keyword so you can know which type it is.

Code: Select all

if(dancerObject is BalletDancer)
{
// Code Here
}
Maybe there's something like this in Java.
There is also the "as" keyword which is a safe typecast. If the parent reference cannot be cast to a child, the reference is set equal to null.

It is a "safer" approach in C#, but rethinking your OO design is probably the best approach.
User avatar
Bullet Pulse
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 89
Joined: Sun Feb 21, 2010 6:25 pm

Re: Java inheritance

Post by Bullet Pulse »

There is also the instanceOf keyword ;)
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Java inheritance

Post by Falco Girgis »

Bullet Pulse wrote:There is also the instanceOf keyword ;)
I'm speaking C# and you're speaking Java. instanceOf is "is" in C#.
User avatar
christo
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 59
Joined: Sat Apr 24, 2010 7:28 am
Favorite Gaming Platforms: iPhone, PS3
Programming Language of Choice: c, java, groovy
Contact:

Re: Java inheritance

Post by christo »

instanceof is like casting, it should be avoided and usually can be unless there is a bigger design problem you can't solve now (think legacy code).

First, just to be clear, when I say "type" I mean "class or interface or primitive" in java.

The basic reasoning here is that type information can be checked by the compiler and this is a whole category of bugs you can avoid because the compiler can stop you from creating them. instanceof and casting leave you open to these bugs because they are runtime type checks and conversions. They only blow up if you go down that code path.

Inheritance is cool when you learn it but you should think of it as only one tool in the language for creating a design that matches the domain you're trying to create with the program.

Java (and c# which is essentially the same language with minor differences) allows you to use interface inheritence in a more obvious way that c++. Interfaces (in c++ this would be classes consisting only of virtual functions) permit multiple inheritance but it's inheritance of the "interface" or contract and not the implementation. For key classes and declared dependencies between classes, interfaces should be preferred over concrete types (interfaces use "interface" where concrete classes use "class" in the source code). The reason for this is that the implementation can be changed at runtime or for testing purposes etc. and the loose coupling that results is much easier to modify if you need to make a new design.

For example perhaps you need to put in a FastBalletDancer which has crazy optimised code in it, so you can do this later if you made an interface for BalletDancer and originally implemented this interface with a class called BalletDancerImpl or SimpleBalletDancer or something.

Tradiional OO teaching has seemingly equated Object-Oriented => Inheritance whereas there are plenty of languages both before and after c++ which have no implementation inheritance (e.g. Smalltalk and Javascript use prototype inheritance which is totally different). Implementation inheritance can be hard to manage and hard to comprehend and easy to get into a mess.

Of course in a small program (i.e. < 10kLOC) many of these things are fine because you generally have all the code and you remember writing it. If you work on big systems or have the luxury problem of shipping software that becomes wildly successful and therefore grows into a big system, you find that inheritance hierarchies are usually unscalable (they quickly becomes too big to manage).

I know this is more that what you were asking about but I really hate seeing things like ifs or switch blocks of instanceof in code because it is basically failing to use the type system to model the decision to switch to an implementation and instead falling back on an imperative (if this then or if that then or else the other), explicit and unextensible decision path that should require no executable code (had it been written correctly).

It's bloat. Flab. Lard.

If you are using instanceof consider putting the result of the decision code into the class you're casting to. Then you can remove the switch and instanceof block. And just call the method that does the right thing for that type. Less code is the primary metric.

The only line of code that can't have a bug on it is the one you never write.
User avatar
Skullman
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 10
Joined: Sun Oct 18, 2009 8:46 am
Current Project: Random
Favorite Gaming Platforms: Mega Drive, SNES, Dreamcast, Gameboy, GBA
Programming Language of Choice: Any and all
Location: England
Contact:

Re: Java inheritance

Post by Skullman »

Hey christo more posts like these when these subjects crop up in Java or C# please. Very informative and interesting. Thanks. 8-)
Post Reply