I tried to research over this topic but could not find a clarity over this. Please help me in this.
In the constructor of a child-class you can call
super(/*params if needed*/);
in order to call its parent's constructor
You can use super() in your child class. You cannot create instance of abstract class(you might know that)
abstract class Parent{
Parent(){
System.out.println("Parent contructor!");
}
}
public class Child extends Parent{
public Child() {
super();
System.out.println("Child contructor!");
}
public static void main(String[] args) {
new Child();
}
}
Even if you do not specify super() in Child class, still the parent class constructor will be called because super() will be put by compiler in default constructor of Child class while generating the .class. If you only have parameterized constructor in Parent class then you will have to explicitly call the parent class constructor by super(..parameter) in your child class constructor . Hope this helps!
Something like this :
abstract class MyClass{
int val;
public MyClass( int val) {
this.val= val;
}
}
class Test extends MyClass{
public Test () {
super(2);
}
}
While you may not call upon a default constructor for an Abastract class, you can invoke the default constructor for the sub-class that embodies your abstract class.
For example:
abstract class Animal {
public Animal (){ ... }
abstract public String sound();
}
class Horse extends Animal{
public Horse(){
super()
}
#Override
public String sound(){
return "neigh";
}
}
class Dog extends Animal{
public Dog(){
super()
}
#Override
public String sound(){
return "woof";
}
}
It is not directly possible to make a new Animal. You can make new Dog-s and Horse-s with annomyously for (common) Type Animal example:
public Animal makeAnimals( Animal existingCreature )
throws InstantiationException, IllegalAccessException
{
return existingCreature.getClass.newInstance();
}
Will make a new instance of the concrete class you provided:
Dog fido = new Dog();
Horse hack = new Horse();
Dog puppy = makeAnimals( fido ); // new uninitialised Dog instance
Horse foal = makeAnimals( hack ); // new uninitialised Horse instance
Alternatively you can make an annomyous instance
Animal parrot = new Animal() {
#Override
public String sound(){
return "squawk";
}
}
As a way to make new animal types. If you were doing something for real like Animals it would probably be better to make a Parot subclass.
Related
I have an abstract class with several subclasses. In the abstract classe I have implemented a copy constructor. Now, I want to clone one of the subclasses using the copy constructor, how can I do this? Obviously I do not know in advance what subclass I have to clone.
Here is an example of what I want to do :
abstract class AbstractClass {
public AbstractClass(AbstractClass ac) {
this();
setX(ac.getX());
setY(ac.getY());
}
// Some setter and getter for X and Y variables
}
class SubclassA extends AbstractClass {
public SubclassA(SubclassA a) {
super(a);
}
}
class SubclassB extends AbstractClass {
public SubclassB(SubclassB b) {
super(b);
}
}
public class Main {
public static void main(String[] args) {
AbstractClass a = new SubclassA();
AbstractClass b = new SubclassB();
// Get a copy of "a" or "b" using the copy constructor of abstract class
AbstractClass newA = AbstractClass(a);
AbstractClass newB = AbstractClass(b);
}
}
There are only two ways I can see to create a copy of a given object without knowing at compile time which class to instantiate (as requested in the question):
Use Reflection to call the copy constructor of the desired class, assuming you know at runtime what the class is, and that said class has a suitable copy constructor.
Call some copy method of the base class which is overridden by subclasses.
The first solution is not good as it requires the use of Reflection. The second can be implemented with the clone()/Cloneable standard mechanism (despite its issues), or with some custom-defined "copy()" method. Your choice.
abstract class AbstractClass {
public AbstractClass(AbstractClass ac) {
this();
setX(ac.getX());
setY(ac.getY());
}
public abstract AbstractClass clone();
// Some setter and getter for X and Y variables
}
class SubclassA extends AbstractClass {
public SubclassA(SubclassA a) {
super(a);
}
#Override
public SubclassA clone() {
return new SubclassA(this);
}
}
class SubclassB extends AbstractClass {
public SubclassB(SubclassB b) {
super(b);
}
#Override
public SubclassB clone() {
return new SubclassB(this);
}
}
public class Main {
public static void main(String[] args) {
AbstractClass a = new SubclassA();
AbstractClass b = new SubclassB();
// Get a copy of "a" or "b" using the copy constructor of abstract class
AbstractClass newA = a.clone(); // is instance of SubclassA
AbstractClass newB = b.clone(); // is instance of SubclassB
}
}
The trick here is to use your own clone method (which has nothing to do with Cloneable what so ever). This method in turns calls the proper copy constructor.
This means you get all the advantages of a copy constructor, and you can be sure that no matter hwta subclass of AbstractClass you get, you always get a copy of the proper subclass without needing to call the constructor yourself.
Here is my question, super keyword is used only in case of inheritence ?
In terms of inheritence, what is the difference between this and super?
this refers to the current object, i.e. it's a reference
super refers to the super class, i.e. it's a scoping mechanism
The current object is the same object as the object of the superclass. If you have a Dog that extends Animal, and do new Dog() then you create 1 object, and this object is both the Animal instance and the Dog instance.
Here's an example
class Dog extends Animal {
public void treatWell(DogSpa spa) {
spa.takeCareOf(this); // pass this object to the spa
}
public void makeSound() {
System.out.println("bark");
super.makeSound(); // call makeSound in Animal scope
}
}
this refers to current object, while super refers to current object's parent class.
Consider this:
class Parent {
protected int value;
public void test() {
//print parent
}
}
class Child extends Parent {
public void test() {
//print child
}
private void someMethod() {
this.test();//will print child
super.test();//will print parent
}
}
Say I've made an abstract class called animal, and then I make a subclass called dogs which extends animal. The animal class has a constructor method written inside. If I decide to instantiate a "dog" object, will the animal classes's constructor automatically be called as well?
If someone could clarify, and further expand on this a bit, it'd be greatly appreciated!
Yes , The constructor of an abstract class can be called. why not? Use super() from subclass to call the super class argument constructor(s). If you dont use super(), then by default the no-arg constructor of super class will be called.
If you call
Dog dog = new Dog();
By default the super class default constructor[no-arg constructor] will be called.
If you call
Dog dog = new Dog("doggie1");
Unless you explicitly call super() inside the one argument constructor of Dog, the default super class constructor will not be called.
Try it..
Edit: If you don't call super() inside the one argument constructor of Dog, then also the default super class constructor will be called.
If you want to explicitly call the argument constructor , say one argument constructor of the super class, you have to explicitly make the call super("value");
Animal() {
System.out.println("Animal superconstructor");
}
Edit 02:
Sample program and output
(1)
public class SubClass extends SuperClass {
SubClass(String str) {
super(str);
}
SubClass() {
}
public static void main(String[] args) {
new SubClass("hello");
}
}
abstract class SuperClass {
SuperClass() {
System.out.println("I am SuperClass()");
}
SuperClass(String str) {
System.out.println("I am SuperClass(String str)");
}
}
//output: I am SuperClass(String str)
(2)
public class SubClass extends SuperClass {
SubClass(String str) {
}
SubClass() {
}
public static void main(String[] args) {
new SubClass("hello");
}
}
abstract class SuperClass {
SuperClass() {
System.out.println("I am SuperClass()");
}
SuperClass(String str) {
System.out.println("I am SuperClass(String str)");
}
}
//output: I am SuperClass()
(3)
public class SubClass extends SuperClass {
SubClass(String str) {
}
SubClass() {
}
public static void main(String[] args) {
new SubClass();
}
}
abstract class SuperClass {
SuperClass() {
System.out.println("I am SuperClass()");
}
SuperClass(String str) {
System.out.println("I am SuperClass(String str)");
}
}
// output: I am SuperClass()
If Animal has a no-arg constructor, then Animal's subclasses will call it automatically. Otherwise, the compiler will complain. In such a case, you have to call super() explicitly with the appropriate parameters for the Animal constructor you wish to use.
If I remember correctly, the abstract class's constructor (only the default constructor) is called by default only in the instance of the default constructor. To call the other constructors of the inherited class, a super() call needs to be made inside the constructors of the subclass.
I have two objects which use really similar methods, save for one line. For example:
public class Cat extends Animal
public class Dog extends Animal
And they both use a breed method in the abstract class Animal. One calls new Dog(), and the other new Cat(). Right now I just have it declared as abstract public void breed(); in Animal, but is there a way I can generalize it so I don't have to make it an abstract method to be overridden?
There are many ways to do this, assuming by breed you mean "create children of me."
Reflection
First is to use reflection. If you have a no-args constructor for your classes, this is as easy as calling Class.newInstance:
public Animal breed() {
try {
return (Animal) getClass().newInstance();
} catch (Exception ex) {
// TODO Log me
return null;
}
}
If you don't have a no-args constructor in all your subclasses, you'll have to have a uniform constructor across all your subclasses. For example, if you have Cat(int, String) and Dog(int, String), then you need to get the constructor via Class.getConstructor and invoke newInstance on that:
return (Animal) getClass().getConstructor(int.class, String.class).newInstance(0, "Unnamed");
int and String here may be age and name, for example. This is how you do this with reflection.
Providers
Another way is to use this simple interface:
public interface Provider<T> {
T create();
}
Then have your abstract class take an instance of this in its constructor:
public abstract class Animal {
private final Provider<Animal> animalProvider;
protected Animal( ... , Provider<Animal> animalProvider) {
// ...
this.animalProvider = animalProvider;
}
public Animal breed() {
return animalProvider.create();
}
}
Then your subclasses will pass a Provider<Animal> to the superclass which will create new instances of the subclass:
public class Dog extends Animal {
public Dog( ... ) {
super( ... , new DogProvider());
// ...
}
private static class DogProvider implements Provider<Animal> {
public Animal create() {
return new Dog( ... );
}
}
}
Do the same for other subclasses as well.
Note: if by breed you mean "get the type of me," then you should edit your question to say so. If this is what you meant, then this is a viable solution:
public abstract class Animal {
protected final Breed breed;
protected Animal( ... , Breed breed) {
// ...
this.breed = breed;
}
public Breed getBreed() {
return breed;
}
}
I recommend following the get/set conventions for data container methods. Java has bean classes designed to handle these naming conventions, and it's more or less a standard across many platforms. For your subclasses:
public class Dog extends Animal {
public Dog( ... ) {
super( ... , new Breed( ... ));
// ...
}
}
Actually, yes you can. You need to use reflection so performance could be a little iffy, but this (untested) should work:
public abstract class Animal{
public Animal breed(){
return getClass().newInstance();
}
//other methods
}
This will return a new instance of the actual calling type, not the type of Animal (where it's implemented).
This is actually somewhat similar to the Prototype Pattern. Although in this case you're creating a new instance, not copying an existing instance.
Edit
As #FrankPavageau pointed out in the comments, rather than masking an exception in the constructor, you can achieve the same result by using
public abstract class Animal{
public Animal breed(){
return getClass().getConstructor().newInstance();
}
//other methods
}
Which will wrap any exception thrown in an InvocationTargetException which is a bit cleaner and probably easier to debug. Thanks #FrankPavageau for that suggestion.
No there isn't. You will have to have something like what you have done as below
I think you want to have in your abstract class
public abstract Breed getBreed();
and then in each sub class have
public Breed getBreed() {
return new DogBreed();
}
and a similar one returning cat.
or
Have a protected field in the Animal class called breed. This could then be initialised in each of the subclasses. This would remove the need for an abstract method. For example
public abstract class Animal {
Breed breed;
...
}
and then in Dog have
public class Dog extends Animal {
public Dog() {
breed = new DogBreed();
}
}
and have something similar to Cat.
It might be worth you while also passing in the breed to the Dog/Cat ctor so that you can create Dog objects of different breeds rather than restricting your model to just one breed of Dog
I am not sure Breed is necessarily modelled correctly in your example. Do you really want new Dog() to be a breed? Or do you mean type? In which case it is just an animal and the abstract method returning animal is the way to go.
Why does this java code produce StackOverflowError? I understand that this somehow connected with recursive generic type parameter. But I don't understand clear the whole mechanism.
public class SomeClass<T extends SomeClass> {
SomeClass() {
new SomeClassKiller();
}
private class SomeClassKiller extends SomeClass<T> {
}
public static void main(String[] args) {
new SomeClass();
}
}
The generic part doesn't matter - nor does it really matter that the class is nested. Look at this mostly-equivalent pair of classes and it should be more obvious:
public class SuperClass
{
public SuperClass()
{
new SubClass();
}
}
public class SubClass extends SuperClass
{
public SubClass()
{
super();
}
}
So the subclass constructor calls the superclass constructor - which then creates a new subclass, which calls into the superclass constructor, which creates a new subclass, etc... bang!
Here it is invoking one constructor from another and from it the previous one, cyclic constructor chain, see the comments below
public class SomeClass<T extends SomeClass> {
SomeClass() {//A
new SomeClassKiller();// calls B
}
private class SomeClassKiller extends SomeClass<T> {//B
//calls A
}
public static void main(String[] args) {
new SomeClass(); //calls A
}
}
This is because of the Recursive constructor calls happening between the classes SomeClass and
SomeClassKiller.
public class SomeClass<T extends SomeClass> {
SomeClass() {
new SomeClassKiller();
}
private class SomeClassKiller extends SomeClass<T> {
public SomeClassKiller()
{
super(); //calls the constructor of SomeClass
}
}
public static void main(String[] args) {
new SomeClass();
}
}
The code produced by the compiler is something like this, so when u create an object it recursivly calls the SomeClass and SomeClassKiller for ever.
Constructors are invoked top-to-bottom, that is if a class A derives from B, A's constructors will first invoke the parent constructor (B).
In you case, new SomeClassKiller() recursively calls the constructor of SomeClass which in turn constructs another SomeClassKiller … there it is.
The main() method is creating a new instance of SomeClass which calls the SomeClass constructor that creates a new instance of SomeClassKiller that by default calls the parent constructor and the stackoverflow occurs.
To avoid the stackoverflow. Change the code to look as follows:
public class SomeClass<T extends SomeClass> {
SomeClass() {
new SomeClassKiller();
}
private class SomeClassKiller extends SomeClass<T> {
public SomeClassKiller(){
//super(); does this by default, but is now commented out and won't be called.
}
}
public static void main(String[] args) {
new SomeClass();
}
}