I want to define an abstract method like so:
public abstract class Saveable {
public Set<Field> getFieldSet();
...
}
getFields() should always return the same output regardless of the object's state. However, I can't declare this as a static method because I want it to be overridden. Now I'm implementing a class User which extends Saveable and it has some static methods which require the field set. Obviously, I can't get it because I don't have an object. Any idea on a design that would allow me to get the fields in a static method?
One approach would be "fake" the this reference by passing in an instance of the correct object to the static methods, and then calling getFields on that object.
Another option is to store the field list in a static field on the class. Your overridden getFields() implementation can return it (or preferably a copy of it,) and your static methods can access it directly.
My preference would be to implement the latter option, as it's a lot less clumsy (since you never have to new up an otherwise useless object to pass in to the static methods.) As well, it captures the idea that the class's fields don't rely on a given instance.
Unfortunately an inherited class can't override a static method, but it can hide it by declaring an static method with the same signature.
This will not help you if your final purpose is to use the GetFields() inside another inherited method in the Saveable class, because it will always call Saveable.getFields(), not the static method in your extending class.
You can leave your current method as non-static and abstract in Savable and return a static Set out of the non-static implementation.
public class User extends Savable {
public static Set<AField> aSet = new HashSet<AField>();
#Override
public Set<? extends Field> getFields() {
return aSet;
}
}
When calling a static method, you're calling the class' name as a scope.
So there's actually no meaning of overriding, you're only hiding it anyway.
Besides, because of the same reason, it cannot be inherited because it belongs to the class type, not a class instance.
The best you can do is call the base class' static method in the derived class, and have the same method name.
Expanding #dlev 's answer, how about you store the fields in a hashmap keyed off by unique identifier per class.
If you are using Spring, you can inject the set of fields in every object. Hence only the reference will be duplicated.
This is the proposal, I worked out. But you somehow have to name the derived class name, when loading those fields, there is no other way around, apart from declaring the methods static anyway.
public abstract class Saveable {
public static Set<? extends Field> getFields(Class<? extends Saveable> clazz) {
return FieldsProvider.get(clazz);
}
}
public class FieldsProvider {
private static final Map<Class<? extends Saveable>, Set<? extends Field>> map =
new HashMap<Class<? extends Saveable>, Set<? extends Field>>();
public static void registerFields(Class<? extends Saveable> clazz, Collection<? extends Field> col) {
Set<? extends Saveable> set = new HashSet<? extends Saveable>();
set.addAll(col);
map.put(clazz, set);
}
public static Set<? extends Field> getFieldSet(Class<? extends Saveable> clazz) {
Set<? extends Field> set = map.get(clazz);
if (set != null) {
return set;
}
return Collections.emptySet();
}
}
public class User extends Saveable {
static {
FieldsProvider.registerFields(User.class, new HashSet<? extends Field>... ;
}
static void someMethod() {
Set<? extends Field> fieldsSet = getFields(User.class);
...
}
}
Related
I have a bounded generic class, let's call it Generic, with a parameter T that extends an abstract class Abstract:
Generic Class:
public class Generic<T extends Abstract> {
public <T extends Abstract> List<T> method() {
Map<String,String> map = T.getMap(); //this is the line with the error. I'll explain it below
//return statement and such
}
}
Abstract Class
public abstract class Abstract {
protected Map<String, String> map;
public abstract Map<String, String> getMap();
}
The class referenced by T in the generic class
public class class1 extends Abstract {
public class1() {
//map is inmutably defined here and assigned to the super
}
#Override
public Map<String, String> getMap() {
return super.map;
}
}
When trying to reference the method getMap() which comes from a class inside bounds of T (and which all possible instances of T will have, per the abstract class definition, I get the following error:
non-static method getMap() cannot be referenced from a static context
Yet there are no static keywords anywhere. What am I missing??
Thanks!
Because the method getMap() is an instance method (ie not static), you need an instance if T to call the method on.
Your class hierarchy looks off too. I think you actually want something more like:
public class Generic<T> extends Abstract<T> {
}
public abstract class Abstract<T> {
protected Map<String, T> map;
}
but without context of your intention, I can't be sure.
I am following examples in "Effective Java" and came across the following code:
abstract static class Builder<T extends Builder<T>>
and its implementation:
public static class Builder extends Pizza.Builder<Builder>
Why is this declared T extends Builder<T> and not T extends Builder. Is it really needed to add the template <T>? What is the impact if I just use Builder<T extends Builder>?
It is called as "generic type". That declaration means T can be any type that is subclass of Builder<T>.
The goal of implementing Generics is finding bugs in compile-time other than in run-time. Finding bugs in compile-time can save time for debugging java program, because compile-time bugs are much easier to find and fix.
What is the impact if we just use Builder<T extends Builder>?
It transforms into raw type. And type safety goes off.
Builder<T extends Builder<T>> means that,
The class T passed in must implement the Builder interface / extend Builder class, and the generic parameter of Builder must be T itself.
I have some examples to show that actually the difference is not that big. I think the OP wants to know the difference between T extends Builder<T> and T extends Builder.
public abstract class Builder2<T extends Builder2> {
//doesn't compile either, because String is not a subtype of Builder2
static class WrongHouseBuilder extends Builder2<String> {}
//all ok
static class RawHouseBuilder extends Builder2 {}
static class HouseBuilder1 extends Builder2<RawHouseBuilder> {}
static class HouseBuilder2 extends Builder2<HouseBuilder1> {}
static class HouseBuilder3 extends Builder2<HouseBuilder2> {}}
Now with Builder<T>:
public abstract class Builder<T extends Builder<T>> {
//all ok
static class RawCarBuilder extends Builder {}
static class CarBuilder extends Builder<CarBuilder> {}
//ok as well, T doesn't have to be CarBuilder2
static class CarBuilder2 extends Builder<CarBuilder> {}
//doesn't compile because CarBuilder2 is not a subtype of Builder<CarBuilder2>
static class CarBuilder3 extends Builder<CarBuilder2> {}}
Of cause with T extends Builder<T>, you have more protection, but not that much.
UPDATE
Just to clarify, we should not use raw type. #Radiodef has provided an interesting example in the comment. And a quote from that answer to help you understand it:
In simpler terms, when a raw type is used, the constructors, instance methods and non-static fields are also erased.
Minor: It looks more natural to me to use Builder as an interface, not an abstract class. This is a sort of recursive type declaration. It is used for type safety to prevent nasty things like the following happens:
public abstract Builder<T extends Builder<T>> {
T build();
}
public class Entity extends Builder<String>{ // does not compile
#Override
public String build() {
return null;
}
}
public class Entity extends Builder<Entity>{ //ok
#Override
public Entity build() {
return null;
}
}
Anyway more naturally looking version (from my point of view) is:
public interface Buildable<T extends Buildable<T>> {
T build();
}
public final class Entity implements Buildable<Entity>{
//other methods
#Override
public Entity build() {
//implementation
}
}
I see that the question is about the <T> part in Builder<T>. Without this <T>, you simply get a raw type, and your IDE might complain.
But in my answer, I'd like to explain what's the purpose of T extends Builder<T>, because other answers do not seem to cover it (maybe you know this already).
T extends Builder<T> serves the purpose of returning appropriate Builder.this in all the Builder methods (except build() method, of course).
I usually use it with a protected abstract method like T thisInstance().
Example:
abstract class NamedBuilder<T extends NamedBuilder<T>> {
private String name;
T name(String name) {
this.name = name;
return thisInstance();
}
protected abstract T thisInstance();
}
final class MoreSpecificBuilder extends NamedBuilder<MoreSpecificBuilder> {
#Override
protected MoreSpecificBuilder thisInstance() {
return this;
}
}
Thanks to such approach, you do not have to redefine name() method in all the NamedBuilder subclasses to return the specific subclass.
Without such constraint type parameter T, you would have:
abstract class NamedBuilder {
NamedBuilder name(String name);
}
and you would need to override all such methods in subclasses like that:
final class MoreSpecificBuilder extends NamedBuilder {
#Override
MoreSpecificBuilder name(String name) {
super.name(name);
return this;
}
}
EDIT: Without the constraint extends Builder<T> on type parameter T:
abstract class NamedBuilder<T> {
// ...
}
this would work fine, although such design would be less intuitive and more error-prone.
Without such constraint, compiler would accept anything as T (e.g. String), so the constraint acts simply as a compile-time check for the implementors of NamedBuilder.
Can I enforce child classes to create a enum in them?
class Document<T extends Enum<T>>{
Map<T, String> fields;
}
class TextDocument extends Document<TextDocument.Field>{
public enum Field{
...
}
}
How can I enforce any implementation of Document to have an enum named Field within it? In the above example, TextDocument can extend Document with some other enum (say GraphDocument.Field) as well which shouldn't be allowed. How can I create this restriction? I need to enforce this rule to subclasses - "You must have your own enum". Is this even possible? By some hacky way? Any ideas?
In short, you can't. However, you can force it to return an array of the values of a particular enumeration. You can also force the enumeration to implement an interface.
public interface SomeInterface {
// any methods you want to be able to perform on the enums
}
public abstract class SomeSuperClass<T extends SomeInterface> {
abstract T[] getSome();
}
public class SomeSubclass extends SomeSuperClass<SomeInterface> {
public enum SomeEnum implements SomeInterface {
testEnum {
// interface implementation
}
}
public SomeInterface[] getSome() {
return SomeEnum.values();
}
}
This is a pretty awkward solution, but it works.
I must admit that Java is a little messy when working with templates...
As the title explains, i'm trying to use an static member coded on the super class of some generalizated attribute. How can i do this?
For example:
class A {
public static void someAction();
}
class B<T extends A>{ (...) }
¿how do i access the A's someAction() method in the class B?
How do i access A's someAction() method from the class B?
Just call
A.someAction()
It's a static method, so the fact that B's type parameter extends A has no effect whatsoever.
If someAction should be generic and you want to use B's <T> parameter with A, then declare someAction with its own type parameter:
public static <T> void someAction(.../* use T here maybe */) { ... }
and from B you can then do
A.<T>someAction(...)
so that the <T> before someAction is the same as the <T extends A> visible in the body of B.
I'm using generics like this: public class MyList<T>. Is there any way to ensure that the class represented by T implements a certain static method?
No, even without generics there is never a way to ensure a class implements a static method.
You can, however, create a generic static method.
public static <T> List<T> makeSingletonList(T item) {
ArrayList<T> result = new ArrayList<T>();
result.add(item);
return result;
}
Unfortunately not.
As an alternative, consider whether the static methods of your class belongs in some sort of associated class like a builder:
class Person {
public static Person createFromDatastore(Datastore datastore) { ... }
}
It may be better to move the static to a separate class as a non-static method:
class PersonBuilder implements Builder<Person> {
public Person createFromDatastore(Datastore datastore) { ... }
}
This means that you can dictate clients of your generic class can now be required to provide it:
public class MyList<B extends Builder<T>, T> ...