I have a class like this :
public class MyClass <T extends Model1, X extends Model2> {
private CommonMessage<T,X> someMethod() {
....
}
}
Now I have a customized message type MyMessage extends CommonMessage, so I want to know how to have generic type that still having T and X as parameters ? For example :
public class MyClass <M extends CommonMessage, T extends Model1, X extends Model2> {
private M<T,X> someMethod() {
....
}
}
Short answer:
First of all as CommonMessage is generic, extending it in a non-generic way is very bad so you should have done M extends CommonMessage<T, X> And this way because type parameter passed to CommonMessage at class declaration you should not mention this parameter type again at method return type so method return type should be M.
Long answer:
I know you do know this definitions but sometimes we as human forget simple things. First we should consider what generics are created for, with generics we can create classes with different parameter types, this parameter types will be provided when they are extended by another class or when we create new instance of them with new() operator, so when we are writing our class we don't know the exact type for those parameter and we want to delay this decision until later, it is contradictory to something you are doing in your class because here your method is private and you can't change its implementation in your child class(the class which inherited from your class). But know we can change your implementation to something like this which will be compiled well:
public class MyClass<M extends CommonMessage<T, X>, T extends Model1, X extends Model2> {
private M method1(){
...
}
}
public class CommonMessage<T, X>{
}
public class MyMessage<T, X> extends CommonMessage<T, X>{
}
public class Model1{
}
public class Model2{
}
although this implementation will be compiled the problem is that when you are writing your private method(method1) you don't know what is the type of M at the time of writing this class because it will be passed when we want to create new instance of this class or when we inherit another class from this class. so what type of Object do you want to create and return in your method1? the only thing that you know here is that its type is M which extends CommonMessage but you don't know what the exact type of M is at the time of writing your private method(method1)!
And on the top of that you can't delegate this decision to your subclass(because this method is private). Now the question is that why it is allowed and compiled well when we don't know the exact type of M? for a moment forget this question I will make it clear after explaining correct approach. so what is the correct approach? Think about it, the person who write subclass does know exactly what the type of parameter M is and they can create appropriate instance of M in implementation of method1 to return from this method. so why not delegate this decision to subclass and making this method abstract? This completely make senses. in a nutshell we have some implementation like this:
public abstract class MyClass<M extends CommonMessage<T, X>, T extends Model1, X extends Model2> {
public abstract M method1();
}
public class CommonMessage<T, X>{
}
public class MyMessage<T, X> extends CommonMessage<T, X>{
}
public class Model1{
}
public class Model2{
}
now lets get back to our question why first program that I suggested to you compiled well? why we are allowed to have private method that its return type is generic that will be passed at instanciation or inheritance time?
because there are a lot of situations that make it correct and appropriate.
one situation is that our private method call another public method which return the appropriate type, like this:
public abstract class MyClass<M extends CommonMessage<T, X>, T extends Model1, X extends Model2> {
private M method1(){
return method2();
}
abstract M method2();
}
public class CommonMessage<T, X>{
}
public class MyMessage<T, X> extends CommonMessage<T, X>{
}
public class Model1{
}
public class Model2{
}
I am building a class Bootstrap for bootstrapping other classes that implement Bootstrappable.
// interface that every class must implement that needs to be bootstrapped
class Bootstrappable implements Runnable {
public foo();
}
class MyApp implements Bootstrappable {
public void foo() {}
}
class Bootstrap {
private Bootstrappable instance;
public bootstrap(Class<Bootstrappable> b) {
instance = b.newInstance();
...
}
}
But then I get a compiler error if I try to pass MyApp.class into Bootstrappable.class.
new Bootstrap().bootstrap(MyApp.class);
The method bootstrap(Class Bootstrappable ) in the type Bootstrap is not applicable for the arguments (Class MyApp)
I think is is because inheritance is not for generics. Any way I can handle this?
If you need a class of something that implements Bootstrappable, you should define its type as follows:
Class<? extends Bootstrappable>
Suppose we have three classes - AbstractMessage, AbstractEngine, and AbstractAction. These three classes all reference each other in a generic fashion so each Engine has a corresponding message and action and you can refer to them directly in the code.
public class MyMessage<M extends AbstractMessage<M,E,A>, E extends AbstractEngine<M,E,A>, A extends AbstractAction<M,E,A>> {
This is working fine, but when I attempt to enforce behavior at the highest level I run into some problems. My AbstractAction class has an applyTo method defined thusly:
protected abstract M applyTo(E engine, Object guarantee);
and my AbstractEngine class has this
private final M apply(A action) {
return action.apply(this, this.guarantee);
}
And it is on this line that it balks - complaining that:
The method applyTo(E, Object) in the type AbstractAction<M,E,A> is not
applicable for the arguments (AbstractEngine<M,E,A>, Object)
Now the reason for this is clear - the E in question might be some OTHER AbstractEngine and there's no way to know if the subclass we're calling this from is actually an E.
My question is, how can I say for certainty that if you're going to class MyEngine extends AbstractEngine<M...,E...,A...> that MyEngine is MUST be an E? And to have this certainty baked into AbstractEngine?
Here is a small example that illustrates the problem.
class EngineExample {
static abstract class AbEng<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
final M func(A act) {
return act.apply(this); // compile error here
}
}
static abstract class AbMes<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
}
static abstract class AbAct<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {
abstract void apply(E e);
}
static class RealEng extends AbEng<RealAct, RealMes, RealEng> {
}
static class RealMes extends AbMes<RealAct, RealMes, RealEng> {
}
static class RealAct extends AbAct<RealAct, RealMes, RealEng> {
void apply(RealEng eng) {
System.out.println("applied!");
}
}
}
Use loosest valid parameter type
The simplest solution, is to not actually enforce that this isInstanceOf E. The rules of abstraction already guarantee that this is a safe operation, so it will just work if you change the parameter to just allow any Engine.
abstract Action<E> {
public void apply(Engine<?> e, Object o) {
e.doSomething(o);
}
}
or
abstract Action<E> {
<T extends Engine<?>> public T apply(T e, Object o) {
return e.doSomething(o);
}
}
Use a type-safe wrapper
Another solution is to create another class that binds these 3 together, and move the interaction calls to the wrapper.
abstract System<A extends Action, M extends Message, E extends Engine> {
abstract void apply(A action, E engine) {
engine.render(action.apply())
}
}
Or have the wrapper class take an instance of these 3 and use the passed in versions. This basically is the "allow anything close enough" solution, and adding another class to manage how they can and can't talk to each other.
Pre-cast check
You can also make a reference cast on construction to throw an error if the cast setup is invalid.
private final E dis = (E) this;
This really just moves the problem from from always on compile time, to sometimes on run time, so in general, not a safe/stable solution.
This next solution is a bit specific to your case (using info from our discussion). Basically, you want to define a method in an abstract class that class A and B can inherit, but A and B should not be interchangeable using their base class.
Just use polymophism and use generics just as a type segregator
Here is a modification of the MVCe that uses polymorphism instead, using generics only as a kind of type-category-exclusive-locking mechanism. Basically, Type is a semantic interface to say whether semantically, it makes sense for these classes to talk to each other. (A Physics Engine and Light Engine may share some functionality, but it would make no sense to let them be interchangeable.)
class test {
public static void main(String[] rawrs) {
RealEng re = new RealEng();
RealAct ra = new RealAct();
MockAct ma = new MockAct();
ra.apply(re);
// Remove all code related to Type interface if next line should compile
ma.apply(re); // compile error here
}
static interface Type {
}
static interface Real extends Type {
};
static interface Mock extends Type {
};
static abstract class AbEng<T extends Type> {
final void func(AbAct<T> act) {
act.apply(this); // compile error here
}
}
static abstract class AbMes<T extends Type> {
}
static abstract class AbAct<T extends Type> {
abstract void apply(AbEng<T> e);
}
static class RealEng extends AbEng<Real> {
}
static class RealMes extends AbMes<Real> {
}
static class RealAct extends AbAct<Real> {
#Override
void apply(AbEng<Real> eng) {
System.out.println("applied!");
}
}
static class MockAct extends AbAct<Mock> {
#Override
void apply(AbEng<Mock> eng) {
System.out.println("applied!");
}
}
}
Recursive type-parameters in Java generics are often troublesome.
The problem here is that paradoxically there in no way that you can guaranteed that this makes reference to an instance of E; the only thing that we known about this is that it also extends Engine<M, A, E> but not that is actually E.
Obvious solution is to add a cast ((E)this) and that might be an acceptable solution but you must make clear in the contract (thru javadoc or other documentations) that Engine extending classes must assign E to themselves.
Another solution simply change those method signatures to be a bit more flexible and instead E accept any engine that extends Engine<M, A, E>.
protected abstract M applyTo(AbstractEngine<M, A, E> engine, Object guarantee);
Also consider to reduce the number of type-parameters whenever possible. For example does Engine need to make reference to its own type? Does it have any method that accepts or returns and engine that must be of the same type/class?
EDIT
If you want to keep the E type parameter in applyTo another option is to create a field typed E in AbstractEngine that would be the one passed to the apply to. This field in fact would make reference to this but once it has been "casted" safely at construction.:
public class AbstractEngine<M extends ..., A extends ..., E extends ...> {
private final E engine;
protected AbstractEngine(final E engine) {
this.engine = Objects.requiresNonNull(engine);
}
}
public class MyEngine extends AbstractEngine<MyMessage, MyAction, MyEngine> {
public MyEngine() {
super(this);
}
}
The reason this works is that when we are declaring MyEngine then the compiler does know that MyEngine is E and so the "cast" is safe one. Then the code in AbstractEngine can use the casted value safely thereafter.
The obvious inconvenience is the extra field making reference to this, that although is a bit of memory waste in practice is probably negligible.
Here we are adding the possibility that an engine could designate a surrogate engine to be used in their apply method calls. Perhaps that might be useful... but if you really want to make it impossible to use a third engine here, then you can change the code in the AbstractEngine constructor to compare the passed engine with this and fail at runtime if they are not the same.
protected AbstractEngine(final E engine) {
if (engine != this) {
throw new IllegalArgumentException();
}
this.engine = engine;
}
Unfortunately this cannot be check at compilation time... the second best thing you can do is to make it part of your code tests to verify that all AbstractEngine extending classes are compliant so it would fail at build-time.
I have a base abstract class PipelineStage which has the following definition:
public abstract class PipelineStage<I, O> implements Runnable {
...
public abstract O step(I input);
...
}
I then have numerous concrete pipeline stages with definitions such as:
public class ConcreteStage extends PipelineStage<InputContextClass, OutputContextClass> {
...
#Override
public OutputContextClass step(InputContextClass input) {
input.someMethod();
...
return new OutputContextClass();
}
...
}
However, this has led to a rigid design in which either:
The context classes are very tightly coupled to which stages they are used in.
Every stage needs to have two full interfaces defined, defining all the properties of the input and output classes.
I wanted to improve this design by having generic interfaces that specify properties of the context classes, the ConcreteStage would then specify what interfaces it's input and output context classes must extend.
However, I can't figure out how to do this in a way the compiler likes.
For example:
public class ConcreteStage extends PipelineStage<I extends Interface1 & Interface2,
O extends Interface2 & Interface3> {
...
#Override
public O step(I input) {
input.someMethodFromInterface1();
input.someMethodFromInterface2();
...
// OutputContextClass extends Interface2 & Interface3
return new OutputContextClass();
}
...
}
However, this doesn't compile, showing that class I needs to be imported.
A wildcard also doesn't work, saying No wildcard expected.
Does anyone have any suggestions on how to implement this in a neat, flexible way? Many thanks in advance!
You need to put the type variable declarations on the class, not the superclass:
public static class ConcreteStage<
I extends Interface1 & Interface2, O extends Interface2 & Interface3>
extends PipelineStage<I, O> {
You can also make an interface uniting input interfaces together interface InputInterface12 extends InputInterface1, InputInterface2 {} and then class ConcreteStage extends PipelineStage<InputInterface12, OutputInterface12> {...}.
I would like to decorate a set of classes that derive from a common class (TextView). The classes exist in a library, so I cannot simply modify the base or insert into their inheritance hierarchy.
class A {
}
class B extends A {
}
class C extends A {
}
class D extends B {
void decoration(){}
}
In the example above, class D is the decorating class. The decorating functionality is common to each of my decorating classes.
My question is, is it possible to template the base class in Java? Something like:
class D<T> extends <T ? extends A> {}
So your question is about adding a method dynamically to existing classes? Something similar to categories in Objective-C. This is not simple to be done in Java since once a class is loaded through the ClassLoader you can't add anything dynamically to it.
The easiest thing that comes into my mind is to provide a custom mapping that will be by any chance external to the existing classes. Something like:
interface Method<T extends A> {
public void invoke(T ref);
}
class MethodForA implements Method<A> {
public void invoke(A ref) { .. }
}
class MethodMapper {
Map<Class<?>, Method<? extends A>> mapping;
MethodMapper() {
mapping = new HashMap<Class<?>, Method<? extends A>>();
mapping.put(A.class, new MethodForA());
}
void invoke(A object) {
Method<? extends A> method = mapping.get(object.getClass());
if (method != null) {
method.invoke(object);
}
}
I just wrote this boilerplate code right now so everything won't be surely correct but the way it would work is this one. I guess you will need to do some runtime type checks to avoid blindly casting things.
If instead you were wondering if this is legal:
class A {
}
class B<T> extends A {
}
class C<T, U> extends B<T> {
}
Yes, it is. You can make a child class generic by introducing a type parameter.