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> {...}.
Related
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
Suppose i have an interface and two extending classes, like below;
public interface UpdateHelper<T>{
List<T> getItemsToOperate();
}
public class ProfileUpdateHelper implements UpdateHelper<Profile>{
//class logic
}
public class PlayerUpdateHelper implements UpdateHelper<Player>{
//class logic
}
Player and Profile are two concrete classes. When i design my classes like above everything is fine. But i would like to introduce another abstraction layer between concrete Profile and Player classes such as;
public abstract class Updatable{
//common attributes will be here
}
public class Player extends Updatable{
}
public class Profile extends Updatable{
}
And use my helper classes like that;
public interface UpdateHelper<T>{
List<T> getItemsToOperate();
}
public class ItemUpdateHelper<? extends Updatable> implements UpdateHelper<Updatable>{
//class logic
}
I think I should use wildcards since any class instance extending updatable can be used with helper classes and it should not matter which sub-class instance is being used.
But when i write like above i get an unexpected wildcard error just after class names and code won't get compiled. Am i missing something, doing something wrong or something like that can't be done in java. By the way I am using java 8.
You can't use wildcards in class declaration. Instead, you pass a type parameter like T:
public class ItemUpdateHelper<T extends Updatable> implements UpdateHelper<Updatable>{
...
}
You can specify concrete implementation of Updatable:
ItemUpdateHelper<Player> playerHelper = new ItemUpdateHelper<>();
ItemUpdateHelper<Profile> profileHelper = new ItemUpdateHelper<>();
or not:
ItemUpdateHelper helper = new ItemUpdateHelper();
You would want to implement it like,
public class ItemUpdateHelper<T extends Updatable> implements UpdateHelper<T>{
}
I have below classes and interfaces.
SuperInterface.java
public interface SuperInterface{/*some logic*/}
SubOneInterface.java
public interface SubOneInterface extends SuperInterface{/*some logic*/}
SubTwoInterface.java
public interface SubTwoInterface extends SuperInterface{/*some logic*/}
One.java
public class One{/*some logic*/}
Two.java
public class Two{/*some logic*/}
SubOne.java
public class SubOne extends One implements SubOneInterface{/*some logic*/}
AnotherSubOne.java
public class AnotherSubOne extends One implements SubTwoInterface{/*some logic*/}
SubTwo.java
public class SubTwo extends Two implements SubOneInterface{/*some logic*/}
AnotherSubTwo.java
public class AnotherSubTwo extends Two implements SubTwoInterface{/*some logic*/}
Now i have to write a class which will hold the implementation classes of both SubOneInterface and SubTwoInterface.
public class ClassesHolder{
private List<One> one;
private List<Two> two;
//setters and getters
}
Now ClassesHolder should accept all the objects(sub classes of One and Two) which implements either SubOneInterface or SubTwoInterface But not mix of both interfaces.
IF they try to populate the lists with mixed interface implementations then exception should be thrown.
How can i do that?
You can't easily exclude classes that implement a particular interface. If your contract requirement references SubOneInterface, then it'll accept classes that implement SubOneInterface, regardless of what else they implement.
Trying to do otherwise seems like a bad design. If your ClassesHolder contains a class implementing SubOneInterface, then that's how it will refer to that class, and any other functionality will be hidden, due to the additional interfaces not being referenced.
You could inspect your classes upon addition to th elist e.g.
public void addToListOfOnes(final SubOneInterface obj) {
if (obj instanceof SubTwoInterface) {
// throw an exception
}
}
but that seems very poor/counterintuitive. I would take a step back and look at your design again.
Have a look at my example below. If you could introduce another interface as the base type of your interfaces, this solution should work for your. Once instantiated, it will either except subtypes of One or subtypes of Two.
public class Example {
public static void main(String[] args) throws Exception {
ClassesHolder<One> ones = new ClassesHolder<One>();
ones.add(new SubOne());
ones.add(new SubSubOne());
}
}
interface Zero {}
interface One extends Zero {};
interface Two extends Zero {};
class SubOne implements One {};
class SubSubOne implements One {};
class SubTwo implements Two {};
class SubSubTwo implements Two {};
class ClassesHolder<V extends Zero> {
public <T extends V> void add(T item) {}
}
Using Class.isInterface() you can check if it belongs to a particular interface.
As per your requirement you want to check before adding to a list you are trying to check if a class is an Interface of SubOneInterface or SubTwoInterface But not mix of both interfaces.
Does that make sense?
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.
I don't know why I can't find an answer to this online.
I have classes that implement multiple methods and I would like to write methods to expect them. I don't know how to do it though or if it's even possible.
E.g:
public void yellAtPet(<? extends Pet implements YellableAt> arg) {
arg.yellAt("Don't go there!");
arg.pet("Good Boy");
}
Extends is used for both interfaces and parent classes.
If you want to inforce multiple extends you needs something like:
<T extends ClassA & InterfaceB>
To enforce this on a method, generify the class:
public class MyClass<T extends something & somethingelse>{
public void doSomething(T arg)
{
//call methods defined by either interface
}
}
This should work fine as a generic method, without making your entire class generic:
public <T extends Pet & YellableAt> void yellAtPet(T arg) {
arg.yellAt("Don't go there!");
arg.pet("Good Boy");
}