Subinstances sharing a common superinstance - java

I have a class Super and several subclases Sub1, Sub2,...
Is there a way to instantiate objects sub1, sub2 that would share the same super instance?
The situation comes from an inner nested class configuration like this:
Super{
superFields...
Sub1{...}
Sub2{...}
........
}
But the inner claeses have grown too much, and I woud feel more confortable having them in separate files. They need to share the same instance of superFields, so my question.

Inner classes are implemented by having the superclass as argument of all their constructors.
So that's what you can do as well:
public class Sub1 {
private Superclass superclass;
public Sub1(Superclass superclass) {
this.superclass = superclass;
}
}
and whenever you want to instantiate the subclass from within the superclass:
Sub1 sub = new Sub1(this);

You could easily break out your inner classes and have each of them reference an instance of the current containing class. When you construct your new classes, you can pass in the same instance to both, and then the new classes can use the accessors to get at the fields of the containing class.
class Super {
String fieldA;
int fieldB;
...
}
in your new files, something like the following:
class Sub1{
Super myOldContainingClass;
Sub1(Super myOldContainingClass) {
this.myOldContainingClass = myOldContainingClass;
}
void myMethod() {
System.out.println(myOldContainingClass.getFieldA());
System.out.println(myOldContainingClass.getFieldB());
}
}

Related

Why is it ok to do "new" to an abstract class? [duplicate]

During one of my interview, I was asked "If we can instantiate an abstract class?"
My reply was "No. we can't". But, interviewer told me "Wrong, we can."
I argued a bit on this. Then he told me to try this myself at home.
abstract class my {
public void mymethod() {
System.out.print("Abstract");
}
}
class poly {
public static void main(String a[]) {
my m = new my() {};
m.mymethod();
}
}
Here, I'm creating instance of my class and calling method of abstract class. Can anyone please explain this to me? Was I really wrong during my interview?
Here, i'm creating instance of my class
No, you are not creating the instance of your abstract class here. Rather you are creating an instance of an anonymous subclass of your abstract class. And then you are invoking the method on your abstract class reference pointing to subclass object.
This behaviour is clearly listed in JLS - Section # 15.9.1: -
If the class instance creation expression ends in a class body, then
the class being instantiated is an anonymous class. Then:
If T denotes a class, then an anonymous direct subclass of the class named by T is declared. It is a compile-time error if the
class denoted by T is a final class.
If T denotes an interface, then an anonymous direct subclass of Object that implements the interface named by T is declared.
In either case, the body of the subclass is the ClassBody given in the class instance creation expression.
The class being instantiated is the anonymous subclass.
Emphasis mine.
Also, in JLS - Section # 12.5, you can read about the Object Creation Process. I'll quote one statement from that here: -
Whenever a new class instance is created, memory space is allocated
for it with room for all the instance variables declared in the class
type and all the instance variables declared in each superclass of the
class type, including all the instance variables that may be hidden.
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:
You can read about the complete procedure on the link I provided.
To practically see that the class being instantiated is an Anonymous SubClass, you just need to compile both your classes. Suppose you put those classes in two different files:
My.java:
abstract class My {
public void myMethod() {
System.out.print("Abstract");
}
}
Poly.java:
class Poly extends My {
public static void main(String a[]) {
My m = new My() {};
m.myMethod();
}
}
Now, compile both your source files:
javac My.java Poly.java
Now in the directory where you compiled the source code, you will see the following class files:
My.class
Poly$1.class // Class file corresponding to anonymous subclass
Poly.class
See that class - Poly$1.class. It's the class file created by the compiler corresponding to the anonymous subclass you instantiated using the below code:
new My() {};
So, it's clear that there is a different class being instantiated. It's just that, that class is given a name only after compilation by the compiler.
In general, all the anonymous subclasses in your class will be named in this fashion:
Poly$1.class, Poly$2.class, Poly$3.class, ... so on
Those numbers denote the order in which those anonymous classes appear in the enclosing class.
The above instantiates an anonymous inner class which is a subclass of the my abstract class. It's not strictly equivalent to instantiating the abstract class itself. OTOH, every subclass instance is an instance of all its super classes and interfaces, so most abstract classes are indeed instantiated by instantiating one of their concrete subclasses.
If the interviewer just said "wrong!" without explaining, and gave this example, as a unique counterexample, I think he doesn't know what he's talking about, though.
= my() {}; means that there's an anonymous implementation, not simple instantiation of an object, which should have been : = my(). You can never instantiate an abstract class.
Just observations you could make:
Why poly extends my? This is useless...
What is the result of the compilation? Three files: my.class, poly.class and poly$1.class
If we can instantiate an abstract class like that, we can instantiate an interface too... weird...
Can we instantiate an abstract class?
No, we can't. What we can do is, create an anonymous class (that's the third file) and instantiate it.
What about a super class instantiation?
The abstract super class is not instantiated by us but by java.
EDIT: Ask him to test this
public static final void main(final String[] args) {
final my m1 = new my() {
};
final my m2 = new my() {
};
System.out.println(m1 == m2);
System.out.println(m1.getClass().toString());
System.out.println(m2.getClass().toString());
}
output is:
false
class my$1
class my$2
You can simply answers, in just one line
No, you can never instance Abstract Class
But, interviewer still not agree, then you can tell him/her
all you can do is, you can create an Anonymous Class.
And, according to Anonymous class, class declared and instantiate at the same place/line
So, it might be possible that, interviewer would be interested to check your confidence level and how much you know about the OOPs .
The technical part has been well-covered in the other answers, and it mainly ends in:
"He is wrong, he doesn't know stuff, ask him to join SO and get it all cleared :)"
I would like to address the fact(which has been mentioned in other answers) that this might be a stress-question and is an important tool for many interviewers to know more about you and how do you react to difficult and unusual situations. By giving you incorrect codes, he probably wanted to see if you argued back. To know whether you have the confidence to stand up against your seniors in situations similar to this.
P.S: I don't know why but I have a feeling that the interviewer has read this post.
Abstract classes cannot be instantiated, but they can be subclassed. See This Link
The best example is
Although Calender class has a abstract method getInstance(), but when you say Calendar calc=Calendar.getInstance();
calc is referring to the class instance of class GregorianCalendar as "GregorianCalendar extends Calendar "
Infact annonymous inner type allows you to create a no-name subclass of the abstract class and an instance of this.
Technical Answer
Abstract classes cannot be instantiated - this is by definition and design.
From the JLS, Chapter 8. Classes:
A named class may be declared abstract (§8.1.1.1) and must be declared
abstract if it is incompletely implemented; such a class cannot be
instantiated, but can be extended by subclasses.
From JSE 6 java doc for Classes.newInstance():
InstantiationException - if this Class represents an abstract class, an interface, an array
class, a primitive type, or void; or if the class has no nullary constructor; or if the
instantiation fails for some other reason.
You can, of course, instantiate a concrete subclass of an abstract class (including an anonymous subclass) and also carry out a typecast of an object reference to an abstract type.
A Different Angle On This - Teamplay & Social Intelligence:
This sort of technical misunderstanding happens frequently in the real world when we deal with complex technologies and legalistic specifications.
"People Skills" can be more important here than "Technical Skills". If competitively and aggressively trying to prove your side of the argument, then you could be theoretically right, but you could also do more damage in having a fight / damaging "face" / creating an enemy than it is worth. Be reconciliatory and understanding in resolving your differences. Who knows - maybe you're "both right" but working off slightly different meanings for terms??
Who knows - though not likely, it is possible the interviewer deliberately introduced a small conflict/misunderstanding to put you into a challenging situation and see how you behave emotionally and socially. Be gracious and constructive with colleagues, follow advice from seniors, and follow through after the interview to resolve any challenge/misunderstanding - via email or phone call. Shows you're motivated and detail-oriented.
It is a well-established fact that abstract class can not be instantiated as everyone answered.
When the program defines anonymous class, the compiler actually creates a new class with different name (has the pattern EnclosedClassName$n where n is the anonymous class number)
So if you decompile this Java class you will find the code as below:
my.class
abstract class my {
public void mymethod()
{
System.out.print("Abstract");
}
}
poly$1.class (the generated class of the "anonymous class")
class poly$1 extends my
{
}
ploly.cass
public class poly extends my
{
public static void main(String[] a)
{
my m = new poly.1(); // instance of poly.1 class NOT the abstract my class
m.mymethod();
}
}
About Abstract Classes
Cannot create object of an abstract class
Can create variables (can behave like datatypes)
If a child can not override at least of one abstract method of the parent, then child also becomes abstract
Abstract classes are useless without child classes
The purpose of an abstract class is to behave like a base. In inheritance hierarchy you will see abstract classes towards the top.
No, you can't instantite an abstract class.We instantiate only anonymous class.In abstract class we declare abstract methods and define concrete methods only.
Extending a class doesn't mean that you are instantiating the class. Actually, in your case you are creating an instance of the subclass.
I am pretty sure that abstract classes do not allow initiating. So, I'd say no: you can't instantiate an abstract class. But, you can extend it / inherit it.
You can't directly instantiate an abstract class. But it doesn't mean that you can't get an instance of class (not actully an instance of original abstract class) indirectly. I mean you can not instantiate the orginial abstract class, but you can:
Create an empty class
Inherit it from abstract class
Instantiate the dervied class
So you get access to all the methods and properties in an abstract class via the derived class instance.
It's impossible to instantiate an abstract class.
What you really can do, has implement some common methods in an abstract class and let others unimplemented (declaring them abstract) and let the concrete descender implement them depending on their needs.
Then you can make a factory, which returns an instance of this abstract class (actually his implementer). In the factory you then decide, which implementer to choose. This is known as a factory design pattern:
public abstract class AbstractGridManager {
private LifecicleAlgorithmIntrface lifecicleAlgorithm;
// ... more private fields
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
//Methods common to all implementors
public Grid calculateNextLifecicle(Grid grid){
return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
}
public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
return lifecicleAlgorithm;
}
public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
this.lifecicleAlgorithm = lifecicleAlgorithm;
}
// ... more common logic and getters-setters pairs
}
The concrete implementer only needs to implement the methods declared as abstract, but will have access to the logic implemented in those classes in an abstract class, which are not declared abstract:
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public Grid initGrid(String filePath) {
List<Cell> cells = new ArrayList<>();
char[] chars;
File file = new File(filePath); // for example foo.txt
// ... more logic
return grid;
}
}
Then finally the factory looks something like this:
public class GridManagerFactory {
public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
AbstractGridManager manager = null;
// input from the command line
if(args.length == 2){
CommandLineGridManager clManager = new CommandLineGridManager();
clManager.setWidth(Integer.parseInt(args[0]));
clManager.setHeight(Integer.parseInt(args[1]));
// possibly more configuration logic
...
manager = clManager;
}
// input from the file
else if(args.length == 1){
FileInputGridManager fiManager = new FileInputGridManager();
fiManager.setFilePath(args[0]);
// possibly more method calls from abstract class
...
manager = fiManager ;
}
//... more possible concrete implementors
else{
manager = new CommandLineGridManager();
}
manager.setLifecicleAlgorithm(lifecicleAlgorithm);
return manager;
}
}
The receiver of AbstractGridManager would call the methods on him and get the logic, implemented in the concrete descender (and partially in the abstract class methods) without knowing what is the concrete implementation he got. This is also known as inversion of control or dependency injection.
You can say: we can't instantiate an abstract class, but we can use new keyword to create an anonymous class instance by just adding {} as implement body at the the end of the abstract class.
No, we can't create the object of abstract class, but create the reference variable of the abstract class. The reference variable is used to refer to the objects of derived classes (Sub classes of Abstract class)
Here is the example that illustrates this concept
abstract class Figure {
double dim1;
double dim2;
Figure(double a, double b) {
dim1 = a;
dim2 = b;
}
// area is now an abstract method
abstract double area();
}
class Rectangle extends Figure {
Rectangle(double a, double b) {
super(a, b);
}
// override area for rectangle
double area() {
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
}
class Triangle extends Figure {
Triangle(double a, double b) {
super(a, b);
}
// override area for right triangle
double area() {
System.out.println("Inside Area for Triangle.");
return dim1 * dim2 / 2;
}
}
class AbstractAreas {
public static void main(String args[]) {
// Figure f = new Figure(10, 10); // illegal now
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
Figure figref; // this is OK, no object is created
figref = r;
System.out.println("Area is " + figref.area());
figref = t;
System.out.println("Area is " + figref.area());
}
}
Here we see that we cannot create the object of type Figure but we can create a reference variable of type Figure. Here we created a reference variable of type Figure and Figure Class reference variable is used to refer to the objects of Class Rectangle and Triangle.
Actually we can not create an object of an abstract class directly. What we create is a reference variable of an abstract call. The reference variable is used to Refer to the object of the class which inherits the Abstract class i.e. the subclass of the abstract class.

java, initialize SubClass from SuperClass

public class Base {
//long list of attributes
// no Constructor using fields
// no init methode
// i cannot change this class
}
now i extended the Base Class like:
public class subClass extends Base{
private boolean selected;
...
getter und setter
...
}
i become a list of Base object List<Base>
but i need the same list but as List<SubClass>
is there a way to initialize the Subclass from the Base Class?
example:
for(Base b: list){
SubClass sub = (SubClass)b; // Thats wrong i know
if(...){
sub.setSelected(true);
}
newList.add(sub);
}
i try to avoid the manual init of each Attribute of the Base Class to the SubClass
i update my Question as requested in the Comments:
the Design above is just an example. my QUESTIN EXACTLY IS:
why converting BaseClass into SubClass (sence Subclass extends BaseClass) is not Possible? why Java dosn't allow me to do the following:
example:
Class Base{
private String name;
.....
}
Class SubClass extends Base{
private String title;
}
then
Base b = DBController.getById(...);
SubClass sub = (SubClass)b;
after that the Object sub should have the Attribute Name from the Object b
and the title Attribute is null
why is this not the case in java?
sorry for my bad english,
thanks
If you have a List<Base>, then you cannot convert it to a List<SubClass>. This is mainly because the list may not contain instances of SubClass. The best you can do is:
List<SubClass> newList = new List<SubClass>();
for(Base b: list){
if (b instanceof SubClass) {
SubClass sub = (SubClass)b;
. . .
newList.add(sub);
}
}
Generally, however, when you find yourself doing this kind of thing, there's something wrong with your design. You might want to avoid subclassing Base and using composition instead.
EDIT Based on your comments, it sounds like you want to construct a list of SubClass instances using a list of Base instances as a start. One approach is to define a constructor for SubClass that takes a Base as an argument.
public class SubClass extends Base{
private boolean selected;
public SubClass() {
// default constructor
}
public SubClass(Base original) {
// copy constructor -- initialize some fields from
// values in original, others with default values
}
...
getter und setter
...
}
Then you can construct your new list with:
List<SubClass> newList = new List<SubClass>();
for(Base b: list){
SubClass sub = new SubClass(b);
. . .
newList.add(sub);
}
There is a way: Various Java Beans spec based manipulation.
For example:
Commons BeanUtils
for( Base base: list ){
SubClass sub = new SubClass();
PropertyUtilsBean.copyProperties( sub, base );
if(...){
sub.setSelected(true);
}
newList.add(sub);
}
This works based on get/setters of the same name. Doesn't copy internal fields.
If you needed to copy internal fields, it's actually not that hard to implement using javax.lang.reflect.
You appear to have a class with a lot of attributes and no easy way of setting them all. You have now run in to a problem where you need a class with an additional attribute but you have to deal with that mess of a base class.
I suggest that, instead of creating a subclass and casting, you create a wrapper class around the ugly one:
public class BigDumbClass {
// A lot of attributes
// No Constructor
// No init method
}
public class Wrapper {
private BigDumbClass base;
private boolean selected;
public Wrapper(BigDumbClass base) {
this.base = base;
this.selected = false;
}
//getters and setters
}
Now when you have to create that new list you can wrap everything in the old list
List<BigDumbClass> oldList = someData();
List<Wrapper> wraps = aNewList();
for (BigDumbClass bigDumb : oldList) {
Wrapper wrap = new Wrapper(bigDumb);
if (someCondition()) {
wrap.setSelected(true);
}
wraps.add(wrap);
}
Ideally, BigDumbClass would implement an interface that Wrapper could also implement, allowing the wrapper to defer all of the calls to the instance it has wrapped.
public class BigDumbClass implements SharedInterface {
// All the stuff outlined above
}
public class Wrapper implements SharedInterface {
// All the stuff outlined above
// Methods defined in SharedInterface
public void doSomething() {
base.doSomething();
}
}
Otherwise, you can provide a getter to the instance and access it directly.
BigDumbClass base = wrapper.getBase();
base.doSomething();

Can we instantiate an abstract class?

During one of my interview, I was asked "If we can instantiate an abstract class?"
My reply was "No. we can't". But, interviewer told me "Wrong, we can."
I argued a bit on this. Then he told me to try this myself at home.
abstract class my {
public void mymethod() {
System.out.print("Abstract");
}
}
class poly {
public static void main(String a[]) {
my m = new my() {};
m.mymethod();
}
}
Here, I'm creating instance of my class and calling method of abstract class. Can anyone please explain this to me? Was I really wrong during my interview?
Here, i'm creating instance of my class
No, you are not creating the instance of your abstract class here. Rather you are creating an instance of an anonymous subclass of your abstract class. And then you are invoking the method on your abstract class reference pointing to subclass object.
This behaviour is clearly listed in JLS - Section # 15.9.1: -
If the class instance creation expression ends in a class body, then
the class being instantiated is an anonymous class. Then:
If T denotes a class, then an anonymous direct subclass of the class named by T is declared. It is a compile-time error if the
class denoted by T is a final class.
If T denotes an interface, then an anonymous direct subclass of Object that implements the interface named by T is declared.
In either case, the body of the subclass is the ClassBody given in the class instance creation expression.
The class being instantiated is the anonymous subclass.
Emphasis mine.
Also, in JLS - Section # 12.5, you can read about the Object Creation Process. I'll quote one statement from that here: -
Whenever a new class instance is created, memory space is allocated
for it with room for all the instance variables declared in the class
type and all the instance variables declared in each superclass of the
class type, including all the instance variables that may be hidden.
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:
You can read about the complete procedure on the link I provided.
To practically see that the class being instantiated is an Anonymous SubClass, you just need to compile both your classes. Suppose you put those classes in two different files:
My.java:
abstract class My {
public void myMethod() {
System.out.print("Abstract");
}
}
Poly.java:
class Poly extends My {
public static void main(String a[]) {
My m = new My() {};
m.myMethod();
}
}
Now, compile both your source files:
javac My.java Poly.java
Now in the directory where you compiled the source code, you will see the following class files:
My.class
Poly$1.class // Class file corresponding to anonymous subclass
Poly.class
See that class - Poly$1.class. It's the class file created by the compiler corresponding to the anonymous subclass you instantiated using the below code:
new My() {};
So, it's clear that there is a different class being instantiated. It's just that, that class is given a name only after compilation by the compiler.
In general, all the anonymous subclasses in your class will be named in this fashion:
Poly$1.class, Poly$2.class, Poly$3.class, ... so on
Those numbers denote the order in which those anonymous classes appear in the enclosing class.
The above instantiates an anonymous inner class which is a subclass of the my abstract class. It's not strictly equivalent to instantiating the abstract class itself. OTOH, every subclass instance is an instance of all its super classes and interfaces, so most abstract classes are indeed instantiated by instantiating one of their concrete subclasses.
If the interviewer just said "wrong!" without explaining, and gave this example, as a unique counterexample, I think he doesn't know what he's talking about, though.
= my() {}; means that there's an anonymous implementation, not simple instantiation of an object, which should have been : = my(). You can never instantiate an abstract class.
Just observations you could make:
Why poly extends my? This is useless...
What is the result of the compilation? Three files: my.class, poly.class and poly$1.class
If we can instantiate an abstract class like that, we can instantiate an interface too... weird...
Can we instantiate an abstract class?
No, we can't. What we can do is, create an anonymous class (that's the third file) and instantiate it.
What about a super class instantiation?
The abstract super class is not instantiated by us but by java.
EDIT: Ask him to test this
public static final void main(final String[] args) {
final my m1 = new my() {
};
final my m2 = new my() {
};
System.out.println(m1 == m2);
System.out.println(m1.getClass().toString());
System.out.println(m2.getClass().toString());
}
output is:
false
class my$1
class my$2
You can simply answers, in just one line
No, you can never instance Abstract Class
But, interviewer still not agree, then you can tell him/her
all you can do is, you can create an Anonymous Class.
And, according to Anonymous class, class declared and instantiate at the same place/line
So, it might be possible that, interviewer would be interested to check your confidence level and how much you know about the OOPs .
The technical part has been well-covered in the other answers, and it mainly ends in:
"He is wrong, he doesn't know stuff, ask him to join SO and get it all cleared :)"
I would like to address the fact(which has been mentioned in other answers) that this might be a stress-question and is an important tool for many interviewers to know more about you and how do you react to difficult and unusual situations. By giving you incorrect codes, he probably wanted to see if you argued back. To know whether you have the confidence to stand up against your seniors in situations similar to this.
P.S: I don't know why but I have a feeling that the interviewer has read this post.
Abstract classes cannot be instantiated, but they can be subclassed. See This Link
The best example is
Although Calender class has a abstract method getInstance(), but when you say Calendar calc=Calendar.getInstance();
calc is referring to the class instance of class GregorianCalendar as "GregorianCalendar extends Calendar "
Infact annonymous inner type allows you to create a no-name subclass of the abstract class and an instance of this.
Technical Answer
Abstract classes cannot be instantiated - this is by definition and design.
From the JLS, Chapter 8. Classes:
A named class may be declared abstract (§8.1.1.1) and must be declared
abstract if it is incompletely implemented; such a class cannot be
instantiated, but can be extended by subclasses.
From JSE 6 java doc for Classes.newInstance():
InstantiationException - if this Class represents an abstract class, an interface, an array
class, a primitive type, or void; or if the class has no nullary constructor; or if the
instantiation fails for some other reason.
You can, of course, instantiate a concrete subclass of an abstract class (including an anonymous subclass) and also carry out a typecast of an object reference to an abstract type.
A Different Angle On This - Teamplay & Social Intelligence:
This sort of technical misunderstanding happens frequently in the real world when we deal with complex technologies and legalistic specifications.
"People Skills" can be more important here than "Technical Skills". If competitively and aggressively trying to prove your side of the argument, then you could be theoretically right, but you could also do more damage in having a fight / damaging "face" / creating an enemy than it is worth. Be reconciliatory and understanding in resolving your differences. Who knows - maybe you're "both right" but working off slightly different meanings for terms??
Who knows - though not likely, it is possible the interviewer deliberately introduced a small conflict/misunderstanding to put you into a challenging situation and see how you behave emotionally and socially. Be gracious and constructive with colleagues, follow advice from seniors, and follow through after the interview to resolve any challenge/misunderstanding - via email or phone call. Shows you're motivated and detail-oriented.
It is a well-established fact that abstract class can not be instantiated as everyone answered.
When the program defines anonymous class, the compiler actually creates a new class with different name (has the pattern EnclosedClassName$n where n is the anonymous class number)
So if you decompile this Java class you will find the code as below:
my.class
abstract class my {
public void mymethod()
{
System.out.print("Abstract");
}
}
poly$1.class (the generated class of the "anonymous class")
class poly$1 extends my
{
}
ploly.cass
public class poly extends my
{
public static void main(String[] a)
{
my m = new poly.1(); // instance of poly.1 class NOT the abstract my class
m.mymethod();
}
}
About Abstract Classes
Cannot create object of an abstract class
Can create variables (can behave like datatypes)
If a child can not override at least of one abstract method of the parent, then child also becomes abstract
Abstract classes are useless without child classes
The purpose of an abstract class is to behave like a base. In inheritance hierarchy you will see abstract classes towards the top.
No, you can't instantite an abstract class.We instantiate only anonymous class.In abstract class we declare abstract methods and define concrete methods only.
Extending a class doesn't mean that you are instantiating the class. Actually, in your case you are creating an instance of the subclass.
I am pretty sure that abstract classes do not allow initiating. So, I'd say no: you can't instantiate an abstract class. But, you can extend it / inherit it.
You can't directly instantiate an abstract class. But it doesn't mean that you can't get an instance of class (not actully an instance of original abstract class) indirectly. I mean you can not instantiate the orginial abstract class, but you can:
Create an empty class
Inherit it from abstract class
Instantiate the dervied class
So you get access to all the methods and properties in an abstract class via the derived class instance.
It's impossible to instantiate an abstract class.
What you really can do, has implement some common methods in an abstract class and let others unimplemented (declaring them abstract) and let the concrete descender implement them depending on their needs.
Then you can make a factory, which returns an instance of this abstract class (actually his implementer). In the factory you then decide, which implementer to choose. This is known as a factory design pattern:
public abstract class AbstractGridManager {
private LifecicleAlgorithmIntrface lifecicleAlgorithm;
// ... more private fields
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
//Methods common to all implementors
public Grid calculateNextLifecicle(Grid grid){
return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
}
public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
return lifecicleAlgorithm;
}
public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
this.lifecicleAlgorithm = lifecicleAlgorithm;
}
// ... more common logic and getters-setters pairs
}
The concrete implementer only needs to implement the methods declared as abstract, but will have access to the logic implemented in those classes in an abstract class, which are not declared abstract:
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public Grid initGrid(String filePath) {
List<Cell> cells = new ArrayList<>();
char[] chars;
File file = new File(filePath); // for example foo.txt
// ... more logic
return grid;
}
}
Then finally the factory looks something like this:
public class GridManagerFactory {
public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
AbstractGridManager manager = null;
// input from the command line
if(args.length == 2){
CommandLineGridManager clManager = new CommandLineGridManager();
clManager.setWidth(Integer.parseInt(args[0]));
clManager.setHeight(Integer.parseInt(args[1]));
// possibly more configuration logic
...
manager = clManager;
}
// input from the file
else if(args.length == 1){
FileInputGridManager fiManager = new FileInputGridManager();
fiManager.setFilePath(args[0]);
// possibly more method calls from abstract class
...
manager = fiManager ;
}
//... more possible concrete implementors
else{
manager = new CommandLineGridManager();
}
manager.setLifecicleAlgorithm(lifecicleAlgorithm);
return manager;
}
}
The receiver of AbstractGridManager would call the methods on him and get the logic, implemented in the concrete descender (and partially in the abstract class methods) without knowing what is the concrete implementation he got. This is also known as inversion of control or dependency injection.
You can say: we can't instantiate an abstract class, but we can use new keyword to create an anonymous class instance by just adding {} as implement body at the the end of the abstract class.
No, we can't create the object of abstract class, but create the reference variable of the abstract class. The reference variable is used to refer to the objects of derived classes (Sub classes of Abstract class)
Here is the example that illustrates this concept
abstract class Figure {
double dim1;
double dim2;
Figure(double a, double b) {
dim1 = a;
dim2 = b;
}
// area is now an abstract method
abstract double area();
}
class Rectangle extends Figure {
Rectangle(double a, double b) {
super(a, b);
}
// override area for rectangle
double area() {
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
}
class Triangle extends Figure {
Triangle(double a, double b) {
super(a, b);
}
// override area for right triangle
double area() {
System.out.println("Inside Area for Triangle.");
return dim1 * dim2 / 2;
}
}
class AbstractAreas {
public static void main(String args[]) {
// Figure f = new Figure(10, 10); // illegal now
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
Figure figref; // this is OK, no object is created
figref = r;
System.out.println("Area is " + figref.area());
figref = t;
System.out.println("Area is " + figref.area());
}
}
Here we see that we cannot create the object of type Figure but we can create a reference variable of type Figure. Here we created a reference variable of type Figure and Figure Class reference variable is used to refer to the objects of Class Rectangle and Triangle.
Actually we can not create an object of an abstract class directly. What we create is a reference variable of an abstract call. The reference variable is used to Refer to the object of the class which inherits the Abstract class i.e. the subclass of the abstract class.

Can I access static member variables defined on the subclass from a method on the abstract superclass?

I have an abstract class with a single concrete method. In this method I want to use a static class variable from the classes that derive from the one the method is declared in. To do so, I of course have to declare this static variable in the abstract class as well.
When the method is called, the variable is resolved to the one in my abstract base class as opposed to the one in the derived class. Do I need to decorate the derived class' property with an attribute?
Am I trying to do something that is not supported in Java, or am I just missing something?
You're trying to do something that isn't supported. Fields can't be "overridden" - and static members don't behave polymorphically.
Instead, create abstract properties which can be implemented in the derived classes. They'll have to be instance properties even if they return static variables.
You can't override variables, only methods. If its likely that a subclass needs to give a different value, add a getter method to the class that does that.
abstract class Foo {
static private final String someValue = "blah";
String getSomeValue() {
return someValue;
}
public abstract void someMethod();
}
class Bar extends Foo {
String getSomeValue() {
return "somethingElse";
}
public void someMethod() {
String x = getSomeValue();
}
}
Depending on what you want to do, you can do:
Base b = new Sub();
System.out.println(b.myInt); // will print myInt from Base
Sub s = new Sub();
System.out.println(s.myInt); // will print myInt from Sub
, but you likely want Jon's approach.

What is the use of creating a constructor for an abstract class in Java?

I would like to know what purpose a constructor for an abstract class serves; as we do not instantiate abstract classes, why would we ever need such a constructor?
there will be times when you have some common initialization of instance variables that all the inheriting classes need to set up. You do instantiate an abstract class when you extend it and that concrete class has a constructor that will either supply the parameters to the constructor of the abstract class.
They can still be invoked by constructors of classes that inherit from that one, making code refactoring a good use for having a constructor in the abstract class.
If you have uninitialised final fields in an abstract class, you'll need to initialise them in a constructor.
E.g.
abstract class A {
final int x;
}
will not compile without a constructor that assigns to x.
If your class doesn't declare a constructor, javac will make a no-arg, do-nothing constructor for you. Then, when your subclass is initialized, it will call the generated no-op constructor and life is good.
However, if your class declares any constructor, javac will NOT make one for you. In that case, the subclass constructor needs to explicitly call the constructor of the parent class. Otherwise, you'll fail to initialize members of the parent class, as the above answer mentions.
Constructors for abstract classes are used by subclasses (invoked from subclass constructors using super(params) ).
You should make these constructors protected to make that clear.
You don't instantiate abstract classes but the constructor is invoked when a subclass is instantiated.
The use could be to initialize common attributes ie.
import java.util.List;
import java.util.ArrayList;
abstract class BaseClass {
protected List list; // visible from subclasses
public BaseClass() {
System.out.println("to abstract...");
// common initialization to all subclasses
list = new ArrayList();
list.add("a");
list.add("a");
list.add("a");
}
}
class ConcreteClass extends BaseClass {
public ConcreteClass(){
// The list is initialized already
System.out.println("now it is concrete and the list is: = "+ this.list );
}
}
class TestAbstractClass {
public static void main( String [] args ) {
BaseClass instance = new ConcreteClass();
}
}
Output
$ java TestAbstractClass
to abstract...
now it is concrete and the list is: = [a, a, a]
De-duplicating common knowledge/behaviour.
E.g. a Car: all your cars will be constructed out of a body and four wheels and an engine. So you do this part of the construction in the constructor for the abstract Car class by calling functions like Body(), Wheel(int x), Engine(). Each particular car class will have their own implementation of Body(), Wheel() and Engine() - but they all will do the same steps to construct the car from them, so there is no need to duplicate those steps in each of those classes. In this case you implement that common behaviour in the ancestor.
I agree, Constructors are created assuming there will be instances. If you have lot of common code you can think of creating a Constructor but it is much better to put it in a init() method.

Categories

Resources