Why not abstract fields? - java

Why can't Java classes have abstract fields like they can with abstract methods?
For example: I have two classes that extend the same abstract base class. These two classes each have a method that is identical except for a String constant, which happens to be an error message, within them. If fields could be abstract, I could make this constant abstract and pull the method up into the base class. Instead, I have to create an abstract method, called getErrMsg() in this case, that returns the String, override this method in the two derived classes, and then I can pull up the method (which now calls the abstract method).
Why couldn't I just make the field abstract to begin with? Could Java have been designed to allow this?

You can do what you described by having a final field in your abstract class that is initialised in its constructor (untested code):
abstract class Base {
final String errMsg;
Base(String msg) {
errMsg = msg;
}
abstract String doSomething();
}
class Sub extends Base {
Sub() {
super("Sub message");
}
String doSomething() {
return errMsg + " from something";
}
}
If your child class "forgets" to initialise the final through the super constructor the compiler will give a warning an error, just like when an abstract method is not implemented.

I see no point in that. You can move the function to the abstract class and just override some protected field. I don't know if this works with constants but the effect is the same:
public abstract class Abstract {
protected String errorMsg = "";
public String getErrMsg() {
return this.errorMsg;
}
}
public class Foo extends Abstract {
public Foo() {
this.errorMsg = "Foo";
}
}
public class Bar extends Abstract {
public Bar() {
this.errorMsg = "Bar";
}
}
So your point is that you want to enforce the implementation/overriding/whatever of errorMsg in the subclasses? I thought you just wanted to have the method in the base class and didn't know how to deal with the field then.

Obviously it could have been designed to allow this, but under the covers it'd still have to do dynamic dispatch, and hence a method call. Java's design (at least in the early days) was, to some extent, an attempt to be minimalist. That is, the designers tried to avoid adding new features if they could be easily simulated by other features already in the language.

Reading your title, I thought you were referring to abstract instance members; and I couldn't see much use for them. But abstract static members is another matter entirely.
I have often wished that I could declare a method like the following in Java:
public abstract class MyClass {
public static abstract MyClass createInstance();
// more stuff...
}
Basically, I would like to insist that concrete implementations of my parent class provide a static factory method with a specific signature. This would allow me to get a reference to a concrete class with Class.forName() and be certain that I could construct one in a convention of my choosing.

Another option is to define the field as a public (final, if you like) in the base class, and then initialize that field in the constructor of the base class, depending upon which subclass is currently being used. It's a bit shady, in that it introduces a circular dependency. But, at least it's not a dependency that can ever change -- i.e., the subclass will either exist or not exist, but the subclass's methods or fields can not influence the value of field.
public abstract class Base {
public final int field;
public Base() {
if (this instanceof SubClassOne) {
field = 1;
} else if (this instanceof SubClassTwo) {
field = 2;
} else {
// assertion, thrown exception, set to -1, whatever you want to do
// to trigger an error
field = -1;
}
}
}

Related

Java method with unknown parameter type

I'm new to Java.
There is repeating code in multiple files in a project I'm working on.
Object types can be Thing1, Thing2, Thing3 etc.
So the code looks like:
if (Thing1.getStuff() instanceof String) {
myObj.setString("Hello");
} else {
myObj.setString("World");
}
I want to extend myObj with a class and method to handle this, as such:
public class myObj extends DoStuff {...}
--
class DoStuff {
public String doThis(*WHAT_TYPE_TO_USE* input) {
var String = input.myMethod(); // I need to call method.
return "String after some logic";
}
}
Which should allow me to run:
myObj.doThis("Something");
However, I can't specify input to be a specific type in the method as it could be Thing1, Thing2 etc. Also, Thing1 and Thing2 can't be dynamically imported, can they? How can I run myMethod (which exists in Thing1 and Thing2)?
Any advice is appreciated.
You need your Thing classes to implement a common interface such as
public interface Thing {
public String myMethod();
}
public class Thing1 implements Thing {
...
}
If they don't have a common supertype, then the two myMethod methods are unrelated. The fact that they have the same name is irrelevant to Java; they're distinct methods defined in distinct classes. You can access them with reflection shenanigans, but then you're giving up a lot of type safety (at that point, you would just take an Object and trust the user to provide a value of the correct type; it's ugly and messy and I don't recommend it).
If the classes in question are third-party classes (i.e. that you don't control) and don't implement a common interface, then you need the adapter pattern. Basically, you define a new class that does implement the interface and wraps an instance of the original.
public class Thing1Adapter implements Thing {
private Thing1 impl;
public Thing1Adapter(Thing1 impl) {
this.impl = impl;
}
#Override
public String myMethod() {
return this.impl.myMethod();
}
}
...
DoThis(new Thing1Adapter(myThing1));

What is the best practice in Java to set a constant required in subclasses?

I have the following situation:
A parent class has a function that depends on a constant. But the only valid place to define that constant is in subclasses (parent class cannot define the constant's value, but it can be used with the constant undefined in 99% of use cases - the constant is a default to use if a specific configuration element is missing).
However, I would like to enforce that any child class inheriting from that parent class must define the value for the constant, since any child classes have to be able to use the other 1% of functionality.
What is the best practice to implement this enforcement in Java, ideally at compile time? (clearly, at runtime, I can simply check if the constant is null/empty in the method using it).
My own solution was to implement a value-getter for the constant as an abstract method in the parent class, and call that in combination with the real setter in the constructor; something like this:
public class HelperClass1 {
private String myConstant;
public void setMyConstant() {} // implemented obviousy
public void myMethod() { // Called from ParentClass's methods
// Do something useful with myConstant
}
}
import HelperClass1;
public abstract class ParentClass {
ParentClass() {
HelperClass1.setMyConstant( getMyConstantValue() );
}
public abstract void getMyConstantValue();
}
public class ChildClass1 extends ParentClass {
public void getMyConstantValue() { return "BUZZ"; }
}
public class ChildClass2 extends ParentClass {
} // Fails to compile without getMyConstantValue()
However, (a) This implementation has a problem (I can't use ParentClass itself, since it's now abstract) without subclassing; and (b) since I'm not a Java developer, I'm afraid that this isn't the best or the most elegant solution. So I'd like to know if there's a best practices approach that improves on what I implemented.
Provide two constructors for the parent class:
One is a protected constructor which takes the constant as an argument.
The other is private constructor which can construct instances of the parent class without setting the constant.
Provide a factory method for the parent class which can call the private no-constant constructor.
Classes that want to get an instance of the parent class can call the factory method. But child classes that want to inherit from the parent class have to call the protected constructer, which can validate that a valid constant was passed.
public class ParentClass {
private final SomeClass myConstant;
protected ParentClass(SomeClass aConstant) {
if (null == aConstant) {
throw new IllegalArgumentException("...");
}
myConstant = aConstant;
}
private ParentClass() {
myConstant = null;
}
public static ParentClass getInstance() {
return new ParentClass();
}
}
public class ChildClass {
public ChildClass() {
super(new SomeClass(42));
}
}
This isn't perfect. Someone could write a child class that passes a bad constant to the superclass constructor, and it wouldn't actually fail until some code tried to construct an instance of the child class.

Most concise and efficient way to share common handling code for a per-class object?

I have a series of classes, A,B,C... (several dozen in total) that share common code. There can be many instance of each class A,B,C... . I'm planning to create a superclass, Abstract, that will contain that code instead.
Problem is, the common stuff works on an object that is unique on a per-class (not per-instance) basis. This is currently solved by A,B,C... each having a static field with the corresponding value. Obviously, when I refactor the functionality into Abstract, this needs to be changed into something else.
In practice, it currently looks like this (note that the actual type is not String, this is just for demonstrative purposes) :
public class A implements CommonInterface {
private static final String specificVar = "A";
#Override
public void common() {
specificVar.contains('');
}
}
public class B implements CommonInterface {
private static final String specificVar = "B";
#Override
public void common() {
specificVar.contains('');
}
}
The best idea I've come up with until now is to have a Map<Class<? extends Abstract>,K> (where K is the relevant type) static field in Abstract, and A,B,C... each containing a static initalization block that places the relevant value into the map. However, I'm not convinced this is the best that can be done.
Note that I'm not using any DI framework.
So, what would be the most concise, in terms of code contained in the subclasses, way to refactor the static fields in A,B,C... handled by the common code, without sacrificing field access efficiency?
Perhaps an enum is what you want.
enum MyInstances implements MyInterface {
A {
fields and methods for A
}, B {
fields and methods for B
};
common fields for all MyInstances
common methods for all MyInstances
}
// To lookup an instance
MyInstances mi = MyInstances.valueOf("A");
As you haven't shown any source code, we can't really tell if the use of static fields is a good or a bad design choice.
Considering the use of static fields by the subclasses is indeed a good design choice, the first way of having common code in a superclass to access them is by calling abstract methods that would be implemented in the subclasses.
Example:
public abstract class SuperClass {
public void processCommonLogic() {
// Common logic
// Execute specific logic in subclasses
processSpecificLogic();
}
public abstract void processCommonLogic();
}
public class ASubClass extends SuperClass {
public static int SPECIFIC_SUBCLASS_CONSTANT = 0;
public void processSpecificLogic() {
// Specific subclass logic
doSomethingWith(ASubClass.SPECIFIC_SUBCLASS_CONSTANT);
}
}
You could use the Template Method Pattern.
Have an abstract method getValue() defined in your abstract class and used within your abstract class wherever you require the value. Then each of your subclasses simply need to implement the getValue method and return the correct value for that subclass.

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.

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