I theoretically understand the point why there is no abstract static in Java, as explained for instance in Why can't static methods be abstract in Java .
But how do I solve such a problem then?
My application uses files of a few types, which I want to assign static properties like a description of that file type (like "data file", the other being "config file", etc.). Obviously, I would put that into a static String so that the description is accessible without instancing a file (useful for the GUI f.i.). On the other hand, obviously all file types should have some common methods like getStatus()
, which obviously I want to inherit from a common superclass MyFileType
.
getDescription()
would of course be abstract in the superclass.
Tried using a combination of a superclass and an interface, but similar problem: A static implementation of an abstract method is not allowed.
How would a Java guru solve this? Is it really such a bad implementation that I want to create?
Many thanks, Philipp
Declaring abstract method static If you declare a method in a class abstract to use it, you must override this method in the subclass. But, overriding is not possible with static methods. Therefore, an abstract method cannot be static.
A static method belongs to class not to object instance thus it cannot be overridden or implemented in a child class. So there is no use of making a static method as abstract.
I think static methods are fine either when they're private or when they're "utility" methods - e.g. to do string escaping. The problem comes when you use static methods for things that you want to be able to mock out or otherwise replace within tests.
We cannot create objects of an abstract class. To implement features of an abstract class, we inherit subclasses from it and create objects of the subclass. A subclass must override all abstract methods of an abstract class. However, if the subclass is declared abstract, it's not mandatory to override abstract methods.
To restate the problem: you want your per-file-type classes to have statically available information on the type (e.g., name and description).
We can easily get part-way there: create a separate class for your type info, and have a static instance of this (appropriately instantiated) in each per-file-type class.
package myFileAPI; public class TypeInfo { public final String name; public final String description; public TypeInfo(String name, String description) { this.name = name; this.description = description; } }
and, say:
package myFileAPI; public class TextFile { public static final TypeInfo typeInfo = new TypeInfo("Text", "Contains text."); }
Then you can do stuff like:
System.out.println(TextFile.typeInfo.name);
(Of course, you could also use getters in TypeInfo
to encapsulate the underlying strings.)
However, as you said, what we really want is to enforce the existence of a particular signature static method in all your per-file-type classes at compile time, but the 'obvious' design path leads to requiring an abstract static method in a common superclass which isn't allowed.
We can enforce this at run-time though, which may be good enough to ensure it is coded correctly. We introduce a File superclass:
package myFileAPI; public abstract class File { public static TypeInfo getTypeInfo() { throw new IllegalStateException( "Type info hasn't been set up in the subclass"); } }
If TextFile
now extends File
, we will get this exception when calling TextFile.getTypeInfo()
at runtime, unless TextFile has a same-signature method.
This is quite subtle: code with TextFile.getTypeInfo()
in still compiles, even when there is no such method in TextFile. Even though static methods are bound at compile time, the compiler can still look through the class hierarchy to determine the compile-time static call target.
So, we need code like:
package myFileAPI; public class TextFile extends File { private static final TypeInfo typeInfo = new TypeInfo("Text", "Contains text."); // Shadow the superclass static method public static TypeInfo getTypeInfo() { return typeInfo; } }
Note that we are still shadowing the superclass method, and so File.getTypeInfo()
can still be 'meaninglessly' called.
This sounds like a great time to pull out the Fundamental Theorem of Software Engineering:
Any problem can be solved by adding another layer of indirection.
The problem you have right here is that a file carries around multiple pieces of information - what the type of the file is, a description of the file, the file contents, etc. I'd suggest splitting this into two classes - one class representing a concrete file on disk and its contents, and a second that is an abstract description of some file type. This would allow you to treat the file type class polymorphically. For example:
public interface FileType { String getExtension(); String getDescription(); /* ... etc. ... */ }
Now, you can make subclasses for each of the file types you use:
public class TextFileType implements FileType { public String getExtension() { return ".txt"; } public String getDescription() { return "A plain ol' text file."; } /* ... */ }
You can then have some large repository of these sorts of objects, which would allow you to query their properties without having an open file of that type. You could also associate a type with each actual file you use by just having it store a FileType
reference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With