Videos
This is a favorite interview question. With this questions, the interviewer tries to find out how well you understand the behavior of objects with respect to constructors, methods, class variables (static variables) and instance variables.
Now a days interviewers are asking another favorite question what is effectively final from java 1.8.
I will explain in the end about this effectively final in java 1.8.
import java.util.ArrayList;
import java.util.List;
class Test {
private final List foo; // comment-1
public Test() {
foo = new ArrayList(); // comment-2
foo.add("foo"); // Modification-1 comment-3
}
public void setFoo(List foo) {
//this.foo = foo; Results in compile time error.
}
}
In the above case, we have defined a constructor for 'Test' and gave it a 'setFoo' method.
About constructor: Constructor can be invoked only one time per object creation by using the new keyword. You cannot invoke constructor multiple times, because constructor are not designed to do so.
About method: A method can be invoked as many times as you want (Even never) and the compiler knows it.
Scenario 1
private final List foo; // 1
foo is an instance variable. When we create Test class object then the instance variable foo, will be copied inside the object of Test class. If we assign final foo inside the constructor, then the compiler knows that the constructor will be invoked only once, so there is no problem assigning it inside the constructor.
If we assign final foo inside a method, the compiler knows that a method can be called multiple times, which means the value will have to be changed multiple times, which is not allowed for a final variable. So the compiler decides constructor is good choice! You can assign a value to a final variable only one time.
Scenario 2
private static final List foo = new ArrayList();
foo is now a static variable. When we create an instance of Test class, foo will not be copied to the object because foo is static. Now foo is not an independent property of each object. This is a property of Test class. But foo can be seen by multiple objects and if every object of Test which is created by using the new keyword which will ultimately invoke the Test constructor which changes the value of final static variable at the time of multiple object creation (Remember static foo is not copied in every object, but is shared between multiple objects.). To stop this, compiler knows final static cannot be initialized inside constructor and also cannot provide method to assign object to it. So we have to declare and define final List object at the same place at comment-1 in above program.
Scenario 3
t.foo.add("bar"); // Modification-2
Above Modification-2 is from your question. In the above case, you are not changing the first referenced object, but you are adding content inside foo which is allowed. Compiler complains if you try to assign a new ArrayList() to the foo reference variable.
Rule If you have initialized a final variable, then you cannot change it to refer to a different object. (In this case ArrayList)
final classes cannot be subclassed
final methods cannot be overridden. (This method is in superclass)
final methods can override. (Read this in grammatical way. This method is in a subclass)
Now let's see what is effectively final in java 1.8?
public class EffectivelyFinalDemo { //compile code with java 1.8
public void process() {
int thisValueIsFinalWithoutFinalKeyword = 10; //variable is effectively final
//to work without final keyword you should not reassign value to above variable like given below
thisValueIsFinalWithoutFinalKeyword = getNewValue(); // delete this line when I tell you.
class MethodLocalClass {
public void innerMethod() {
//below line is now showing compiler error like give below
//Local variable thisValueIsFinalWithoutFinalKeyword defined in an enclosing scope must be final or effectively final
System.out.println(thisValueIsFinalWithoutFinalKeyword); //on this line only final variables are allowed because this is method local class
// if you want to test effectively final is working without final keyword then delete line which I told you to delete in above program.
}
}
}
private int getNewValue() {
return 0;
}
}
Above program will throw error in java 1.7 or <1.8 if you do not use final keyword. Effectively final is a part of Method Local Inner classes. I know you would rarely use such effectively final in method local classes, but for interview we have to be prepared.
You are always allowed to initialize a final variable. The compiler makes sure that you can do it only once.
Note that calling methods on an object stored in a final variable has nothing to do with the semantics of final. In other words: final is only about the reference itself, and not about the contents of the referenced object.
Java has no concept of object immutability; this is achieved by carefully designing the object, and is a far-from-trivial endeavor.
Don't use the super keyword to refer to other methods which aren't overridden. It makes it confusing for other developers trying to extend your classes.
Let's look at some code which does use the super keyword in this way. Here we have 2 classes: Dog and CleverDog:
/* file Dog.java */
public static class Dog extends Animal {
private String name;
public Dog(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
/* file CleverDog.java */
public class CleverDog extends Dog {
public CleverDog(String name) {
super(name);
}
public void rollover() {
System.out.println(super.getName()+" rolls over!");
}
public void speak() {
System.out.println(super.getName() + " speaks!");
}
}
Now, imagine you are a new developer on the project, and you need some specific behavior for a clever dog who is on TV: that dog has to do all its tricks, but should go by its fictitious TV name. To accomplish this, you override the getName(...) method...
/* file DogOnTv.java */
public class DogOnTv extends CleverDog {
String fictionalName;
public DogOnTv(String realName, String fictionalName) {
super(realName);
fictionalName = fictionalName;
}
public String getName() {
return fictionalName;
}
}
... and fall into a trap set by the original developer and their unusual use of the super keyword!
The code above isn't going to work - because in the original CleverDog implementation, getName() is invoked using the super keyword. That means it always invokes Dog.getName() - irrelevant of any overriding. Consequently, when you use your new DogOnTv type...
System.out.println("Showcasing the Clever Dog!");
CleverDog showDog = new CleverDog("TugBoat");
showDog.rollover();
showDog.speak();
System.out.println("And now the Dog on TV!");
DogOnTv dogOnTv = new DogOnTv("Pal", "Lassie");
dogOnTv.rollover();
... you get the wrong output:
Showcasing the Clever Dog!
Tugboat rolls over!
Tugboat speaks!
And now the Dog on TV!
Pal rolls over!
Pal speaks!
This is not the usual expected behavior when you override a method, so you should avoid creating this kind of confusion using the super keyword where it doesn't belong.
If, however, this is actually the behavior you want, use the final keyword instead - to clearly indicate that the method can't be overridden:
/* file CleverDog.java */
public class CleverDog extends Dog {
public CleverDog(String name) {
super(name);
}
public final String getName() { // final so it can't be overridden
return super.getName();
}
public void rollover() {
System.out.println(this.getName()+" rolls over!"); // no `super` keyword
}
public void speak() {
System.out.println(this.getName() + " speaks!"); // no `super` keyword
}
}
You are doing the right way by not using the super keyword for accessing getTyreCost.
But you should set your members private and only use the getter method.
Using super keyword should be reserved for constructors and overridden methods which need to explicitly call the parent method.
Calling exactly super() is always redundant. It's explicitly doing what would be implicitly done otherwise. That's because if you omit a call to the super constructor, the no-argument super constructor will be invoked automatically anyway. Not to say that it's bad style; some people like being explicit.
However, where it becomes useful is when the super constructor takes arguments that you want to pass in from the subclass.
public class Animal {
private final String noise;
protected Animal(String noise) {
this.noise = noise;
}
public void makeNoise() {
System.out.println(noise);
}
}
public class Pig extends Animal {
public Pig() {
super("Oink");
}
}
super is used to call the constructor, methods and properties of parent class.