I'm extending from an abstract class named ChildClass, it has 4 constructors which should be implemented.
There is a set of general configuration common to all constructors.
I could abstract these tasks and call it in all constructors.
Is there anyway to call a specif method when an object is going to be initialized rather than calling it in all of the constructor signatures?
Since Java compiler must ensure a call to a constructor of the base class, you can place the common code in a constructor of your abstract base class:
abstract class BaseClass {
protected BaseClass(/*put arguments here*/) {
// Code that is common to all child classes
}
}
class ChildClassOne extends BaseClass {
public ChildClassOne(/*put arguments here*/) {
super(arg1, arg2, ...);
// More code here
}
}
As already stated in the comment, one way to call common initialization code would be the use of this(...), i.e. you'd call one constructor from another. The problem, however, is that this call would have to be the first statement of a constructor and thus might not provide what you want.
Alternatively you could call some initialization method (the most common name would be init()) in all constructors and in a place that is appropriate (e.g. at the end of the constructor). There is one problem though: if a subclass would override that method it could create undefined situations where the super constructor calls the method and the method uses non-yet-initialized fields of the subclass. To mitigate that the method should not be overridable, i.e. declare it final or make it private (I'd prefer to have it final though because that's more explicit).
Depending on your needs there's a 3rd option: use the initializer block:
class Super {
{
//this is the initializer block that is called before the corresponding constructors
//are called so it might or might not fit your needs
}
}
Here's an example combining all 3 options:
static class Super {
{
//called before any of the Super constructors
System.out.println( "Super initializer" );
}
private final void init() {
System.out.println( "Super init method" );
}
public Super() {
System.out.println( "Super common constructor" );
}
public Super(String name) {
this(); //needs to be the first statement if used
System.out.println( "Super name constructor" );
init(); //can be called anywhere
}
}
static class Sub extends Super {
{
//called before any of the Sub constructors
System.out.println( "Sub initializer" );
}
private final void init() {
System.out.println( "Sub init method" );
}
public Sub() {
System.out.println( "Sub common constructor" );
}
public Sub(String name) {
super( name ); //needs to be the first statement if used, calls the corrsponding Super constructor
System.out.println( "Sub name constructor" );
init(); //can be called anywhere
}
}
If you now call new Sub("some name"), you'll get the following output:
Super initializer
Super common constructor
Super name constructor
Super init method
Sub initializer
Sub name constructor
Sub init method
You can declare an instance method in the class which can be called from a constructor like this:
Class A{
public A(){
initialize();
}
public void initialize(){
//code goes here
}
}
This concept extends to abstract classes as well.
You could chain your constructors.
public class Test {
public Test() {
// Common initialisations.
}
public Test(String stuff) {
// Call the one ^
this();
// Something else.
}
You can then put your common code in the () constructor.
An alternative is to use an Initializer block.
Class A {
{
// initialize your instance here...
}
// rest of the class...
}
The compiler will make sure the initializer code is called before any of the constructors.
However, I would hesitate a bit to use this use this - perhaps only if there are no other alternatives possible (like putting the code in a base class).
If you can put the common code in one constructor and call it as the first instruction from the other constructors, it is the Java idiomatic way.
If your use case is more complex, you can call a specific method from the constructors provided it is private, final or static (non overidable). An example use case would be:
class Test {
private final void init(int i, String str) {
// do common initialization
}
public Test(int i) {
String str;
// do complex operations to compute str
init(i, str); // this() would not be allowed here, because not 1st statement
}
public Test(int i, String str) {
init(i, str);
}
}
Make a common method and assign it to instance variable. Another way of doing it.
import java.util.List;
public class Test {
int i = commonMethod(1);
Test() {
System.out.println("Inside default constructor");
}
Test(int i) {
System.out.println("Inside argument Constructor ");
}
public int commonMethod(int i) {
System.out.println("Inside commonMethod");
return i;
}
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test(2);
}
}
Related
I'm learning about inheritance and am working with this simple program that has has a superclass and a subclass as shown below. My question isn't specific to this program; however, this is where I've first seen this happen so I'm using it as an example for a more general conceptual question. Why does simply instantiating the class run the constructors and output the contents? My previous understanding was that instantiating the class simply creates the object but it wont do anything.
SuperClass1.java
public class SuperClass1 {
public SuperClass1(){
System.out.println("This is the superclass constructor.");
}
}
SubClass2.java
public class SubClass2 extends SuperClass1
{
public SubClass2()
{
System.out.println("This is the subclass constructor.");
}
}
Main.java
public class Main {
public static void main(String[] args)
{
SubClass2 obj1 = new SubClass2(); // why should this print something?
}
}
Output
This is the superclass constructor.
This is the subclass constructor.
First of all, instantiating an object means calling (and executing) the constructor, that is what it is for.
So, this:
SubClass2 newInstance = <createNewInstance>;
newInstance.<init()>;
is both done by the constructor call new SubClass2() in Java. There is no separation between "constructing" the object and "initialising" its properties.
Furthermore, if you do not explicitly call another constructor of a super class the default constructor (the one without arguments) is automatically called first thing when creating an object of a class. So instantiating an object of the subclass calls the superclass contructor (which prints the first line), and then prints the second line itself.
More in detail, the subclass looks like this behind the scene:
public class SubClass2 extends SuperClass1
{
public SubClass2()
{
super(); // calls the superclass constructor
System.out.println("This is the subclass constructor.");
}
}
Because the constructor you call includes a print statement.
You call the constructor method SubClass2() which has a print statement in it.
The statements are not printed because the class ist loaded, but because an object of that class in instantiated and the constructors are called:
That a class can be loaded without using constructor is demonstrated by the following code:
public class Test {
public static void main(String[] args) {
try {
Class.forName("Test$Inner");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
static class Inner {
static {
System.out.println("static initializer");
}
public Inner() {
System.out.println("inner ctor");
}
}
}
running that program shows that only the static class initializer is called and no constructor.
In Java, is there any way to initialize a field before the super constructor runs?
Even the ugliest hacks I can come up with are rejected by the compiler:
class Base
{
Base(String someParameter)
{
System.out.println(this);
}
}
class Derived extends Base
{
private final int a;
Derived(String someParameter)
{
super(hack(someParameter, a = getValueFromDataBase()));
}
private static String hack(String returnValue, int ignored)
{
return returnValue;
}
public String toString()
{
return "a has value " + a;
}
}
Note: The issue disappeared when I switched from inheritance to delegation, but I would still like to know.
No, there is no way to do this.
According to the language specs, instance variables aren't even initialized until a super() call has been made.
These are the steps performed during the constructor step of class instance creation, taken from the link:
Assign the arguments for the constructor to newly created parameter
variables for this constructor invocation.
If this constructor begins with an explicit constructor invocation
(§8.8.7.1) of another constructor in the same class (using this),
then evaluate the arguments and process that constructor invocation
recursively using these same five steps. If that constructor
invocation completes abruptly, then this procedure completes
abruptly for the same reason; otherwise, continue with step 5.
This constructor does not begin with an explicit constructor
invocation of another constructor in the same class (using this). If
this constructor is for a class other than Object, then this
constructor will begin with an explicit or implicit invocation of a
superclass constructor (using super). Evaluate the arguments and
process that superclass constructor invocation recursively using
these same five steps. If that constructor invocation completes
abruptly, then this procedure completes abruptly for the same
reason. Otherwise, continue with step 4.
Execute the instance initializers and instance variable initializers
for this class, assigning the values of instance variable
initializers to the corresponding instance variables, in the
left-to-right order in which they appear textually in the source
code for the class. If execution of any of these initializers
results in an exception, then no further initializers are processed
and this procedure completes abruptly with that same exception.
Otherwise, continue with step 5.
Execute the rest of the body of this constructor. If that execution
completes abruptly, then this procedure completes abruptly for the
same reason. Otherwise, this procedure completes normally.
Super constructor will run in any case, but since we are talking about the "ugliest hacks", we can take advantage of this
public class Base {
public Base() {
init();
}
public Base(String s) {
}
public void init() {
//this is the ugly part that will be overriden
}
}
class Derived extends Base{
#Override
public void init(){
a = getValueFromDataBase();
}
}
I never suggest using these kind of hacks.
I got a way to do this.
class Derived extends Base
{
private final int a;
// make this method private
private Derived(String someParameter,
int tmpVar /*add an addtional parameter*/) {
// use it as a temprorary variable
super(hack(someParameter, tmpVar = getValueFromDataBase()));
// assign it to field a
a = tmpVar;
}
// show user a clean constructor
Derived(String someParameter)
{
this(someParameter, 0)
}
...
}
As others have said, you can't initialize the instance field before calling the superclass constructor.
But there are workarounds. One is to create a factory class that gets the value and passes it to the Derived class's constructor.
class DerivedFactory {
Derived makeDerived( String someParameter ) {
int a = getValueFromDataBase();
return new Derived( someParameter, a );
}
}
class Derived extends Base
{
private final int a;
Derived(String someParameter, int a0 ) {
super(hack(someParameter, a0));
a = a0;
}
...
}
It's prohibited by the Java language specification (section 8.8.7):
The first statement of a constructor body may be an explicit
invocation of another constructor of the same class or of the direct
superclass.
The constructor body should look like this:
ConstructorBody:
{ ExplicitConstructorInvocationopt BlockStatementsopt }
although it's not possible to do it directly, you can try to do it with nested object
so with your example:
open class Base {
constructor() {
Timber.e(this.toString())
}
}
class Derived {
val a = "new value"
val derivedObject : Base = object : Base() {
override fun toString(): String {
return "a has value " + a;
}
}
}
Happy coding - it's hack but works :) remember to define derivedObject as LAST variable
I designed a hierarchy of UI forms which ran into a similar issue. I found a similar case and some workarounds here: https://www.javaspecialists.eu/archive/Issue086-Initialising-Fields-Before-Superconstructor-Call.html
I changed a little the implementation of their first workaround to make it more generic (by accepting a variable number of parameters):
public abstract class BaseClass {
int someVariable; // not relevant for the answer
public BaseClass (int someVariable, Object... arguments) {
this.someVariable = someVariable;
// Must be called before using local variables of derived class
initializeLocalVariablesOfDerivedClass(arguments);
useLocalVariablesOfDerivedClass();
}
protected abstract void initializeLocalVariablesOfDerivedClass (Object... arguments);
protected abstract void useLocalVariablesOfDerivedClass();
}
public class DerivedClass extends BaseClass {
protected String param1;
protected Integer param2;
public DerivedClass(int someVariable, Object... arguments) {
super(someVariable, arguments);
}
#Override
protected void initializeLocalVariablesOfDerivedClass(Object... arguments) {
// you must know the order and type of your local fields
param1 = (String) arguments[0];
param2 = (Integer) arguments[1];
}
#Override
protected void useLocalVariablesOfDerivedClass() {
System.out.println("param1: " + param1);
System.out.println("param2: " + param2);
}
public static void main(String[] args) {
new DerivedClass(1, new String("cucu"), new Integer("4"));
}
}
Why It calls base class method when we declare method as static in base as well as in derive class and do upcasting.
class Base
{
static void show(){
System.out.println("Base class....");
}
}
class Derive extends Base
{
static void show(){
System.out.println("Drive class....");
}//method hidding.....
public static void main(String[] args)
{
Base b= new Derive();
b.show();
}
}
There are several issues here to mention:
static methods are not inherited and not overridden by the sub-classes
static methods do not need an instance to be called, they need a class
So, basically, calling b.show(); actually means calling Base.show();
You're calling Base.show, not Derive.show. Method hiding is not overriding.
§8.4.8.2. of the Java Language Specification gives an example that demonstrates exactly what happens here:
A class (static) method that is hidden can be invoked by using a reference whose type is the class that actually contains the declaration of the method. In this respect, hiding of static methods is different from overriding of instance methods. The example:
class Super {
static String greeting() { return "Goodnight"; }
String name() { return "Richard"; }
}
class Sub extends Super {
static String greeting() { return "Hello"; }
String name() { return "Dick"; }
}
class Test {
public static void main(String[] args) {
Super s = new Sub();
System.out.println(s.greeting() + ", " + s.name());
}
}
produces the output:
Goodnight, Dick
because the invocation of greeting uses the type of s, namely Super, to figure out, at compile time, which class method to invoke, whereas the invocation of name uses the class of s, namely Sub, to figure out, at run-time, which instance method to invoke.
Just one more completion to the answers above. It's best to invoke class methods by their class not by an instance variable: Base.show() not b.show() to make clear that the method is a static method. This is especially useful in your case when you are hiding a method, not overriding it.
Take a look at the following code sample :
public class Test{
public static void main(String[] args){
System.out.println(new Test());
System.out.println(new Test(){
public String toString(){
return "manual override";
}
});
System.out.println(new Test(){
public String gm(){
return "manual gm";
}
}.gm());
} //end of main method
public String gm(){
return "gm";
}
}
There may be some argument that the toString() method is being overridden in anonymous inner class which is an entirely different class.
But the overriding code still resides in the same class. So, will it be justified to conclude that in some situations [as described above] , the overriding of a method in same class is possible?
Firstly, you haven't defined toString in your Test.java class.
Secondly, when you make a anonymous class, its is conceptually like creating a subclass. So overriding in anonymous class is allowed as long as parent method is not final.
Mainly, overriding is NOT possible in same class otherwise.
The answer is No, you cannot override the same method in one class. The anonymous inner class is a different class.
The code above overrides toString() method of Object class. So you cannot say that it overrides in the same class. Now also it is overriding a superclass method and here the super class is Object which is the super class of all classes.
No , You can override a method in subclass only.
public String toString(){
return "manual override";
}
In your case you are overriding Object's toString() method not Test class method.
In one class we can not have method with same signature.
this is because there is no need to have override method in same class.
hence overriding method in same class is not possible, where as if we want to use same method name we can overload method by changing signature.
About the "real world use case," I do find a practical usage of the above program in section 2.5 of "JUnit Recipes" 2005 by Manning.
public class Counter {
private int count;
// a simple integer instance variable
public Counter( ) { }
// default constructor (count is 0)
public Counter(int initial) { count = initial; }
// an alternate constructor
public int getCount( ) { return count; }
// an accessor method
public void increment( ) { count++; }
// an update method
public void increment(int delta) { count += delta; }
// an update method
public void reset( ) { count = 0; }
// an update method
}
Isn;t this function overriding under same class??
I have something like this:
public abstract class Menu {
public Menu() {
init();
}
protected abstract void init();
protected void addMenuItem(MenuItem menuItem) {
// some code...
}
}
public class ConcreteMenu extends Menu {
protected void init() {
addMenuItem(new MenuItem("ITEM1"));
addMenuItem(new MenuItem("ITEM2"));
// ....
}
}
//Somewhere in code
Menu menu1 = new ConcreteMenu();
As you can see superclass's init method is abstract and is called by constructor automatically after object is created.
I'm curious if i can run into some sort of problems with code like this, when i need to create some object of this kind whose structure wont't be changed in time.
Would be any approach better? It works in Java, but will it work in C++ and possibly ActionScript?
Thank you for answer.
DO NOT INVOKE OVERRIDEABLE METHODS FROM THE CONSTRUCTOR.
A quote from Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it:
There are a few more restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will be invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.
Here's an example to illustrate:
public class ConstructorCallsOverride {
public static void main(String[] args) {
abstract class Base {
Base() { overrideMe(); }
abstract void overrideMe();
}
class Child extends Base {
final int x;
Child(int x) { this.x = x; }
#Override void overrideMe() {
System.out.println(x);
}
}
new Child(42); // prints "0"
}
}
Here, when Base constructor calls overrideMe, Child has not finished initializing the final int x, and the method gets the wrong value. This will almost certainly lead to bugs and errors.
Related questions
Calling an Overridden Method from a Parent-Class Constructor
State of Derived class object when Base class constructor calls overridden method in Java
See also
FindBugs - Uninitialized read of field method called from constructor of superclass
You are right in that it might cause problems with a derived class whose instance variables are initialised in the constructor or when the instance is created.
If you had this:
public class ConcreteMenu extends Menu {
String firstItem = "Item1";
protected void init() {
addMenuItem(new MenuItem(firstItem));
// ....
}
}
Then the MenuItem would have null as it's constructor argument!
Calling non-final methods in constructors is a risky practise.
A simple solution could be to separate the construction and the initialisation, like so:
Menu menu = new ConcreteMenu();
menu.init();
As others mentioned, calling an overridable method from the constructor is entering a world of pain ...
Have you considered doing the initialization in the constructor itself?
public abstract class Menu {
public Menu() {
....
}
protected void addMenuItem(MenuItem menuItem) {
// some code...
}
}
public class ConcreteMenu extends Menu {
public ConcreteMenu() {
super();
addMenuItem(new MenuItem("ITEM1"));
addMenuItem(new MenuItem("ITEM2"));
// ....
}
}