What is the Difference between super(variable-name); and super.variableName = something; in a constructor, when you want to initialize the parameters and you wanna assign one of them to a variable of a parent class?
for example i want to implement the constructor of the "Zahnradfraese" and it takes the parameter "int Kennung" and this parameter should be assigned to the attribute "kennung" of the parent class "Produktionmittel"
Should I always use super when I wanna call a variable from this parent class or I just use it if I have another variable with the same name in the child class?
What is the difference between super(variableName); and super.variableName = something;?
method() (here, super(variableName)) is a method invocation (here, a parent's constructor invocation).
super.variableName = something; is an assignment to a parent's field.
Should I always use super when I wanna call a variable from this parent class or I just use it if I have another variable with the same name in the child class?
super(variableName) can initialise the inner state of the parent, particularly super.variableName. It is reasonable to initialise a super.variableName before accessing it. Both ways you listed can be utilised for that. Just make sure there is no code duplication.
I want to implement the constructor of the Zahnradfraese and it takes the parameter int Kennung and this parameter should be assigned to the attribute kennung of the parent class Produktionmittel.
Add a constructor to Produktionmittel which takes an int
public Produktionmittel(int i) {
kennung = i;
}
and call it from the child:
public Zahnradfraese(int kennung) {
super(kennung);
}
super(variable_name) represents a constructor call and should be first line in the constructor. Whereas super.variableName = something; means you are assigning a value to the instance variable of the parent class from the child class using super which is used to refer parent class objects.
Now in your case: as per given class-diagram
the class Zahnradfraese has a constructor which takes int Kennung argument. Also, kennung is the parent-class and has no constructor and instead it has method setKennung(). So you can do super.setKennung(kennung) from inside the constructor of Zahnradfraese class. You can also declare a constructor inside kennung but that would mean deviating from the class-diagram which has setter and getter methods and no constructor.
public class Zahnradfraese extends Kennung{
public Zahnradfraese(int kennung){
super.setKennung(kennung);
}
}
So super(variableName) is invoking your parent class one arg constructor, and that logic gets executes
super.variableName = something; is assigning something value to parent class variable variableName
super() is a keyword which is used to call the constructor in the parent class and it must be called from inside the constructor of the child class. Also it must be the first statement.
Where as super.s is used to set the variable s (which is declared in the parent class) from the child class and it doesn't have restrictions as above.
See below example:
class Test {
int s;
Test(int d) {
}
}
class T extends Test {
T() {
super(8);
int d = 99;
super.s = 00;
}
void ss() {
super.s = 99;
}
}
super(arg) invokes the constructor of the super class, setting the variable just sets the variable. (The constructor might contain more logic than just assigning a variable, which you bypass with the second way)
Simple example:
public class P{
protected String variable1;
private boolean variableInitialized = false;
public P (String s){
this.variable1 = s;
this.variableInitialized=true;
}
}
public class C extends P{
}
calling super("x") within C will also set the boolean flag, as the parent class "might expect" it. Calling super.variable1="x" will not affect the boolean flag, and you can't change it, cause it's private.
As a rule of the thumb i'd say: If there is a dedicated constructor for a certain variable, it seems worth using it, unless you exactly want to override that implementation.
Related
In the following example:
class A {
private int a;
private int b;
private int c;
public A(int a, int b , int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
class B extends A {
public B() {
super(1,2,3);
}
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
You cannot call super() like this:
class B extends A {
super(1,2,3);
}
super() OR this() should be the first statement in a constructor. First correct this basic mistake of yours before going further. super() is used by default even if you don't explicitly use it.
class B extends A {
B (){
super(1,2,3);
}
}
This is the right way. Please Read about Constructors and Java language basics first before posting questions.
EDIT
I didn't notice that someone edited you question to add super(1,2,3) in a constructor, now answering your questions as follows:
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
No, by calling super(1,2,3) all you're doing is passing 3 integer values to the base class constructor public A(int a, int b , int c) After that you're assigning these values to the private instance variables of base class, you're not making a separate fields for class B, if thats what you asked, and No B class still can't access base class instance variables directly (by stating directly I mean by inheritance or making an instance, there are other ways like setters/getters etc)
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
No, if you don't use a constructor in B class which uses super(int, int, int) to match the arguments of base class constructor (int a, int b , int c) then your code won't even compile. The default constructor will call the no-args constructor of Base class, but since Base class has no default constructor you'll get compilation error!
First of all, the code you posted is not valid Java. It is important that you post working code, otherwise we can't be sure about what you are asking.
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
Assuming you put the statement in a constructor instead of at class level, which is illegal, then no, that will not automatically create fields in class B. It just calls the constructor in the superclass A that takes three int arguments and initializes the fields in the superclass part of the object.
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
Since there is no default (i.e. no-arguments) constructor in class A, you would get a compiler error - the compiler would complain that there is no appropriate constructor in class A.
Java only automatically adds a no-arguments constructor to a class if you do not specify a constructor at all in the class. Since class A already has a constructor, Java is not automatically going to add a no-arguments constructor.
First of all you need to understand one thing: private fields of a parent class ARE BEING INHERITED. The only thing is that if they are private in parent, then they cannot be accessed directly from the child class (the B class in your example). So in other words: not a single B class method can access those fields, but every A class method can access them. So for example its possible that there is a public/protected method inside A class that changes some of those fields and this method can be called from a child class (B).
Once you correct your class to the proper:
class B extends A {
public B() {
super(1,2,3);
}
}
...we can proceed to answer your actual questions.
The constructor of A does not create fields. The fields are created as part of creating of any A object, and are initialized by the constructor.
Those fields are created in B as well, but not because you called super(1,2,3) but because you extend A. As soon as an instance of B, which is an extended instance of A is created, those fields are there - but they are accessible only to methods that are declared in A itself and not in its descendents.
By calling super(1,2,3), you are initializing those private fields. They are still not accessible to B. The constructor of A is mediating between B and these private variables. If you had a method that prints those fields in A, and that method was not private, you could call it and it would print them with these values.
As for your second question, if you didn't call the super(1,2,3), Java would try to call the default constructor. However, for a class that has a constructor, there is no default constructor. The empty/nullary constructor only exists if you either declared it yourself, or if you didn't declare any constructor at all.
// The following two classes have a default constructor which will be called
// if any descendent doesn't call super(...)
class HasADefaultConstructor {
}
class AlsoHasADefaultConstructor {
AlsoHasADefaultConstructor() {
}
}
// But this one doesn't.
class DoesntHaveADefaultConstructor {
DoesntHaveADefaultConstructor( String a ) {
}
}
So you can't inherit private varibles, but you can access them if the parent class has the appropriate getters:
Run the example and you see the output is 'a is: 1'
Regarding the default constructor: In your example you have explicitly implemented
a constructor. So the implicit default constructor is not there any more
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
//access a
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}
One of my classes inherits from a class in a framework I use. The superclass calls a method in its constructor which I overwrite in my own class.
The method uses a field I want to initialize before it is called by the super constructor to avoid a NullPointerException.
Is there any way to do this?
Here is a synthetic test scenario, I want c in Child to not be null when call is called.
public class Test {
public static class Parent {
public Parent() {
super();
call();
}
// only called from parent constructor
public void call() {
System.out.println("Parent");
}
}
public static class Child extends Parent {
private Child c = this;
public Child() {
super();
}
// only called from parent constructor
public void call() {
System.out.println("Child, c is " + (c == null ? "null" : "this"));
}
}
public static void main(String[] args) {
new Child();
}
}
Prior to Java 7, that was possible. I could get by with stunts like this:
public static class Child extends Parent {
private Child c;
private Child(Object unused) {
super();
}
public Child() {
this(c = this);
}
// only called from parent constructor
public void call() {
System.out.println("Child, c is " + (c == null ? "null" : "this"));
}
}
Now, that won't work anymore. I appreciate the additional safety, but the call from super destroys any safety gained by it and reduces the flexibility.
I'd like a way to circumvent this restriction.
As an alternative, I'd like to know what's gained by an restriction that spares the super constructor case.
A static initializer will be called before the super class constructor. However, you won't be able to set any non-static fields, so it most likely won't help.
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
A non-static initialization block also doesn't help as it is called after the super class constructor completes.
Another approach may be to do nothing when called from the super-constructor and make the call again the child constructor, e.g:
public Child() {
super();
call();
}
public void call() {
if (c==null) {
return;
}
System.out.println("do something with c now");
}
This won't work if more stuff happens in the super constructor that is dependent on this method though.
I have to agree with EJP that this is all a bad idea; it would be much better to find a completely different solution that doesn't involve torturing constructors.
This is an answer to the "I'd like to know what's gained by an restriction that spares the super constructor case." part of the question.
In the course of construction, there are three states the fields declared in a class X might be in: All default values, all fully initialized to consistent working values, and anything else.
The objective seems to be that code in classes other than X only sees one of the first two states. When non-static initializer or constructor code for any of X's superclasses is running, X's fields are all in the default state. When non-static initializer or constructor code for any subclass of X is running, all X's fields have been initialized to a fully consistent, usable state.
Only X initializer and constructor code should have to deal with X fields in an inconsistent state, some initialized, some default, and some partially initialized.
This can certainly be circumvented by calling X methods from an X superclass initializer or constructor, but that is commonly regarded as an anti-pattern. The problem is running X code that is not called locally from an initializer or constructor in a partially constructed X. If that code changes a field, the change may be overwritten when the X initializers and constructor body run.
Note that your class Child is translated into the following equivalent by the Java compiler:
public static class Child extends Parent {
private Child c;
public Child() {
super();
c = this;
}
// Remaining implementation
}
This is the same for Java 6 and 7, the generated byte code for the constructor is even the same when compiling with any of both versions. The local field is always instantiated after calling the super constructor. What compiler did you use to make your "work-around" work?
This restriction is quite elementary. This way, you can rely on that super constructors are applied first. Imagine, your sub constructor was using a final field declared in this class. You could not guarantee that this field was initialized if you would not guarantee this constructor execution order. This restriction makes Java more reliable.
This should never have worked in the first place.
Note that at the bytecode level, this actually is allowed. In bytecode, you can set fields declared in the current class before calling a superclass constructor. However, Java provides no way to use this behavior. It is only used secretly by the Java compiler to initialize the synthetic fields added to support inner classes.
why I can't assign variable i in subclass ?
class a {
int i;
}
class b extends a {
i=1;
}
You can assign variables in a subclass. What you can't do is put statements where only declarations are allowed. (Note that int i = 10; is a declaration - not a statement.)
In this case the constructor would likely be a suitable place to establish a default value (for the subtype):
class b extends a {
public b () {
i = 1;
}
}
As damo suggested, an initialization block would also work. This is discussed in Initializing Fields tutorial:
Normally, you would put code to initialize an instance variable in a constructor [but] there are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods.
All answers are correct but no one says that you can do this..
class b extends a {
{
i=1;
}
}
And this will compile and be execute after a constructor and before b constructor
As you are using the default access modifier, this means that the property in class a is accessible to all classes within the same package, including the subclass b. However, you must access the property in a method.
class a {
int i; // this is an instance variable
}
Instance variables are a class level, they can be assigned to a literal or reference variable or you can leave it to have it's default value, the subclass can use the public instances inside it's method or constructor not in the class level as you did :
class b extends a {
i = 3; // assgining a literal to i is compilation error
}
Because it's the location that Class fields and Instance variables declared, not assigning a super class's instance variable to something.
If you want to use i inside class a, you have to use it inside some method or a constructor.
class b extends a {
a(){
i = 4;
}
void doSomething(){
i = 5;
}
}
I was wondering how to use a superclass constructor in a subclass but need to instantiate fewer attributes in the subclass. Below are the two classes. I'm not even sure if I'm doing things right currently. In the second class, there's an error that says "Implicit super constructor PropertyDB() is undefined. Must explicitly invoke another constructor." Note that this code is obviously incomplete and there is code that's commented out.
public abstract class PropertyDB {
private int hectares;
private String crop;
private int lotWidth;
private int lotDepth;
private int buildingCoverage;
private int lakeFrontage;
private int numBedrooms;
private int listPrice;
//public abstract int getPricePerArea();
//public abstract int getPricePerBuildingArea();
public PropertyDB(int newHectares, String newCrop, int newLotWidth, int newLotDepth,
int newBuildingCoverage, int newLakeFrontage, int newNumBedrooms, int newListPrice){
hectares = newHectares;
crop = newCrop;
lotWidth = newLotWidth;
lotDepth = newLotDepth;
buildingCoverage = newBuildingCoverage;
lakeFrontage = newLakeFrontage;
numBedrooms = newNumBedrooms;
listPrice = newListPrice;
}
}
public class FarmedLand extends PropertyDB{
public FarmedLand(int newHectares, int newListPrice, String newCorn){
//super(270, 100, "corn");
hectares = newHectares;
listPrice = newListPrice;
corn = newCorn;
}
}
implicit constructor PropertyDB() exists only if you do not define any other constructors, in which case you will have to explicitly define PropertyDB() constructor.
The reason you see this error "Implicit super constructor PropertyDB() is undefined. Must explicitly invoke another constructor." is that in your public FarmedLand(int newHectares, int newListPrice, String newCorn) constructor, super() is automatically called as the first statement, which does not exist in your superclass.
Here's a simplified example:
public class A { }
can be instantiated by using A a = new A() because public A() { } is an implicit constructor of class A.
public class A {
public A(int z) { /* do nothing*/ }
}
can not be instantiated using A a = new A() because by defining an explicit constructor public A(int z) the implicit one is no longer available.
Moving onto constructors and inheritance, from Java Language Specification section 8.8.7:
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body is implicitly assumed by the compiler to begin with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments.
So in your case the first statement executed in public FarmedLand(int newHectares, int newListPrice, String newCorn) constructor is an implicit call to super();, which in your case is not defined implicitly (there's already a public PropertyDB(int, String, ...) constructor defined) or explicitly (it's not in the source code)
When you have a derived class which extends a base class, the base class always gets constructed before the derived class. If you don't explicitly specify which constructor to use for the base class (like in your example), Java assumes you meant the parameterless constructor (in your case the PropertyDB() constructor).
But wait - PropertyDB doesn't have a parameterless constructor! So your only option is to use super so the Java compiler knows which constructor to call for the base class. In your case, there's only one constructor to choose from, so you have to use it with all 8 arguments. If you want to use less arguments, you either have to specify "default" values (like pass a 0), or else define more constructors for PropertyDB which take fewer arguments.
The error you're witnessing is due to the fact that the PropertyDB class doesn't have a default (no-arguments) constructor. Either create it in PropertyDB or call the existing superclass constructor PropertyDB(int newHectares, String newCrop, int newLotWidth, int newLotDepth, int newBuildingCoverage, int newLakeFrontage, int newNumBedrooms, int newListPrice) from the FarmedLand constructor using super.
Use super(newHectares, newCorn, 0, 0, 0, 0, newListPrice); instead. 0 is the default value of the int anyway.
Your superclass only has one constructor, so your subclass constructor must call it. There's no way around this: the superclass has (for example) a lotWidth field, so the subclass necessarily has that field, and the superclass initializes that field in its constructor, so it will necessarily be initialized in the subclass.
So, unless you modify the superclass in some way, you're going to have to call super(...) as the very first thing in the subclass constructor, specifying values for all its parameters.
I have a class "ChildClass" that extends the class "ParentClass". Rather than completely replace the constructor for the parent class, I want to call the parent class's constructor first, and then do some extra work.
I believe that by default the parent class's 0 arguments constructor is called. This isn't what I want. I need the constructor to be called with an argument. Is this possible?
I tried
this = (ChildClass) (new ParentClass(someArgument));
but that doesn't work because you can't modify "this".
You can reference the parent's constructor with "super", from within a child's constructor.
public class Child extends Parent {
public Child(int someArg) {
super(someArg);
// other stuff
}
// ....
}
To invoke a specific parent-class constructor, put super(param1, param2, ...) as the first statement in the child-class constructor body.
You should use the super keyword.
public ChildClass(...) {
super(...);
}