I have the following classes and interfaces
interface R
class A extends Component implements R
class B extends JButton implements R
class C extends JPanel implements R
class D extends xyz (that extends Component) implements R
So I have several classes that all extend some kind of Component (more or less directly) and that all implement R.
Then I have a different class F that has variables AND methods that needs to work like this:
public class F {
public TYPE myVariable;
public myMethod void (TYPE argument) {
//...code...
myVariable = argument;
actionThatRequiresComponent(argument);
argument.actionDefinedInR();
//...code...
}
public anotherMethod void () {
//...code...
myMethod(myVariable);
//...code...
}
}
The problem is, that TYPE has to meet two requirments: It has to be any kind of Component and has to implement the interface R. The variable has therefore the same requirements.
I'm not sure at all which approach to take? Shall I make some kind of abstract classes extending Component, implementing R? Shall I skip the requirement of interface R and just do it with try catch? Shall I work with generic classes and how do I do that when it comes to variables?
Any suggestions?
If you want to write a method that accepts a parameter that must extend Component and implement R, you can do it like this:
public <T extends Component & R> void myMethod(T item) {
...
}
Then you should be able to pass into your method any argument whose type extends/implements the types you specified.
See https://docs.oracle.com/javase/tutorial/java/generics/bounded.html
Related
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{
}
Assign to a variable an object that extends a class and implements an Interface at the same time.
I have a method like this
public static <T extends Component & MyInterface> T instance() {
if (test1) return new MyLabel();
if (test2) return new MyCombo();
if (test3) return new MyText();
}
class MyLabel extends JLabel implements MyInterface {
...
}
class MyCombo extends JComboBox implements MyInterface {
...
}
class MyText extends JTextField implements MyInterface {
...
}
this means the instance() returned object is a Component AND implements MyInterface.
and I can do something like
instance.setEnable(true); // calling a Component method
instance.foo(); // calling a MyInterface method
Now I want to assign the returned value to a variable: how to declare the variable in order to bring with the variable all the Generics info?
I expect to be able to do something like this:
static <T extends Component & MyInterface> T myVar = instance();
myVar.setEnable(true); // calling a Component method
myVar.foo(); // calling a MyInterface method
and also this:
static void f1(Component c) {}
static void f2(MyInterface c) {}
f1(myVar);
f2(myVar);
In my opinion the question is different from the one in Why can't I use a type argument in a type parameter with multiple bounds? because I'm not using a type parameter inside a generic class declaration.
Based on John Bollinger suggestion I do some other experiments and found a possible "solution" (however not as simple as I required).
But I think my wrap() method is different from what John meant.
public final class Wrap<X extends Component & MyInterface> {
public final X x;
public Wrap(X x) {
this.x = x;
}
}
public static <X extends Component & MyInterface> Wrap<X> wrap(X x) {
return new Wrap<X>(x);
}
static Wrap<?> myVar = wrap(instance());
myVar.x.setEnabled(true); // Component method
f1(myVar.x); // Component parameter
myVar.x.foo(); // MyInterface method
f2(myVar.x); // MyInterface parameter
I expect to be able to do something like this:
static <T extends Component & MyInterface> T myVar = instance();
myVar.setEnable(true); // calling a Component method
myVar.foo(); // calling a MyInterface method
I'm afraid not. Java does not offer generic variables, and for the most part it wouldn't make sense to do so. You may declare the type of an instance variable as a type parameter of its class, but you cannot give any variable its own, independent type parameter like you can a method. There is no way to declare a variable that has two types.
If you want to be able to make use of both facets of myVar, as shown in the example, then its type must be declared as a specific type that extends or implements both supertypes. There are two main alternatives for that:
Make the instance() method return such a type. This is probably the most natural solution, since that method doesn't depend on T for any purpose other than to hang supertypes upon.
public class MyInterfaceComponent extends Component implements MyInterface {
// ...
}
MyInterfaceComponent myVar = instance();
Dynamically generate a wrapper object of such a type that adapts general objects that extend the class and implement the interface to a particular type that does so.
MyInterfaceComponent myVar = wrap(instance());
The latter makes sense to me only if there's a possibility that you need to handle externally-provided objects that extend the class and implement the interface, but whose specific class you cannot control.
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> {...}.
In this factory, which returns Components which also implement a special interface, I get the error "Type mismatch: cannot convert from SpiffyCombo to C" in createSomethingSpiffy.
Am I doing something wrong, or is it expected that I have to cast SpiffyCombo to C here?
class Factory {
public static <C extends Component & SpiffyComponent> C createSomethingSpiffy(Object... params) {
C comp = new SpiffyCombo();
// real method will be more complex
return comp;
}
}
class SpiffyTextField extends Component implements SpiffyComponent {
public void wow() { ... }
}
class SpiffyCombo extends JComboBox implements SpiffyComponent {
public void wow() { ... }
}
interface SpiffyComponent {
void wow();
}
A type parameter is really only useful from a call site (+/- a few cases). Within the scope of the type parameter, the type is basically its bounds. So although a SpiffyCombo fits the bounds of C, not every possible type bound to C is a SpiffyCombo. The compiler can therefore not let you use the value of either interchangeably.
You seem to want to achieve something like
abstract class HellaSpiffyComponent extends Component implements SpiffyComponent {}
public static HellaSpiffyComponent createSomethingSpiffy(Object... params) {...}
and makes your corresponding class extend HellaSpiffyComponent instead of extending Component and implementing SpiffyComponent.
I have an interface that ensures objects can make copies of themselves:
public interface Duplicable<T extends Duplicable<T>> {
public T duplicate();
}
I now have
class X implements Duplicable<X>
but I also have a class Y that extends X.
This isn't a problem, until I need another generic class:
public class DoStuffWithDuplicable<T extends Duplicable<T>>
I can't use a generic version of DoStuffWithDuplicable using Y, since it does not implement Duplicable<Y> but Duplicable<X> since it inherits it from X.
So I tried
public class DoStuffWithDuplicable<T extends Duplicable<? super T>>
.. but this means later introducing an unsafe cast
(T) obj.duplicate()
in the code body. Also the class parameters are more convoluted and the usage of the class harder to understand. Any ideas how to get around this problem?
I may not have understood your question properly, but I'll give it a go.
First of all, why do you have an interface that extends itself like that?
What you can try is this:
public interface Duplicable<T> {
public T duplicate();
}
Then when you use another class where you want the generic parameter to be Duplicable, you do it like this:
public class X<T extends Duplicable<T>> {
code...
}
Now when you inherit from X, any generic component in the subclasses will have to be Duplicable.
It is not possible to do this in Java.
Assume you call obj.duplicate() on an object of type Y. Then the typesystem can only ensure that it will return an object of type X, since Y implements Duplicate<X>.
But you can just create a DoStuffWithDuplicable<X> and pass Y objects to it.
DoStuffWithDuplicable<X> blub = new DoStuffWithDuplicable<X>();
Y y = (Y) blub.doStuff(new Y());
For return values, the client of your library can just use safe casts, as he probably knows the concrete types.
An other option would be to use unsafe casts in the library and check the types manually:
class DoStuffWithDuplicable<T extends Duplicable<? super T>> {
T doStuff(T obj) {
#SuppressWarnings("unchecked")
T t = (T) obj.duplicate();
if (!t.getClass().equals(obj.getClass()))
throw new ClassCastException("...");
return t;
}
}