Extend a generic type in Java - java

is it possible in Java to let a class extend a generic type, so that you can inject an method into any class passed through your code? (Or is there any other way to inject or override methods into an existing class with Java?)
What I mean with "extend a generic type" is something like this (Class "T extends GameObject" belongs to game and may not be changed AND is unknown because loaded into the game at runtime (from other mods)):
class GameObject {
void moveForward(float amount) {
this.camera.z += amount;
}
}
class Extender<T extends GameObject> extends T {
void onTick(float time) {
this.camera.z -= amount;
}
}
onTick is called by the GameEngine, and in this way I could replace every existing game object with a version that moves backwards on every tick.

No. You cannot extend a generic supertype. You can extend classes that make use of generic types (e.g. public class MyClass<T> extends TheirClass<T>) but you cannot extend a purely generic type.

In my opinion you can find the solution not in language's features, but in some design pattern, as Decorator or Template Method Pattern.
If the behaviour is determinated in runtime, you could give a look at behaviour patterns.

Related

Reference implementing class from interface definition

Given an interface I:
interface I<T> {
public abstract T doSomthing(T other);
}
where any class C which implements the interface I will always use itself (C) as the type parameter:
class MyClass implements I<MyClass> {
#Override
public MyClass doSomthing(MyClass other) {
return null;
}
}
Is there a way to accomplish this without explicitly passing the class C as the parameter every time a new class implements the interface?
In other words is it possible, in an interface, to reference the class which implements that interface?
tl;dr
You asked:
Is there a way to accomplish this without explicitly passing the class C
No, not in Java.
Example
You seem to be describing exactly the scenario of the Comparable<T> interface bundled with Java. That interface has a single generic argument, for the type of the two objects to be compared. That interface requires a single method compareTo​(T o) taking a single parameter of that same generic type.
Let’s look at an example usage in the OpenJDK source code, the source code for class Year.
The class declares itself explicitly as the type of comparison on the Comparable interface being implemented.
public final class Year
implements Temporal, TemporalAdjuster, Comparable<Year>, Serializable {
The compareTo method explicitly cites its own class as the type being compared.
#Override
public int compareTo(Year other) {
return year - other.year;
}
You asked:
Is there a way to accomplish this without explicitly passing the class C as the parameter every time a new class implements the interface?
It seems the answer is No. The implementing class must cite itself explicitly as the fulfillment of the generic type of the interface being implemented.
Caveat: (a) I am not an expert on such language matters. (b) I may have misunderstood your question.
To add to the other answer: what you're describing is a self type.
Some other languages have it (such as Scala).
But I'm afraid Kotlin doesn't.  (Java doesn't, either.)
There has been long discussion about the possibility of adding it to a future version of Kotlin; it seems the potential uses may not be wide enough for it to be worthwhile, though there doesn't seem to be a final consensus.
The usual workaround is using a type parameter — similar to what C++ calls the curiously-recurring template pattern.  It's not quite as typesafe in Java or Kotlin, as this question illustrates, but covers most of the same ground.
That's called self-bounded generics. It could be declared in Java as well as in Kotlin.
Java:
interface I<T extends I<T>> {
public abstract T doSomething(T other);
}
Kotlin:
interface I<T : I<T>> {
fun doSomething(other: T): T
}
But it doesn't mean, that generic parameter could be omitted then you declare classes, implementing this interface. It just imposes additional restrictions on type, you're passing as a generic parameter (narrowing it down to only one type). Type inference is not supported for class declaration neither in Kotlin, nor in Java.
Also see: Can I resolve a generic type from another generic declaration in an interface?

How can I restrict arguments of methods in abstract classes for subclasses that use them?

I've been trying to design a set of classes to model a classic RPG. I've found myself confused on how to solve this one issue, however: how do I force the use of character-type (e.g. Tank, Healer, DPS) specific spells/equipment, etc. in an abstract class. The example below better articulates what I mean.
I've got an abstract PlayableCharacter class which all character-types inherit from:
public abstract class PlayableCharacter {
private Set<Spell> mSpells;
...
public void addSpell(Spell spell) {
mSpells.add(spell);
}
}
For example:
public class Healer extends PlayableCharacter { ... }
public class Tank extends PlayableCharacter { ... }
Note the Set of Spell in the abstract class. I would like it if each subclass of PlayableCharacter could use its addSpell method but with the restriction that the type of Spell correspond to the PlayableCharacter subtype.
For example I have these Spell classes:
public abstract class Spell { ... }
public class HealerSpell extends Spell { ... }
public class TankSpell extends Spell { ... }
I only want Healers to use HealerSpells and Tanks to use TankSpells, etc. For example:
PlayableCharacter tank = new Tank();
tank.addSpell(new TankSpell()); // This is fine
tank.addSpell(new HealerSpell()); // I want to prevent this!
I thought of giving each subclass of PlayableCharacter it's own Set of subclass-specific Spells, but that creates a lot of code duplication.
I also tried making PlayableCharacter.addSpell marked as protected, then each subclass would have to implement an interface like this:
public interface Spellable<T extends Spell> { void addClassSpell(T spell); }
and each subclass that implements it would call super.addSpell(spell); but that lead to more code duplication and nothing was forcing those implementations to do the super call.
Is my strategy fundamentally flawed in some way? Any advice? I feel like this issue will keep getting worse as I add more character-type-specific equipment, traits, and so on.
I wouldn't do it that way (via type inheritance). It would be better to add characteristics to a Spell itself because it's a spell, which can be cast by a certain character only. Also, a specific spell can be cast to a certain character type only. These rules belong to a spell, not to a character.
Spell rules can be checked in a runtime by a separate class or by a Spell class itself inside a cast() method or another one.
so far what you have is good
the rest of the stuff, think more strategy pattern than super call
so abstract class can have algorithm that does step1, step2, step3 with possible parent implementation
child classes can override it, but only override parts that is different
when you call algorithm, it performs all steps
Steps themselves could be different class that has logic, if everything becomes too big
maybe have each subclass of playable character store the class (or classes) of subspells that are allowed. then do an if(spell instance of allowedSpell) ...

Why is it not possible to implement Comparable<T> multiple times?

It seems like you usually implemented the java.lang.Comparable interface without specifying the type parameter.
public abstract class Area implements Comparable {
#Override
public int compareTo(Object other) {
if (other instanceof Area)
return new Double(getArea()).compareTo(other.getArea());
return -1; // or something else
}
abstract public double getArea();
}
Since I only want to compare apples with apples, I think it would make sense to specify the type.
public abstract class Area implements Comparable<Area> {
#Override
public int compareTo(Area other) {
// ...
If I want to introduce another class to compare Area with, I thought I could do the following:
public abstract class Area implements Comparable<Area>, Comparable<Volume> {
#Override
public int compareTo(Area other) {
// ...
}
#Override
public int compareTo(Volume other) {
// ...
}
}
But the java compiler tells me:
Area.java:2: error: repeated interface
public abstract class Area implements Comparable<Area>, Comparable<Volume> {
^
Area.java:2: error: Comparable cannot be inherited with different arguments: <Area> and <Volume>
Are there any drawbacks specifying the type argument for the generic interface?
Why won't Java allow me this multiple implementation?
Note: I'm using Java version 1.7.0_45
No, it's not a drawback of specifying the generic - it's actually a feature. Also, I don't recall any drawback for using generics in interfaces, other than the well-known fact you can't instantiate a generic type nor create a generic array (but that's more a problem of implementation, not the interface itself).
It's due to type erasure. Comparable<Area> and Comparable<Volume> is essentially the same class for the VM, and, shortly after checking validity, also for compiler.
If you want to have two distinct comparable interfaces implemented, just use Comparators for them - it's generally easier to maintain composition than inheritance in classes.
For some applications (distinguishing generics at run-time) you may also try subclassing them, e.g. ComparableArea extends Comparable<Area> & ComparableVolume extends Comparable<Volume>, but that would, in this particular case, cause more trouble than it would solve IMO, since you'd still get Comparable cannot be inherited with different arguments error - but at least you could differentiate those interfaces by e.g. instanceof.
I think this way java is saying that related classes can be Comparable, but using artificial Comparator we can do more comparisons among unrelated classes.
So we should implement generic interface of related classes (classes within the same inheritance hierarchy). In case we want to add an artificial implementation, add an interface which can be passed through (so have pair of family of interfaces like Comparable and Comparator).

How to restrict object creation with generics?

I want to have a type hierarchy where only Foo objects are in control of the creation of Bar objects. E.g:
public abstract class Foo<F extends Foo<F>> {
public abstract Bar<F> makeBar();
}
public abstract class Bar<F extends Foo<F>> {}
Now a subclass of Foo could implement a subclass of Bar and give it back:
public class FooImpl extends Foo<FooImpl> {
private static class BarImpl extends Bar<FooImpl> {}
#Override
public Bar<FooImpl> makeBar() { return new BarImpl(); }
}
However that does still allow the creation of Bars elsewhere:
public class FakeBar extends Bar<FooImpl> {}
How can I restrict Bar<FooImpl> (using only the type system, not runtime checks) in a way that it must be created by an instance of FooImpl, and cannot be created in any other place?
This isn't something the type system can (or should) do. You want access restrictions, use Java's access modifiers. But I don't think those can implement your very specific and unusual requirements either.
Actually, I don't think they can be implemented at all: you want a class to be publically visible and non-final, yet allow the ability to call its constructors and to extend it only to a specific class and its subclasses?
Sorry, no can do. What would be the point anyway?
That doesn't work (with the limitation: type system only, no runtime checks). We can either disallow subclassing in general (final class) or allow it. If a (public) class is not final, any other class may subclass.
You could try playing with annotations - like inventing an annotation, that lists allowed classname, but this depends on processing the annotations.
Example:
#AllowedSubclasses(classnames="com.example.FooBar; *.AnyFooBar; com.example.foobars.*")
public abstract class Bar<F extends Foo<F>> {}
The annotation processor then would throw an error, if any other class subclasses this annotated class.
What about a mixed approach: annotate your internal methods with "HANDS OFF" in the javaDoc and document, that any violation will result in runtime exceptions. After the method has been called, you can verify within the method, if the caller is an instance of one of the classes, that are allowed to use this feature.
Well instead of relying on generics etc, a simpler way to accomplish this is to enforce that you need an instance of Foo to create a Bar
public Bar(Foo foo){...}
This way, no one can create a bar independently of Foo. This couples the 2 classes, and indicates to users of this fact as well. There are other ways to accomplish this as well... this is just one example
You can make makeBar a concrete method which calls a protected abstract makeBar0 which does the actual creation. makeBar() can take the result and check it the object any way you wish.
public abstract class Foo<F extends Foo<F>> {
public Bar<F> makeBar() {
Bar<F> bar = makeBar0();
// check bar
return bar;
}
}
If you prefer you could add a check on the creation of Foo which may be more performance. i.e. check the return type of makeBar0();

Arbitrary Java enum argument

I'm fairly new to java, and am used to enums essentially beeing nothing more than a named list of integers.
Now I'm writing an implementation where a parent class has a couple of methods that take an enum value as argument. The enum will be defined in child classes, and will differ slightly. Since enums basically seem to behave like classes, this doesn't work the way I expected it to. Each enum defined will be considered a different type of object and the parent class will have to pick one of the defined enums to take as argument.
Is there a good way to make the parent class accept any enum defined in it's child-classes? Or will I have to write a custom class for this?
Edit: Here is my example, fixed as per Jon Skeets answer, for anyone who is looking into how to do this later on:
class Parent {
protected interface ParentEvent {}
private HashMap<ParentEvent, String> actions = new HashMap<ParentEvent, String>();
protected void doStuff(ParentEvent e){
if(actions.containsKey(e)){
System.out.println(actions.get(e));
}
}
}
class Child extends Parent {
enum Event implements ParentEvent {EDITED, ADDED, REMOVED}
public void trigger(){
doStuff(Event.REMOVED);
}
}
You could make your enums implement an interface, then give your parent class method a parameter of that interface type.
As you say, enums are rather different in Java. They're not named numbers - they're a fixed set of values, but those values are object-oriented (i.e. they can use polymorphism etc). Java enums pretty much rock, except for a few tricksy issues around initialization ordering.
if i understand you correctly, you want to have a common base class for your enum and want to define several unrelated sets of enums for the sub classes. This is not possible with java's typesafe enums, because they don't allow you to define a base class.
Of course it is not an option just to have one enum defined and always extend its values because this clearly violates the open close principle.
For such a use case I have fairly good experience with Josh Bloch's Typesafe Enum Pattern he describes in Effective Java
Just introduce your super class here and make distinct sub classes for each of enum values your client classes need.
I'm not sure, but maybe this is what you want:
public abstract class EnumTest<E extends Enum<E>> {
public abstract void frobnicate(E value);
}
public class Derived extends EnumTest<Derived.DerivedEnum> {
public void frobnicate(DerivedEnum value) {
System.out.println(value);
}
public static enum DerivedEnum {
FOO, BAR,
}
}
You could define the enums in their own file if they're applicable to different classes. They don't need to be nested within a class.
You can't extend one set of enums from another though.
It took me a while to get out of the mindset of an enum 'just being an integer'.

Categories

Resources