public class Publisher { String name; String url; } // class Publisher public class Book { int a; Publisher p; } // class Book
Book has-a Publisher. Inheritance expresses the is-a relationship. Inheritance allows us to abstract some parts of the data to hide them from the programmer, while allowing re-use of other parts. The key power of inheritance is to isolate and re-use code and data.
For example, a product consists of one or more programs. Programs consist of one or more code units. Products have data like release dates, cost, part numbers, manuals, owner, completion date, etc. They have methods like is_development_complete() and get_part_number();
Programs have owners, language, compiler, completion date. They have methods like is_development_complete() and compile_program();
Code units have owners, language, compilers, unit test date, completion date, NCSL. They have methods like is_development_complete() and compile_program() and count_ncsl().
You can see that there are commonalities and differences.
Here is a simpler example. The regular code file for this is here. First we look at the code for the parent class, foo. Then the code for the child class, bar. Finally, a driver program to show off the inheritance, main.
Parent and child classes are independent in the sense that you can create instances of the child class without creating instances of the parent. The parent class can exist solely to hold common methods and data.
All the data and methods from the parent are present in the child. But private things stay private. The child has no special rights to access private data or methods. We can use the public interface to access the private data, however. Protected members are private to outside classes but public to subclasses. So we marked b in foo as protected so bar was able to refer to it directly, as if they were really part of the class. All classes in the same package can see the protected variables and methods as if they were public.
bar(1,2,3);before the 3 arg constructor is executed, the no-arg constructor for foo is run. Then the calls to setA() and setB() override the initialization. This is a little redundant. so we can define the subclass constructor to use the parameterized superclass constructor. We could change the constructor
bar(int x,int y, int z) { setA(x); b=y; c = z;}to be
bar(int x,int y, int z) { super(x,y); c = z;}
Inheritance is transitive. This means, that is class B inherits (extends) from class A and class C inherits from class B, then class C also inherits from A.
Java supports single inheritance. This means that a class can inherit from only one other class. You can use interfaces to introduce some flexibility to this since a class can implement any number of interfaces. Multiple inheritance is powerful but becomes horribly confusing when you try to figure out where a method comes from when multiple parents have it.
Design is crucial to making full use of the power of inheritance. You want to carefully examine the data and methods involved in the classes you are building and create a hierarchy that reflects the structure of the problem. Then you want to push the common methods as far up the tree as you can. The classes farther down the tree can override the methods if they need to. But the more code that you only have in one place, the easier it is to maintain the system.
Java has a complete object hierarchy. Every class is part of an object hierarchy, whether it uses extends or not. If it doesn't, it is a child of the Object class. This allows you to create variables that can hold references to any kind of object. The Vector class uses this. The base type of a Vector is Object so a Vector can hold anything. In fact, each slot in a Vector could be a different type of object. An Object instance has very few methods. If you use an Object reference to refer to an instance, you will have to cast it to t he correct type before trying to access the methods.