Assume for some reason that I don't want to implicitly call super() which is done by default.
class Animal {
public Animal() {
System.out.println("Constructing an animal.");
}
}
class Dog extends Animal {
public Dog() {
System.out.println("Constructing a dog.");
}
public static void main(String[] a) {
new Dog();
}
}
Is there any way to "disable" the default behavior that super() is invoked when making a new Dog? Or would that be principally and conceptually wrong?
I mean there could be cases where you would want only the constructor of the subclass and not invoke the construction of the baseclass, and still inherit the baseclass.
If I understand you correctly you want to override the behavior of the Animal constructor or just not call it. If so you're conceptually wrong: you always need to call a super constructor, the only thing you could to with the calls is provide a non-default constructor, i.e. one with arguments and provide appropriate arguments to influence the behavior of that constructor (e.g. by either selecting a different constructor, passing some sort of strategy/function object etc.)
Another way might be to provide some init() method that the default constructor is calling and which you can override but there are a few problems with it, e.g.:
If the overridden method tries to access anything only visible to the subclass (e.g. additional fields) you could run into problems because those haven't been initialized yet.
That method can't initialize any final field.
s there any way to "disable" the default behavior that super() is
invoked when making a new Dog? Or would that be principally and
conceptually wrong?
It is conceptually wrong since any class which invokes its constructor has to invoke the constructor of its parent : super() or super() with any arguments if the super constructor has not it.
If the constructor of the super class does some specific processing and that is not desirable for all concrete classes, you should change rather the implementation of the super constructor and move the specific behavior in a method of the super class or in a method of concrete classes.
You can't bypass the construction of a parent class, and perhaps you shouldn't attempt to circumvent this rule.
But, if you must do this then you could build a no-op constructor in Animal (that you mark as protected so only derived classes can see it):
protected Animal(Noop foo)
{
/*do nothing explicit here*/
}
And call that one explicitly from your derived class using
super(new Noop())
Here I've invented a new class Noop (meaning "no operation") to enable the compiler to distinguish the constructor parameters.
Agreeing with all the answers here on invoking the constructor which cannot be avoided, providing one more workaround which ensures a block of code in constructor that gets executed only when it is directly invoked and not when any sub class constructors are invoked.
public class Animal{
public Animal() {
if(this.getClass() == Animal.class){
System.out.println("Animal");
}
}
}
public class Dog extends Animal{
public Dog() {
System.out.println("Dog");
}
}
That's one of the reasons inheritance is a pain and usually misused:
public interface Animal {
// define behaviour
}
public class Dog implements Animal {
// implement behaviour
}
Use interfaces and aggregation / decoration so you can avoid the struggle of bad design decisions in inheritance chains.
Related
I'm dealing with a class which extends JFrame.
It's not my code and it makes a call to super before it begins constructing the GUI. I'm wondering why this is done since I've always just accessed the methods of the superclass without having to call super();
There is an implicit call to super() with no arguments for all classes that have a parent - which is every user defined class in Java - so calling it explicitly is usually not required. However, you may use the call to super() with arguments if the parent's constructor takes parameters, and you wish to specify them. Moreover, if the parent's constructor takes parameters, and it has no default parameter-less constructor, you will need to call super() with argument(s).
An example, where the explicit call to super() gives you some extra control over the title of the frame:
class MyFrame extends JFrame
{
public MyFrame() {
super("My Window Title");
...
}
}
A call to your parent class's empty constructor super() is done automatically when you don't do it yourself. That's the reason you've never had to do it in your code. It was done for you.
When your superclass doesn't have a no-arg constructor, the compiler will require you to call super with the appropriate arguments. The compiler will make sure that you instantiate the class correctly. So this is not something you have to worry about too much.
Whether you call super() in your constructor or not, it doesn't affect your ability to call the methods of your parent class.
As a side note, some say that it's generally best to make that call manually for reasons of clarity.
None of the above answers answer the 'why'.
Found a good explanation here:
A subclass can have its own private data members, so a subclass can
also have its own constructors.
The constructors of the subclass can initialize only the instance
variables of the subclass. Thus, when a subclass object is
instantiated the subclass object must also automatically execute one
of the constructors of the superclass.
You might also want to read everything about the super keyword here or watch everything about the super keyword here.
We can access super class elements by using super keyword
Consider we have two classes, Parent class and Child class, with different implementations of method foo. Now in child class if we want to call the method foo of parent class, we can do so by super.foo(); we can also access parent elements by super keyword.
class parent {
String str="I am parent";
//method of parent Class
public void foo() {
System.out.println("Hello World " + str);
}
}
class child extends parent {
String str="I am child";
// different foo implementation in child Class
public void foo() {
System.out.println("Hello World "+str);
}
// calling the foo method of parent class
public void parentClassFoo(){
super.foo();
}
// changing the value of str in parent class and calling the foo method of parent class
public void parentClassFooStr(){
super.str="parent string changed";
super.foo();
}
}
public class Main{
public static void main(String args[]) {
child obj = new child();
obj.foo();
obj.parentClassFoo();
obj.parentClassFooStr();
}
}
It simply calls the default constructor of the superclass.
We use super keyword to call the members of the Superclass.
As a subclass inherits all the members (fields, methods, nested classes) from its parent and since Constructors are NOT members (They don't belong to objects. They are responsible for creating objects), they are NOT inherited by subclasses.
So we have to explicitly give the call for parent constructor so that the chain of constructor remains connected if we need to create an object for the superclass. At the time of object creation, only one constructor can be called. Through super, we can call the other constructor from within the current constructor when needed.
If you are thinking why it's there for a class that is not extending any other class, then just remember every class follows object class by default. So it's a good practice to keep super in your constructor.
Note: Even if you don't have super() in your first statement, the compiler will add it for you!
We can Access SuperClass members using super keyword
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super. You can also use super to refer to a hidden field (although hiding fields is discouraged). Consider this class, Superclass:
public class Superclass {
public void printMethod() {
System.out.println("Printed in Superclass.");
}
}
// Here is a subclass, called Subclass, that overrides printMethod():
public class Subclass extends Superclass {
// overrides printMethod in Superclass
public void printMethod() {
super.printMethod();
System.out.println("Printed in Subclass");
}
public static void main(String[] args) {
Subclass s = new Subclass();
s.printMethod();
}
}
Within Subclass, the simple name printMethod() refers to the one declared in Subclass, which overrides the one in Superclass. So, to refer to printMethod() inherited from Superclass, Subclass must use a qualified name, using super as shown. Compiling and executing Subclass prints the following:
Printed in Superclass.
Printed in Subclass
as constructor is not a part of class,
so while calling it cannot be implemented,
by using SUPER() we can call the members and memberfunctions in constructor.
Consider the following case,
interface IFace1 {
default void printHello() {
System.out.println("IFace1");
}
}
interface IFace2 {
void printHello();
}
public class Test implements IFace1, IFace2 {
public static void main(String[] args) {
Test test = new Test();
test.printHello();
IFace1 iface1 = new Test();
iface1.printHello();
IFace2 iface2 = new Test();
iface2.printHello();
}
#Override
public void printHello() {
System.out.println("Test");
}
}
In above example I am getting following output which is quite expected.
Test
Test
Test
I have been reading about Java-8 default methods and specifically about Extending Interfaces That Contain Default Methods
2nd bullet : Redeclare the default method, which makes it abstract.
In above example where I have two interfaces which have default method with same name and when I implemented both I was only able to reach to the implementation of printHello of Test which refers to IFace2.
I have few questions about this,
How can I reach to the printHello method of IFace1 and if I can't than why ?
Doesn't this behavior keep me away from the intended nature of IFace1 which is may be now shadowed by other method ?
Quote says, you can make the default method abstract in it's child interface. For example,
interface IFace2 extends IFace1 {
void printHello();
}
Here when I implement IFace2 I won't be actually able to reach default method of IFace1 that is exactly what is happening in my case.
It seems that you are a bit confused by the presence of a default method. So let’s forget for a moment that IFace1.printHello() is a default method. So then, there is a clear situation: Test implements two interfaces, IFace1 and IFace2, which happen to have a method with the same name and signature.
Test implements that method and therefore implements the method for both interfaces. The new feature of default methods does not change anything about this logic. Moreover, the language designers took care that adding a default method does not affect the behavior of existing code, so if your class implements the method, the presence of default methods becomes irrelevant.
However, if you write code that is aware of the presence of default methods, you may invoke it, if it is declared or inherited by a direct super interface, i.e. in your code you may use IFace1.super.printHello() to invoke the default method of IFace1.
The rules are not much different to the rules of super classes. If you change the interfaces so that interface IFace2 extends IFace1 and still declares printHello() as an abstract method, then this abstract method does override the default method and you can’t invoke IFace1.super.printHello() from within Test anymore.
As said, these rules are not much different to ordinary instance methods. If Test declares a method printHello(), that’s the only method that you can invoke by a reference to a Test instance, regardless whether its declared type is Test, IFace1 or IFace2. Only implementation methods of Test itself may do super invocations.
The main difference comes into play when the possible multiple inheritance of interfaces is involved. If your class Test does not implement the method printHello(), it depends on the inheritance relationship of the two interfaces, what will happen
If IFace2 extends IFace1, it’s abstract method redeclares the default method, hence a compiler error occurs, as Test must implement the abstract method
If IFace2 does not extend IFace1, there are ambiguously two inheritable methods with the same name and signature, therefore Test will not inherit the default method, and a compiler error occurs, as Test must implement the abstract method
If IFace1 extends IFace2, Test will inherit the default method. It will also inherit it if Test does not implement IFace2, but this should come at a surprise…
How can I reach to the printHello method of IFace1 and if I can't than why ?
You can only do so within an instance method of a type that implements IFace1 with
IFace1.super.printHello(); // only if IFace1 declares a default implementation of the method
In other words, you can't do it through a simple reference of type IFace1 or Test (or whatever). That would break encapsulation.
Doesn't this behavior keep me away from the intended nature of IFace1
which is may be now shadowed by other method ?
There's no shadowing going on here. You've overriden the method, so the overriden one gets invoked.
Concerning your 3rd question, you haven't extended any interfaces, so I don't see the relevance.
If you really did have
interface IFace2 extends IFace1 {
void printHello();
}
with
public class Test implements IFace2 {
then you would not be able to access IFace1's default implementation of the method. You can never skip super types to access implementations higher up in the inheritance hierarchy.
So this code has an error because the base class has parameters right? Because the default constructor of each subclass calls the default constructor of the base class? and we don't have a default constructor for the base class which causes the error?
Did I misunderstand it, also what is the best way around this while implementing the principle of code-reuse because I'm trying to practice programming in OOP
class A {
int item;
A(int item) {
this.item = item;
}
}
class B extends A {
int subitem;
B(int item) {
super(item);
subitem = item * 2;
}
}
class C extends A {
}
Firstly, on the title of this question:
Subclasses inherting base class constructor while maintaining principle of code-reuse
Constructors are never inherited. It just doesn't happen. What you've been demonstrating is not inheritance - it's just the requirement that any constructor (other than the one in java.lang.Object) has to either chain to another constructor in the same class, or chain to a constructor in the superclass.
So this code has an error because the base class has parameters right?
Well, to be precisely, it's because the base class has no parameterless constructor.
Because the default constructor of each subclass calls the default constructor of the base class?
A default constructor is only provided if you don't specify any constructors explicitly. The default constructor always calls a parameterless constructor in the base class, implicitly.
and we don't have a default constructor for the base class which causes the error?
We don't have a parameterless constructor for the base class. Basically it's equivalent to writing:
class C extends A {
C() {
super();
}
}
If you understand why that doesn't compile, you understand why the version without any explicitly-declared constructors doesn't compile, as they're equivalent.
Did I misunderstand it, also what is the best way around this
Around what? You can't create an instance of A without providing an item. It would be bad if it did compile - what would the item be? Every instance of C can also be considered to be an A, which requires an item...
You could write a parameterless constructor which provides some sort of default to the superclass constructor:
public C() {
super("default item");
}
if that's what you want. But beyond that, we can't really suggest alternatives without knowing what you're trying to achieve.
Note that inheritance is far from the only way of achieving code reuse - and in fact I personally prefer reuse via composition instead of inheritance in general. Inheritance is powerful, but overused IMO.
your class C extends A by which it has to satisfy the contract of calling its one-arg constructor explicitly in your constructor, or you could simply have a no-args default constructor defined in your class A like:
class A {
int item;
A(int item) {
this.item = item;
}
A(){
//default stuff
}
}
In Java, when I override a method the compiler flags off any attempt to narrow down the visibility as an error. For ex: I can't override a public method as protected, while I can override a protected method as public.
I am interested in knowing the design decision/thinking behind this rule.
A subclass should always satisfy the contract of the superclass. See Liskov Substitution principle.
The visibility of methods is part of this contract. So anything publicly visible in the superclass should be public in the subclass as well.
Consider a class B which inherits from A. A.m() is public. Now consider this code:
A obj = new B();
obj.m();
Should this call be allowed? Yes, it should, because obj is an object of type A! It is also an object of type B, but that is not necessarily known to the one using the object.
Every object of type A must adhere to the contract (interface) for A. B extends A and must therefore also adhere to that contract.
While over ridding or implementing the access level, we should go for same access level or wider to that access level.
private < (default) < protected < public
Public is wider most level.
In Interface all members are default public. So, While implementing or over ridding we have to go for only public.
Assume parent class and child class with overriding method with public access modifier.
class Parent{
public void m(){
// method implementation
}
}
class Child extends Parent{
#Override
public void m(){
//child implementation
}
}
assume there are some classes which are utilising this functionality like this
Parent p = new Child();
p.m(); // this access is fine, because JVM calls Overriding method at run time
Now if we change the access of overriding method to anything less than public
class Child extends Parent{
#Override
void m(){
//Child implementation
}
}
Now some of the classes which were able to use the functionality of method m() may not be able access the function.This is not a desired behaviour.
Hence the rule is Overriding method should not decrease the scope of overridden method.
Is there any keyword or design pattern for doing this?
Please check the update
public abstract class Root
{
public abstract void foo();
}
public abstract class SubClass extends Root
{
public void foo()
{
// Do something
//---------------- Update -------------------//
// This method contains important code
// that is needed when I'm using a instance
// of SubClass and it is no instance of any
// other class extending SubClass
}
}
public class SubberClass extends SubClass
{
// Here is it not necessary to override foo()
// So is there a way to make this necessary?
// A way to obligate the developer make again the override
}
Thanks
If you are doing this, then you are probably abusing inheritance; inheritance, contrary to popular myth, is not intended for making custom hooks/handlers, but rather to enable alternative implementations.
If you want your user to provide some sort of function/hook/callback, then you should define an interface that provides just those methods that you need your user to define. Then you should require the user to pass in an instance of that interface to your object's constructor or passed into the function that needs it.
Aggregation, delegation, and composition are frequently better and safer design patterns than inheritance; forcing other users to inherit from your class, is incredibly risky, as it provides the user with many opportunities to violate the contract of your class or to invalidate the invariant of your base class.
If every class subclassing SubClass has to override foo() then why provide an implementation at all in SubClass? You can simply remove the method definition from SubClass and then all subclasses will be forced to provide an implementation.
If you really want to, you can re-declare foo as abstract.
public abstract class SubberClass extends SubClass
{
public abstract void foo();
}
Instead of overriding foo() in SubClass, create a new method fooImpl() and leave foo() abstract. This way, all classes must implement foo() but you can simply implement it by calling fooImpl() if that is already enough.
Yeah it is not necessary to override foo() in SubberClass.
You can't have it both ways. You can't provide a method with a default implementation AND require child classes override it. Instead of declaring the method as abstract in Root, you could define an interface (IFoo) with the method declared and then provide an abstract class that implements the interface. That would still require a concrete child class but would not require a method override.
Most of the time you see this type of pattern, an interface is used to define a set of methods and an abstract base class provides some default implementations for some but not all methods from the interface. This requires the concrete child class to provide code for the remaining methods and the option to override the default behaviors.
In any case, you can't provide a default behavior for a single method and require child classes to override that same method.