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"));
}
}
Related
I had this code:
class Egg2 {
protected class Yolk {
public Yolk() { System.out.println("Egg2.Yolk()");}
public void f() { System.out.println("Egg2.Yolk.f()"); }
}
private Yolk y = new Yolk();
public Egg2() { System.out.println("New Egg2()");}
public void insertYolk(Yolk yy) { y = yy; }
public void g() { y.f(); }
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2.Yolk {
public Yolk() { System.out.println("BigEgg2.Yolk"); }
public void f() { System.out.println("BigEgg2.Yolk.f()"); }
}
public BigEgg2() { insertYolk(new Yolk()); }
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
}
Output is:
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk
BigEgg2.Yolk.f()
Issue: now I can't make out how such objects and classes were initialized.
I thought the order should be like this:
Create new link e2: Egg2 e2 = new BigEgg2();
Go to constructor: public BigEgg2() { insertYolk(new Yolk()); }
Because of inheritance compiler go to: public Yolk() { System.out.println("Egg2.Yolk()");}, after that we saw output: Egg2.Yolk();
Then compiler invoked this method: public void insertYolk(Yolk yy) { y = yy; }, where Egg2.Yolk.y = BigEgg2.Yolk.yy (figuratively speaking).
At this step I can't figure out why the next output result will be:
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk
What's appearance at this stage?
Why it go like this?
A lot is going on when you call a constructor of a class with a superclass constructor, and they both have instance variable initializers.
Your constructor for BigEgg2 doesn't explicitly call any superclass constructor, so the compiler inserted a call to the default constructor for Egg2. (The same thing applies to the Egg2 constructor calling the Object constructor, but that one doesn't print anything.)
After the call to the superclass constructor completes, instance initializers for the superclass, if any, are run. This means any instance variables initialized where they are declared. Here, an instance of Egg2.Yolk is created for the instance variable y. This is the first line of output Egg2.Yolk().
Then the body of the superclass constructor is finally executed. This is the second line of output New Egg2().
The BigEgg2 class has its own Yolk class to instantiate to be passed to insertYolk in its own constructor. It creates a Yolk that subclasses the nested class Yolk in Egg2. The superclass constructor is called first, which refers to the Egg2.Yolk class. This is the third line of output Egg2.Yolk(). Note that this is the same print statement as the first line of output.
This object of class BigEgg2.Yolk is assigned to the instance variable y in the superclass method Egg2.insertYolk. This occurs in the body of the BigEgg2.Yolk constructor. The BigEgg2.Yolk constructor is responsible for the fourth line of output BigEgg2.Yolk. Note that the y variable is now referring to an instance of BigEgg2.Yolk. At this point the execution of the first line of main is complete: Egg2 e2 = new BigEgg2();.
When you call e2.g(), you are calling the g() method that BigEgg2 inherits from Egg2, which calls y.f(), where y is a Egg2.Yolk. Because of polymorphism, the f() method in BigEgg2.Yolk is called. This is the fifth line of output BigEgg2.Yolk.f().
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);
}
}
I can't seem to use getConstructor for constructors with no parameters.
I keep getting the following exception:
java.lang.NoSuchMethodException: classname.<init>()
Here is the code:
interface InfoInterface {
String getClassName();
String getMethodName();
String getArgument();
}
class asa implements InfoInterface {
#Override
public String getClassName() {
return ("jeden");
}
#Override
public String getMethodName() {
return ("metoda");
}
#Override
public String getArgument() {
return ("krzyk");
}
}
class Jeden {
Jeden() {
System.out.println("konstruktor");
}
public void Metoda(String s) {
System.out.println(s);
}
}
class Start {
public static void main(String[] argv) {
if (argv.length == 0) {
System.err.println("Uzycie programu: java Start nazwa_klasy nazwa_klasy2...");
return;
}
try {
for (int x = 0; x < argv.length; x++) {
Class<?> c = Class.forName(argv[x]);
InfoInterface d = (InfoInterface) c.newInstance();
String klasa = d.getClassName();
String metoda = d.getMethodName();
String argument = d.getArgument();
Class<?> o = Class.forName(klasa);
// o.newInstance();
Constructor<?> oCon = o.getConstructor();
System.out.println("ASD");
Class<?> p = (Class<?>) oCon.newInstance();
}
} catch (Exception e) {
System.out.println(e);
}
}
}
o.newInstance(); prints "konstruktor" without problems.
The problem is clear when you read the javadoc of .getConstructor():
Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object.
Emphasis mine.
In your code, the constructor is not public!
Example:
// Note: class is NOT public -- its default constructor won't be either
final class Test
{
public static void main(final String... args)
throws NoSuchMethodException
{
// throws NoSuchMethodException
Test.class.getConstructor();
}
}
Obligatory link to an SO answer which also gives the JLS reference. In particular, note that the default constructor has the same access modifier as the class.
It seems as if your class provides a constructor that is NOT a default constructor. The call to getConstructor() without parameters requires the class to have a default constructor. The following test illustrates this.
import org.junit.Test;
public class ConstructorTest {
public static class ClassWithParameterizedConstructor {
public ClassWithParameterizedConstructor(final String param) {
// A parameterized constructor, no default constructor exists
}
}
#Test
public void testFoo() throws NoSuchMethodException {
// Parameterized constructor lookup works fine
ClassWithParameterizedConstructor.class.getConstructor(String.class);
// This doesn't work since there is no default constructor
ClassWithParameterizedConstructor.class.getConstructor();
}
}
So, a possible solution is to either change the call to getConstructor() to include the correct type or to provide a default constructor on the object itself (but why would you do that?).
Read this: http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html
It seems that both classes Class and Constructor have the method newInstance the difference is that in the Class class you can only call newInstance with no arguments, so the called constructor must have an no arguments (this also brings a problem when you have more that one constructor).
The methoe newInstance in the Constructor class allows you to call the constructor with arguments also, notice that you can also use the method getConstructors instead of getConstructor that returns you all the class constructors and allows you to call the constructor method you want.
In this case, since you only have one constructor only and with no arguments, Class.newInstance works fine. To use the getConstructor to have the same result you'll need to add in the end oCon.newInstance();
You can use getDeclaredConstructors() which returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object
class SomeClass{
{
System.out.println("I'am here!");
}
}
public class Main {
public static void main(String[] args) throws Exception{
System.out.println(Arrays.toString(SomeClass.class.getDeclaredConstructors()));
// returns public, protected, default (package) access, and private constructors
// System.out.println(SomeClass.class.getConstructor());
// in that case you got:
// NoSuchMethodException: reflection.SomeClass.<init>()
// because SomeClass don't have public constructor
for (Constructor constructor : SomeClass.class.getDeclaredConstructors()){
constructor.newInstance();
}
}
}
And if you have private constructor like this:
class SomeClass{
private SomeClass(String val){
System.out.println(val);
}
}
You have to set accessible for constructor:
constructor.setAccessible(true);
And get something like this:
class SomeClass{
private SomeClass(String val){
System.out.println(val);
}
}
public class Main {
public static void main(String[] args) throws Exception{
for (Constructor constructor : SomeClass.class.getDeclaredConstructors()){
// constructor.newInstance("some arg"); // java.lang.IllegalAccessException
constructor.setAccessible(true);
constructor.newInstance("some arg");
}
}
}
Note: if your class declared as private his default constructor must be private too.
And be careful with nonstatic-inner classes, which receives an outer class instance
In this (somewhat convoluted) scenario, it's actually possible to get hold of the (non-public) constructor by replacing:
Constructor<?> oCon = o.getConstructor();
with
Constructor<?> oCon = o.getDeclaredConstructor();
The "default" visibility of the Jeden class (and its constructor) makes it accessible to the Start class, since it's defined in the same package.
I was wondering if it was possible to do the following with a Class, that extends another class in Java, if so. How?:
public class HelloWorld {
public HelloWorld() {
A aClass = new A(22);
}
}
public class A extends B {
public A() {
System.out.println(number);
}
}
public class B {
public int number;
public B(int number) {
this.number = number;
}
}
Your A constructor needs to chain to a B constructor using super. At the moment the only constructor in B takes an int parameters, so you need to specify one, e.g.
public A(int x) {
super(x); // Calls the B(number) constructor
System.out.println(number);
}
Note that I've added the x parameter into A, because of the way you're calling it in HelloWorld. You don't have to have the same parameters though. For example:
public A() {
super(10);
System.out.println(number); // Will print 10
}
Then call it with:
A a = new A();
Every subclass constructor either chains to another constructor within the same class (using this) or to a constructor in the superclass (using super or implicitly) as the first statement in the constructor body. If the chaining is implicit, it's always equivalent to specifying super();, i.e. invoking a parameterless superclass constructor.
See section 8.8.7 of the JLS for more details.
I have the following situation:
public abstract class A {
private Object superMember;
public A() {
superMember = initializeSuperMember();
// some additional checks and stuff based on the initialization of superMember (***)
}
protected abstract Object initializeSuperMember();
}
class B extends A {
private Object subMember;
public B(Object subMember) {
super();
subMember = subMember;
}
protected Object initializeSuperMember() {
// doesn't matter what method is called on subMember, just that there is an access on it
return subMember.get(); // => NPE
}
}
The problem is that I get a NPE on a new object B creation.
I know I can avoid this by calling an initializeSuperMember() after I assign the subMember content in the subclass constructor but it would mean I have to do this for each of the subclasses(marked * in the code).
And since I have to call super() as the first thing in the subclass constructor I can't initialize subMember before the call to super().
Anyone care to tell me if there's a better way to do this or if I am trying to do something alltogether wrong?
Two problems:
First, you should never call an overrideable member function from a constructor, for just the reason you discovered. See this thread for a nice discussion of the issue, including alternative approaches.
Second, in the constructor for B, you need:
this.subMember = subMember;
The constructor parameter name masks the field name, so you need this. to refer to the field.
Follow the chain of invocation:
You invoke the B() constructor.
It invokes the A() constructor.
The A() constructor invokes the overridden abstract methot
The method B#initializeSuperMember() references subMember, which has not yet been initialized. NPE.
It is never valid to do what you have done.
Also, it is not clear what you are trying to accomplish. You should ask a separate question explaining what your goal is.
Hum, this code does not look good and in all likelyhood this is a sign of a bad situation. But there are some tricks that can help you do what you want, using a factory method like this:
public static abstract class A {
public abstract Object createObject();
}
public static abstract class B extends A {
private Object member;
public B(Object member) {
super();
this.member = member;
}
}
public static B createB(final Object member) {
return new B(member) {
#Override
public Object createObject() {
return member.getClass();
}
};
}
The problem is when you call super(), the subMember is not initialized yet. You need to pass subMemeber as a parameter.
public abstract class A {
public A (Object subMember) {
// initialize here
}
}
class B extends A {
public B (Object subMember) {
super(subMember);
// do your other things
}
}
Since you don't want to have subMember in the abstract class, another approach is to override the getter.
public abstract class A {
public abstract Object getSuperMember();
protected void checkSuperMember() {
// check if the supberMember is fine
}
}
public class B extends A {
private Object subMember;
public B(Object subMember) {
super();
this.subMember = subMember;
checkSuperMemeber();
}
#Override
public Object getSuperMember() {
return subMember.get();
}
}
I hope this can remove your duplicate code as well.