What's the constructor here? - java

The text of an exercise from a well known and basic Java programming textbook follows:
'Sometimes we would like a class that has just a single unique instance. Create a class Merlin that has one attribute, theWizard, which is static and of type Merlin. The class has only one constructor and two methods, as follows:
* Merlin —a private constructor. Only this class can invoke this construc-
tor; no other class or program can create an instance of Merlin
* summon —a static method that returns theWizard if it is not null; if theWizard is null, this method creates an instance of Merlin using the private constructor and assigns it to theWizard before returning it.
* consult—a non-static method that returns the string "Pull the sword
from the stone" '
Were you able to understand what the author is asking in the point 'Merlin -a private constructor' ? I know what a constructor is as well as what a private method is. But here what's the answer ? I thought of something like
public class Merlin {
private static Merlin theWizard;
/*public Merlin()
{
???
}*/
private Merlin()
{
this();
}
public static Merlin summon(Merlin theWizard) {
if (theWizard == null) {
theWizard = new Merlin();
return theWizard;
}
public String consult() {
return "Pull the sword from the stone";
}
}
and of course JavaBeans says 'private Merlin()' is recursive. So what do I do ? The next exercise is related to the above one and could help you to understand what the answer is; here it is:
Create a program that tests the class Merlin described in the previous exercise.
Use the toString method to verify that a unique instance has been created.
Thank you very much for all that you will be able to tell me.

This is an instance of the Singleton Pattern; in your case, just replace this() with super() to use the superclass's constructor (technically, if you don't place a super constructor call, the compiler will insert one for you; so you could just remove it).
Food for thought:
why is the Merlin class private?
why is the Merlin class static?
where's the rest of your code?

Get rid of this():
public class Merlin {
private static Merlin theWizard;
private Merlin() {}
...
}
this followed by parens is the syntax used to call a constructor of the same class, since you are not specifying any arguments inside the parens then you're referring to the no-argument instructor, which is the constructor this is being called from, so the constructor would call itself recursively until it runs out of stack space. The IDE is checking for this problem and trying to warn you about it.
Calling super() in the constructor is allowed (it calls the no-argument constructor in the superclass, which here is java.lang.Object) but not required, the compiler will insert a call to super if you don't.
By the way you can't have multiple overloads of a constructor or method with the same argument list. You can't have a public no-arg constructor and a private no-arg constructor.
The author is trying to describe a class that has control over how its instances are created, it makes its constructor private so that only the class itself is allowed to instantiate an object of that class.

Related

Can't understand Java inheritance

i'm studying java as first language, so i'm a complete newbie.
I'm now studying inheritance between classes, and there's something i can't understand. I give you an example:
This is the main class:
public class Bici {
protected int misura;
protected String modello;
public Bici(int misura, String modello)
{
this.misura=misura;
this.modello=modello;
}
public void stampaCaratteristiche()
{
System.out.println("Size is: "+misura);
System.out.println("Model is: "+modello);
System.out.println();
}
}
This is the subclass:
public class Tandem extends Bici {
private int ruote;
public Tandem (int ruote)
{
super(misura, modello);
this.ruote=ruote;
}
public void stampaCaratteristicheTandem()
{
System.out.println("Le ruote del tandem sono "+ruote);
}
}
but when declaring super variables i get this error:
"Cannot refer to an instance field modello while explicitly invoking a constructor"
Why? Thank you!
you do not have default constructor in Bici class, it means in Tandem class it has to be invoked explicitly. like this :
private int ruote;
public Tandem (int ruote, int misura, String modello)
{
super(misura, modello);
this.ruote=ruote;
}
public void stampaCaratteristicheTandem()
{
System.out.println("Le ruote del tandem sono "+ruote);
}
A superclass constructor must execute before a subclass constructor. So that the state and behavior defined by the superclass may be correctly and completely initialized before a subclass constructor executes.
Java compiler assumes that the first line of every constructor is an implicit call to the default superclass constructor unless you explicitly use super() or this().
Note that Super keyword is used to explicitly invoke a superclass constructor. If you use this form, it must appear as the first statement of the constructor to ensure that the superclass constructor executes before the subclass constructor
The Java inheritance mechanism does not include constructors. In other words, constructors of a superclass are not inherited by subclasses. Subclasses can still call the constructors in the superclass using the super() contruct. In fact, a subclass constructor is required to call one of the constructors in the superclass as the very first action inside the constructor body. You may have seen Java classes where the subclass constructors did not seem to call the constructors in the superclass. Maybe the superclass did not even have a constructor. However, the subclass constructors have still called superclass constructors in those case. You just could not see it. Let me explain why:
If a class does not have any explicit constructor defined, the Java compiler inserts an implicit no-arg constructor. Thus, a class always has a constructor.
This is because you can not call an instance method before the instance is created. By the way, it is possible to call an instance method later on in the constructor.
This solve your problem:
public Tandem (int misura, String modello, int ruote){
super(misura, modello);
this.ruote=ruote;
}

Why class instance itself has no public constructor?

While reading Reflection API i got this "Every Java Type has a class Instance And the class instance itself has no public Constructor" .
Now this is really confusing for me. Because what i have read till now says . All classes have constructor even when we don't specify any, we get constructor by default (even if the class is static) once we create its instance. Can someone explain me this in simple word
(to show even static class has constructor)
public class Reader1 {
private int pageNumber;
private class ReaderName1{
public int getPage(){
return pageNumber;
}
}
static class ReaderFound{
}
}
using javap
class Reader1$ReaderFound {
Reader1$ReaderFound();
}
It says: no public constructor. That doesn't mean it has no constructor at all. It does have a private constructor, which you can also create, as below given class, which also doesn't have a public constructor.
class Test {
private Test() { }
}
"Every Java Type has a class Instance And the class instance itself has no public Constructor" that's means the java.lang.Class has no public constructor because Only the JVM can create the java.lang.Class instance ,and every class Java Type has a java.lang.Class instance.i think that is reason why you were confused.
In Java you can suppress a public constructor by defining it private in the inheriting class - for Class this means:
public final class Class<T> {
private Class() {
//this constructor is private, no other constructor exists or will be generated
}
}
To create an instance of class there exist some factory methods, like Class.forName.
Directly cited from the official website. I hope it can help you.
The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
Class has no public constructor. Instead a Class object is constructed automatically by the Java Virtual Machine when a class loader invokes one of the defineClass methods and passes the bytes of a class file.
https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html

In Java, can you call a parent class's superclass constructor through the constructor of the child class of the parent class?

I know the wording is a bit confusing and strange, but bear with me, I have no clue how to phrase that any shorter.
Say you have a class called SuperBlah, and you inherited it in a class called Blah then you inherited Blah into a class called ChildBlah (So SuperBlah-Blah-ChildBlah). Would the super(); keyword used in the ChildBlah's constructor called the SuperBlah's constructor if Blah doesn't have a constructor?
To those of you who said no, then why does this work?
We have a class called BlusterBug that extends Critter class, and calls the super in the BlusterBug's constructor. Critter doesn't have a constructor, but the Class that Critter extends does have a constructor. (I purposefully omitted the rest of the code on the classes)
public class BlusterCritter extends Critter {
// instance vaiables
private int courageFactor;
private static final double DARKENING_FACTOR = 0.05;
// create a constructor(include what is necesary for parent)
public BlusterCritter(int c)
{
super();
courageFactor = c;
}
Then in the Critter class, it doesn't have any constructors!
public class Critter extends Actor// omitted all the code
{
/**
* A critter acts by getting a list of other actors, processing that list,
* getting locations to move to, selecting one of them, and moving to the
* selected location.
*/
public void act()
{
if (getGrid() == null)
return;
ArrayList<Actor> actors = getActors();
processActors(actors);
ArrayList<Location> moveLocs = getMoveLocations();
Location loc = selectMoveLocation(moveLocs);
makeMove(loc);
}
But then the Actor class has a constructor!
public class Actor
{
private Grid<Actor> grid;
private Location location;
private int direction;
private Color color;
/**
* Constructs a blue actor that is facing north.
*/
public Actor()
{
color = Color.BLUE;
direction = Location.NORTH;
grid = null;
location = null;
}
And the weirdest part? The program works perfectly fine and the compiler doesn't do catch any errors! How is this happening?
If Blah doesn't have any constructor, the compiler will generate an implicit no-argument constructor for Blah that is just super()--that is, it will call SuperBlah's constructor.
So when ChildBlah's constructor calls super(), it will call this implicit constructor that the compiler generated for Blah, which results in SuperBlah's constructor being called. So in some sense, I think the answer to your question is "yes".
But this only works if Blah has no constructors. (And in your actual code, Critter doesn't have any constructors, so it works.) If any other constructors are defined for Blah, but there's no accessible no-argument constructor, then there won't be an implicit no-argument constructor, and the result will be an error at compile time.
No, it won't. It will call the implicit default constructor in Blah.
If Blah defines other constructors (with parameters) but has no
default constructor, then this will generate a compilation error.
Also, note that constructors are not inherited
(if that relates in any way to your question/thoughts).
Yes it will. If Blah doesn't have any constructor, it will call default empty constructor and transitively it will call non-parametric SuperBlah constructor.
It will call Blah's constructor, throwing a compiler error if Blah doesn't have one.
No. Constructors aren't like methods in the respect of optional overriding by an intermediate class in the hierarchy. If an instance method of the super class is not implemented in the intermediate class, calling the method from the subclass via super.method() will invoke the superclass method. But a constructor for every class in the hierarchy must be called - you can't skip over the intermediate class's constructors.

Do I really need to define default constructor in java?

It works fine when constructors are not defined, but gives errors if I define a parameterized constructor and not a default one and not passing any values while creating an object. I thought constructors are predefined.
Why do I need to define a default constructor if I've defined a parameterized constructor? Ain't default constructor predefined?
A default (no-argument) constructor is automatically created only when you do not define any constructor yourself.
If you need two constructors, one with arguments and one without, you need to manually define both.
While all the answers above are correct, it's a bit difficult for new-comers to wrap it in their head. I will try to answer the question anew for new-comers.
The problem that Ayush was facing was in trying to instantiate an Object for a class via a no-arg constructor. This class however has one or more parameterized constructor and this results in a compile time error.
For example, let us create a class Student with a single parameterized constructor and try to instantiate it via the no-arg constructor.
public class Student {
private String name;
private int rollNo;
public Student(String name, int rollNo) {
this.name = name;
this.rollNo = rollNo;
}
public static void main(String[] args) {
// The line below will cause a compile error.
Student s = new Student();
// Error will be "The constuctor Student() is undefined"
}
}
Woha! But when we remove the public Student(String name, int rollNo)
constructor all-together, the error is gone and the code compiles.
The reason behind this seeming anomaly lies in the fact that Java only
provides us with the default (no-arg) constructor when we do not define any
constructor for that class on our own.
For example, the following class is supplied with a default contructor:
public class Student {
private String name;
private int rollNo;
}
becomes:
public class Student {
private String name;
private int rollNo;
//Default constructor added by Java.
public Student() {
super();
}
}
In other words, the moment we define any parameterized constructor,
we must also define a no-arg constructor if we want to instantiate
the object of that class via a no-arg constructor.
Also in case of inheritance, a sub-class with no constructors; is supplied one
default constructor. This default constructor supplied by Java as above calls the super class's no-arg constructor. If it can't find one, then it will throw an error.
So yes it's always a good choice to define a no-arg/default constructor.
Ref : Oracle Java Tutorial
A no-arg constructor is automatically inserted for you, if you don't write one. This means, if you write a constructor with some parameters, it will be the only constructor you have, so you must pass some values for those parameters to create an instance of it.
This is exactly the expected behavior.
Java automatically generates a default (no arguments constructors) for classes that don't have any constructor.
If you define another constructor (with arguments), default constructor will not be generated. If you still want one, you need to define it yourself.
Whenever you class is complied, if compiler does not find any valid constructor in class (default,parametrized) only then it will substitute auto generated default constructor for your class.
You must have noticed, you can create objects without any default constructor defined in your class, there comes the concept of auto-generated default constructor.As whenever object is created,default constructor is called.
But, If you define Parametrized constructor in your class, that means you restrict the objects to have that parameters
Example:Every employee must have an id.
So,at that time, Compiler will not insert any default constructor there as there is valid constructor in a class.If you need default constructor too, you have to define by yourself.
There is also one curious case when you must define non argument constructor.
As the other wrote, if you don't specify default constructor - Java will do it for you. It's good to understand how "default generated by Java" constructor looks like.
In fact it calls constructor of the super class and this is fine.
Let's now imagine one case.
You are creating Vehicle class:
public class Vehicle {
private String name;
private String engine;
public Vehicle(String name, String engine) {
this.name = name;
this.engine = engine;
}
public String makeNoise(){
return "Noiseee";
}
}
As we can see Vehicle class has got only one defined 2 arguments constructor.
Now let's create Car class which inheritates from Vehicle class:
public class Car extends Vehicle {
#Override
public String makeNoise() {
return "Wrrrrrrr....";
} }
Maybe it looks strange but only one reason why wouldn't it compile is fact that Java cannot create default constructor for Car class which call super Vehicle class. Vehicle class doesn't have no argument constructor and it cannot be generated automatically while 2 arg constructor already exists.
I know that it's very rare case, but I found it as a interesting to know.

How to create an "abstract field"?

I know abstract fields do not exist in java. I also read this question but the solutions proposed won't solve my problem. Maybe there is no solution, but it's worth asking :)
Problem
I have an abstract class that does an operation in the constructor depending on the value of one of its fields.
The problem is that the value of this field will change depending on the subclass.
How can I do so that the operation is done on the value of the field redefined by the subclass ?
If I just "override" the field in the subclass the operation is done on the value of the field in the abstract class.
I'm open to any solution that would ensure that the operation will be done during the instantiation of the subclass (ie putting the operation in a method called by each subclass in the constructor is not a valid solution, because someone might extend the abstract class and forget to call the method).
Also, I don't want to give the value of the field as an argument of the constructor.
Is there any solution to do that, or should I just change my design ?
Edit:
My subclasses are actually some tools used by my main program, so the constructor has to be public and take exactly the arguments with which they will be called:
tools[0]=new Hand(this);
tools[1]=new Pencil(this);
tools[2]=new AddObject(this);
(the subclasses are Hand, Pencil and AddObject that all extend the abstract class Tool)
That's why I don't want to change the constructor.
The solution I'm about to use is to slightly change the above code to:
tools[0]=new Hand(this);
tools[0].init();
tools[1]=new Pencil(this);
tools[1].init();
tools[2]=new AddObject(this);
tools[2].init();
and use an abstract getter to acces the field.
How about abstract getter/setter for field?
abstract class AbstractSuper {
public AbstractSuper() {
if (getFldName().equals("abc")) {
//....
}
}
abstract public void setFldName();
abstract public String getFldName();
}
class Sub extends AbstractSuper {
#Override
public void setFldName() {
///....
}
#Override
public String getFldName() {
return "def";
}
}
Also, I don't want to give the value
of the field as an argument of the
constructor.
Why not? It's the perfect solution. Make the constructor protected and offer no default constructor, and subclass implementers are forced to supply a value in their constructors - which can be public and pass a constant value to the superclass, making the parameter invisible to users of the subclasses.
public abstract class Tool{
protected int id;
protected Main main;
protected Tool(int id, Main main)
{
this.id = id;
this.main = main;
}
}
public class Pencil{
public static final int PENCIL_ID = 2;
public Pencil(Main main)
{
super(PENCIL_ID, main);
}
}
How about using the Template pattern?
public abstract class Template {
private String field;
public void Template() {
field = init();
}
abstract String init();
}
In this way, you force all subclasses to implement the init() method, which, since it being called by the constructor, will assign the field for you.
You can't do this in the constructor since the super class is going to be initialized before anything in the subclass. So accessing values that are specific to your subclass will fail in your super constructor.
Consider using a factory method to create your object. For instance:
private MyClass() { super() }
private void init() {
// do something with the field
}
public static MyClass create() {
MyClass result = new MyClass();
result.init();
return result;
}
You have an issue in this particular sample where MyClass can't be subclassed, but you could make the constructor protected. Make sure your base class has a public / protected constructor also for this code. It's just meant to illustrate you probably need two step initialization for what you want to do.
Another potential solution you could use is using a Factory class that creates all variants of this abstract class and you could pass the field into the constructor. Your Factory would be the only one that knows about the field and users of the Factory could be oblivious to it.
EDIT: Even without the factory, you could make your abstract base class require the field in the the constructor so all subclasses have to pass in a value to it when instantiated.
Also, I don't want to give the value of the field as an argument of the constructor.
Is there any solution to do that, or should I just change my design ?
Yes, I think you should change your design so that the subclass passes the value to the constructor. Since the subclass portion of your object isn't initialized until after the superclass constructor has returned, there's really no other clean way of doing it. Sure, this'd work:
class Super {
protected abstract int abstractField();
protected Super() { System.out.println("Abstract field: " + abstractField); }
}
class Sub {
protected int abstractField(){ return 1337; }
}
... since the implementation of abstractField() doesn't operate on object state. However, you can't guarantee that subclasses won't think it's a great idea to be a little more dynamic, and let abstractField() returns a non-constant value:
class Sub2 {
private int value = 5;
protected int abstractField(){ return value; }
public void setValue(int v){ value = v; }
}
class Sub3 {
private final int value;
public Sub3(int v){ value = v; }
protected int abstractField(){ return value; }
}
This does not do what you'd expect it to, since the initializers and constructors of subclasses run after those of the superclass. Both new Sub2() and new Sub3(42) would print Abstract field: 0 since the value fields haven't been initialized when abstractField() is called.
Passing the value to the constructor also has the added benefit that the field you store the value in can be final.
If the value is determined by the type of subclass, why do you need a field at all? You can have a simple abstract method which is implemented to return a different value for each subclass.
I think you need a factory (aka "virtual constructor") that can act on that parameter.
If it's hard to do in a given language, you're probably thinking about it incorrectly.
If I understand you correctly: You want the abstract class's constructor to do something depending on a field in the abstract class but which is set (hopefully) by the subclass?
If I got this wrong you can stop reading ...
But if I got it right then you are trying to do something that is impossible. The fields of a class are instantiated in lexical order (and so if you declare fields "below", or "after", the constructor then those will not be instantiated before the constructor is called). Additionally, the JVM runs through the entire superclass before doing anything with the subclass (which is why the "super()" call in a subclass's constructor needs to be the first instruction in the constructor ... because this is merely "advice" to the JVM on how to run the superclass's constructor).
So a subclass starts to instantiate only after the superclass has been fully instantiated (and the superclass's is constructor has returned).
And this is why you can't have abstract fields: An abstract field would not exist in the abstract class (but only in the subclass) and so is seriously(!) "off limits" to the super (abstract) class ... because the JVM can't bind anything references to the field (cause it doesn't exist).
Hope this helps.

Categories

Resources