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).
Related
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.
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
Is this statement true or false?
"The only way a constructor can be invoked is from within another constructor."
I thought a constructor could be invoked from within a method (and other places) if the call to the constructor is preceded with the keyword 'new'.
How about this statement? True or false?
"The only way a constructor can be invoked is from within another constructor (using a call to super() or this()), or from within static or instance methods, static or instance initializer blocks, or even constructors, if the call to the constructor is preceded by the keyword 'new'." Trying to invoke a constructor like you would invoke a method (using only its name) is not allowed."
Is this more accurate? "Where the call to the constructor is not preceded by the keyword 'new', the only way a constructor can be invoked is from within another constructor using this() or super() as the first statement."
Let's just go straight to the JLS, §8.8:
Constructors are invoked by class instance creation expressions (§15.9), by the conversions and concatenations caused by the string concatenation operator + (§15.18.1), and by explicit constructor invocations from other constructors (§8.8.7). [...]
Constructors are never invoked by method invocation expressions (§15.12).
Therefore, the first statement you quoted is technically false, as the JLS defines using new as invoking the constructor.
Note that your paragraph-length statement is a combination of true and false information; you can't invoke a constructor from static or instance methods except via creating a new object.
Rather than focusing on what the author of the original questions means by "invoke"1, here are the different ways that a constructor will be called.
By using the new operator with the class name and parameters that match the constructor signature:
Foon f = new Foon(1, 2);
It is also possible to do the same thing using reflection and the Constructor object equivalent to a new expression, or by using the relevant JNI or JNA callbacks in native code equivalent to a new expression. However, in all cases, the constructor invocation is conceptually happening at same point in the object creation. Hence I will treat them as identical.
By explicitly chaining to the constructor from another constructor in the same class using this(...).
By explicitly chaining to the constructor from a direct subclass constructor using super(...), or by implicitly chaining to a no-args constructor via an implied super() in a direct subclass constructor (declared or implied).
The implicit cases are merely "syntactic sugar" for the explicit super chaining cases.
There are a few other places where new is invoked behind the scenes by Java from regular Java code. A couple that spring to mind are string concatenation, auto-boxing, and the JVM throwing certain exceptions; e.g.
null.toString() // implicitly creates a NullPointerException obj.
1 - ... which is unknowable unless we understand the context, including how the OP's lecturer (or text book) is using the word "invoke".
It's true. You can't write code that actually calls a constructor as follows:
class Vehicle {
Vehicle() { } // Constructor
void doSomething() {
Vehicle(); // Illegal
}
}
The famous illusive constructor.
It's there when it's there, and even when it's not there it's still there.
The constructor is called at object creation.
So yeah the constructor can, or more precisely will be called if you create a object using new , na matter where you use it.
That quote of yours seems to be incomplete
"The only way the constructor of the superclass of the current class can be invoked is from within the current class constructor."
You can use the constructor when you use the class as an object in other class.
MyClass mc = new MyClass();
This statement is false.
'Invoking a constructor' can mean three different things:
You can invoke a constructor by creating a new object with the new operator:
String s = new String("abc");
In which case you will first allocate an object and then invoke the constructor:
NEW java/lang/String // allocate String instance
LDC "abc" // push the String constant on the stack
INVOKESPECIAL "java/lang/String"."<init>" : "(Ljava/lang/String;)V" // invoke constructor
The second way is to invoke another constructor from the same class:
class Super
{
Super(int i) { }
}
class Test extends Super {
Test() { this(1); }
// Bytecode:
INVOKESPECIAL "Test"."<init>" : "(I)V"
// ---------
The third way to invoke a constructor is to invoke one from the super class:
Test(int i) { super(i); }
// Bytecode:
INVOKESPECIAL "Super"."<init>" : "(I)V"
// ---------
}
Either way, the generated bytecode will contain an INVOKESPECIAL instruction. This means you are literally invoking the constructor in three cases, so if you define 'invoke' by that instruction, there is more than one way to invoke a constructor.
If you mean, directly invoking another constructor of the same object using the this(...) or super(...) construct (called explicit constructor invocation), the answer is yes.
It is probable that this is what the question meant but you have to be really precise in the wording and this question isn't.
Because if by "invoke" you mean, "causing a constructor to run", then you can "invoke" a constructor with the new keyword, which first allocates and creates the object, and then a constructor is run. In this, rather looser sense the answer is no.
But, importantly, new does a lot more than just calling the constructor. So in the most literal sense, calling new is not the same as invoking a constructor. Just like making tea involves pouring hot water but is not the same as simply pouring hot water.
Whether you want to make that distinction or not is up to you, or in this case the author of the question, you need to ask them.
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
Let's look at the following code snippet in Java.
package trickyjava;
class A
{
public A(String s)
{
System.out.println(s);
}
}
final class B extends A
{
public B()
{
super(method()); // Calling the following method first.
}
private static String method()
{
return "method invoked";
}
}
final public class Main
{
public static void main(String[] args)
{
B b = new B();
}
}
By convention, the super() constructor in Java must be the first statement in the relevant constructor body. In the above code, we are calling the static method in the super() constructor parameter list itself super(method());.
It means that in the call to super in the constructor B(), a method is being
called BEFORE the call to super is made! This should be forbidden by the compiler but it works nice. This is somewhat equivalent to the following statements.
String s = method();
super(s);
However, it's illegal causing a compile-time error indicating that "call to super must be first statement in constructor". Why? and why it's equivalent super(method()); is valid and the compiler doesn't complain any more?
The key thing here is the static modifier. Static methods are tied to the class, instance methods (normal methods) are tied to an object (class instance). The constructor initializes an object from a class, therefore the class must already have been fully loaded. It is therefore no problem to call a static method as part of the constructor.
The sequence of events to load a class and create an object is like this:
load class
initialize static variables
create object
initialize object <-- with constructor
object is now ready for use
(simplified*)
By the time the object constructor is called, the static methods and variables are available.
Think of the class and its static members as a blueprint for the objects of that class. You can only create the objects when the blueprint is already there.
The constructor is also called the initializer. If you throw an exception from a constructor and print the stack trace, you'll notice it's called <init> in the stack frame. Instance methods can only be called after an object has been constructed. It is not possible to use an instance method as the parameter for the super(...) call in your constructor.
If you create multiple objects of the same class, steps 1 and 2 happen only once.
(*static initializers and instance initializers left out for clarity)
Yep, checking the JVM spec (though admittedly an old one):
In the instance init method, no reference to "this" (including the implicit reference of a return) may occur before a call to either another init method in the same class or an init method in the superclass has occurred.
This is really the only real restriction, so far as I can see.
The aim of requiring the super constructor to be invoked first is to ensure that the "super object" is fully initialized before it is used (It falls short of actually enforcing this because the super constructor can leak this, but that's another matter).
Calling a non-static method on this would allow the method to see uninitialized fields and is therefore forbidden. A static method can only see these fields if it is passed this as argument. Since accessing this and super is illegal in super constructor invocation expressions, and the call to super happens before the declaration of any variables that might point to this, allowing calls to static methods in super constructor invocation expressions is safe.
It is also useful, because it allows to compute the arguments to the super constructor in an arbitrarily complex manner. If calls to static methods weren't allowed, it would be impossible to use control flow statements in such a computation. Something as simple as:
class Sub extends Super {
Sub(Integer... ints) {
super(Arrays.asList(ints));
}
}
would be impossible.
This is one situation where the java syntax hides what's really going on, and C# makes it a bit clearer.
In C# your B would look like
class B : A {
public B() : base(method()) {
}
private static String method() {
return "method invoker";
}
}
Although the java syntax places super(method) within the constructor it's not really called there: All the parent initialization is run before your subclass constructor. The C# code shows this a little more clearly; by placing super(method()) at the first line of the java constructor you're simply telling java to use the parameterized constructor of the super class rather than the parameterless version; this way you can pass variables to the parent constructor and they'll be used in the initialization of the parent level fields before your child's constructor code runs.
The reason that super(method()) is valid (as the first line in a java constructor) is because method() is being loaded with the static elements--before the non-static ones, including the constructors--which allows it to be called not only before B(), but before A(String) as well. By saying
public B() {
String s = method();
super(s);
}
you're telling the java compiler to initialize the super object with the default constructor (because the call to super() isn't the first line) and you're ready to initialize the subclass, but the compiler then becomes confused when it sees that you're trying to initialize with super(String) after super() has already run.
A call to super is a must in java to allow the parent to get initalized before anything with child class starts.
In the case above, if java allows String s= method(); before the call to super, it opens up flood gate of things that can be done before a call to super. that would risk so many things, essentially that allows a half baked class to be used. Which is rightly not allowed. It would allow things like object state (some of which may belong to the parent) being modified before it was properly created.
In case of super(method()); call, we still adhere to the policy of completing parent initialization before child. and we can use a static member only, and static member of child classes are available before any child objects are created anyways. so the method is avilable and can be called.
OK..i think, this one could be relevant that, if we are calling some member with Super, then it first try to invoke in super class and if it doesn't find same one then it'll try to invoke the same in subclass.
PS: correct me if i'm wrong