What's the point of a default constructor in OOP? - java

I'm relatively new/inexperienced when it comes to computer science. I was wondering what the point of having a default constructor is when you can just declare any fields you want in your class and initialize them with whatever default value you want them to have. Then, you can write overloaded constructors.
To get an idea of what I'm talking about, here's an example.
public class Restaurant {
String name = "No name";
int Rating = -1;
}
versus
public class Restaurant {
String name;
int rating;
public Restaurant() {
name = "No name";
rating = -1;
}

Constructors are basically used for making objects. As far as variable initialization is concerned, when you initialize a variable (instance variable), you change the variable which is a member of the object you just created. You will understand it better by the example given below (your eg itself):
public class Restaurant {
String name;
int rating;
public Restaurant() {
name = "No name";
rating = -1;
}
}
Now suppose you create an object,
Restaurant obj = new Restaurant();
Here, obj.name = "No name" and obj.rating=-1. Note that name and obj.name are different. Now when you use the first code given by you,
public class Restaurant {
String name = "No name";
int Rating = -1;
}
Now whichever object you create, variable name of every object will contain "No name" only.
Thus, when you have to work with objects, you should initialize the instance variable through constructors. By the way, instance itself means object...

When your variable initialization is based on some logic, you need to write some code and for that purpose default constructor is required. Java provides another approach called initializer blocks and you will be able to do the same but the consistency is the key. The constructors are for object construction let it handle the construction from code readability and maintainability perspective.

IMHO the default constructor is not a requirement of OOP. This is more of a requirement of Java: each class must have at least one constructor. This is underlined by the JLS: 8.8.9 Default Constructors:
If a class contains no constructor declarations, then a default constructor is implicitly declared.
If your class contains at least one constructor declaration (as in your second example) the default constructor is not generated.
Note that when you write
public class Restaurant {
String name = "No name";
int Rating = -1;
}
the field initializers name = "No name"; and Rating = -1; are executed as part of the constructor (JLS 12.5 Creation of New Class Instances):
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
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.
This initialization code is added to every constructor - whether it is the default constructor or any constructor that you write.

Related

Scala overriding Java fields and members

I'm trying to extend the class A which is written in Java to class B in Scala.
class A {
private Pattern pattern;
private String regex= "folder1/folder2/folder3/.*";
A(...){
this.regex = regex;
this.pattern = Pattern.compile(getRegex());
}
public String getRegex() {
return regex;
}
}
class B(...) extends A(...) {
val regex: String= "folder4/.*";
override def getRegex(): String = {
return regex;
}
}
However it seems that the Pattern.compile(getRegex()) is getting null value from the B class. I'm also not allowed to pass the override regex through the constructor. Not sure how I can resolve this issue.
This has nothing to do with scala specifically.
The regex instance variable you create in class B is initialized at some point. Unfortunately, that point is after A's constructor runs.
In general, when a constuctor in Parent invokes an instance method that is overridden in Child, all heck breaks loose. Doesn't matter if it's all java, all scala, or a combination of the two.
There are a few solutions. The simplest is to simply get rid of that field. If the getRegex() method instead is written as return "folder4/.*" instead of return regex, this problem won't occur.
See Java order of Initialization and Instantiation
The constructor is executed at the step 3
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.
And an instance field is initialized at the 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.
So at the step 3 in the line this.pattern = Pattern.compile(getRegex()) inside the constructor of A, getRegex() returns regex, which is null at the moment (regex will become "folder1/folder2/folder3/.*" later, at the step 4).

Java cyclic variable assignment resolution [duplicate]

I am trying to piece together the process of Initialization and Instantiation in the JVM but the JLS is a little obtuse on a few details, so if anyone would mind clearing up some details it would be appreciated. This is what I have been able to figure out so far.
Initialization
Recursively Initialize static final variables of the class and it's interfaces that are compile time constants.
Back out of the recursion processing static blocks and static fields in textual order.
Instantiation
Recursively Initialize final instance variables of the class that are compile time constants.
Back out of the recursion processing non-static blocks and instance fields in textual order prepending them to the constructors as it returns.
Okay, so now for the questions.
are interfaces processed in order of declaration?
are interfaces processed in a separate recursive stack?
a) if yes, do interfaces get processed before or after superclasses?
b) if yes, am I correct in deducing that one or the others (Interface or Superclass) gets its non-compile-time constant fields initialized before the others compile-time constants.
What role does calls to the nondefault super() constructor play in this process?
Am I mistaken in any of my conclusions?
Am I missing any other key details?
It is important to distinguish between the initialization of a class, and initialization of an object.
Class Initialization
A class or interface is initialized upon first access, by assigning the compile time constant fields, then recursively initializing the superclass (if not already initialized), then processing the static initializers (which include the initializers for for the static fields that are not compile time constants).
As you have noticed, initialization of a class does not, by itself, trigger initialization of the interfaces it implements. Interfaces are therefore initialized when they are first accessed, typically by reading a field that is not a compile time constant. This access may occur during evaluation of an initializer, causing a recursive initialization.
It is also worth noting that initialization is not triggered by accessing fields that are compile time constants, as these are evaluated at compile time:
A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.
If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed.
If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).
Object Initialization
An object is initialized whenever a new object is created, typically by evaluation of a class instance creation expression. This proceeds as follows:
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.
As we can see in step 3, the presence of an explicit call to the super constructor simply changes which super class constructor is invoked.
Following is an example that print the order of each step during object creation.
InstanceCreateStepTest.java:
import javax.annotation.PostConstruct;
/**
* Test steps of instance creation.
*
* #author eric
* #date Jan 7, 2018 3:31:12 AM
*/
public class InstanceCreateStepTest {
public static void main(String[] args) {
new Sub().hello();
System.out.printf("%s\n", "------------");
new Sub().hello();
}
}
class Base {
static {
System.out.printf("%s - %s - %s\n", "base", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "base", "instance", "block");
}
public Base() {
System.out.printf("%s - %s\n", "base", "constructor");
}
#PostConstruct
public void init() {
System.out.printf("%s - %s\n", "base", "PostConstruct");
}
public void hello() {
System.out.printf("%s - %s\n", "base", "method");
}
}
class Sub extends Base {
static {
System.out.printf("%s - %s - %s\n", "sub", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "sub", "instance", "block");
}
public Sub() {
System.out.printf("%s - %s\n", "sub", "constructor");
}
#PostConstruct
public void init() {
System.out.printf("%s - %s\n", "sub", "PostConstruct");
}
#Override
public void hello() {
// super.hello();
System.out.printf("%s - %s\n", "sub", "method");
}
}
Execution:
Just invoke the main method, and then check the output.
Tips:
The methods marked by #PostConstruct won't be invoked, unless you invoke it inside some container, like Spring-boot, since it depends on those containers to implement annotation like #PostConstruct.

Constructor Chaining and Visibility in Java

Consider this class:
public class Passenger {
public Passenger() {
}
public Passenger(int freeBags) {
this(freeBags > 1 ? 25.0d : 50.0d);
this.freeBags = freeBags;
}
public Passenger(int freeBags, int checkedBags) {
this(freeBags);
this.checkedBags = checkedBags;
}
private Passenger(double perBagFee) {
this.perBagFee = this.perBagFee;
}
}
Passenger fred = new Passenger(2);
If I understand correctly, 'fred' is a new instance of Passenger. 'fred' calls the constructor with one parameter which is public Passgener(int freeBags). Then this line this(freeBags > 1 ? 25.0d : 50.0d) gets called.
Here is my question: How does the compiler know that the conditional statement in the first constructor to chain to the 'private' constructor? My guess would be that the 'd' in the conditional statement points to the double parameter in the private constructor. But what if there was another constructor with a double parameter? What would it chain to then? There is no mention of perBagFee in the first constructor. I'm a little confused.
EDIT
How does the compiler know that the conditional statement in the first constructor to chain to the 'private' constructor?
Since either values returned by your ternary expression are double values, the compiler knows that this call refers to your constructor method that received one double argument.
My guess would be that the 'd' in the conditional statement points to the double parameter in the private constructor.
The .0d suffix merely says that those are double values.
There is no mention of perBagFee in the first constructor
Method arguments names have no relevance whatsoever outside the method itself. The compiler will always check for what kind of object does your expression evaluate to in order to figure out which method you want to call.
But what if there was another constructor with a double parameter?
Try it :) Inside the same class, you cannot define two methods (constructor or not) with the same signature, regardless of the visibility. Official docs on methods overloading:
Overloaded methods are differentiated by the number and the type of the arguments passed into the method.
You cannot declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart.
What you can see is called Overloading
Overloading is a concept used to avoid redundant code where the same
method name is used multiple times but with a different set of
parameters. The actual method that gets called during runtime is
resolved at compile time, thus avoiding runtime errors.
Java does not remember variable names of the method to identify which overloaded constructor to be called, instead, Java tries to match the variable type
Passenger(int) -> Passenger(10)
Passenger(int, int) -> Passenger(10,10)
Passenger(double) -> Passenger(2.5d)
so, if you defined another constructor of the same pattern as Passenger(double)
. Java will throw compile time error
constructor Passenger(double) is already defined in class Passenger

Trouble trying to grasp inheritance

Given Main.java:
public class Main{
public static void main(String[]args){
A a = new B();
a.print();
}
}
class A{
A() {print();}
void print() { System.out.println("A"); }
}
class B extends A{
int i = 4;
void print() { System.out.println(i); }
}
Results in:
0
4. But why doesn't a.print output "A" if it is referencing Class A? How do I know when one method will called be over another in cases like this? Why is A's constructor being called and still using B's method?
Calling a.print() prints 4 because of polymorphism. The method called depends on the runtime type of a, which is B. It doesn't matter when it's called; polymorphism applies always.
Both times, B's print method is called. Once is from A's constructor, which is called by the default constructor in B. The other time is your explicit call in main.
The reason that the first printing yields 0 and not 4 is because at the time that print is called, A is still being constructed. That is, the A constructor is still being executed. Before a superclass constructor returns, nothing is initialized in the subclass yet, not even variable initializers. The value 4 is assigned after the superclass constructor completes, but before the rest of the subclass constructor completes. Because the variable initializers haven't run yet, the default value of 0 (it would be false for booleans and null for objects) is the value of i in the first printing.
This order is listed by the JLS, Section 12.5:
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
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.
(bold emphasis mine)
This is an example of why it's a bad idea to call a method that can be overridden from a constructor. The subclass state isn't initialized yet.
In case of Overridden methods (like print() in your example), object type decides which method to be invoked, not the reference type.
B doesn't have any constructor, so its default constructor won't do anything except calling A's constructor.
Now when B's default constructor is called, it calls A's constructor (keep in mind i is still not set, so default value 0). A's constructor calls print(), now as object is of actually B it calls B's print() and it prints 0 (remember i was not set).
Now once these constructor calls completes B's code gets executes which sets i to 0. Now calling print() will again get you to B's print() (as object is of B only) which will print 4.
"DEBUGGING IS THE KEY"

Blocking Scoped outputs

I dont know whether this question has been asked before or not .I searched but couldn't find any duplicate question. If you find any related question please mention the link.
public class Exp
{
Exp()
{
System.out.println("Hello"); //3
}
{ System.out.println("Hello")}; //1
{ static{System.out.print("x");} //2
}
The order of printing of messages is 2,1,3.
What are the significance of these lines 1 & 2 and why that exec order
Line "1" is an instance initializer, which runs when an object is first created, before any constructors are called.
Line "2" is a static initializer, which runs when a class is first loaded, before any objects are created.
Section 12.5 of the JLS specifies when instance initializers are run:
Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new
object using the following procedure:
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.
(emphasis mine)
The rest of the body of the constructor is executed after the instance initializer.
static blocks of a class are executed during class loading along with constants (static final members). 3 is invoked when the object is instantiated.
For you to understand better debug the code through your IDE to understand the sequence of execution.
See http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
A static initialization block is a normal block of code enclosed in braces, { }, and preceded by the static keyword. Here is an example:
static {
// whatever code is needed for initialization goes here
}
A class can have any number of static initialization blocks, and they can appear anywhere in the class body. The runtime system guarantees that static initialization blocks are called in the order that they appear in the source code.
The reason for the execution order is, in non-static block you might want to use static members, but in static block you cannot use non-static members. So it makes sense to execute static block first.
non-static block allows you to abstract the code that every constructor needs to execute, therefore it gets executed before constructor.
More detailed order of execution:
1.static block of superclass
2.static block of this class
3.non-static block of superclass
4.constructor of superclass
5.non-static block of this class
6.constructor of this class

Categories

Resources