A and AService are base classes.
B and BService extend these classes.
A and B are beans containing parameters for the services.
BService expects a B typed argument in the execute method.
public class A
{
private int a1;
public int getA1() { return a1; }
public void setA1(int a1) { this.a1 = a1; }
}
public class B extends A
{
private int b1;
public int getB1() { return b1; }
public void setB1(int b1) { this.b1 = b1; }
}
public abstract class AService
{
public int execute(A a)
{
return a.getA1() + getValue();
}
public abstract int getValue(A a);
}
public class BService extends AService
{
public int getValue(A a)
{
B b = (A) a;
return b.getB1();
}
}
Is there a better way to do this code ?
In particular, is there a way to avoid to cast objects ?
It sounds like generics are what you're looking for. Typically, whenever you have a concrete class which can always safely cast a value, you can usually express this via generic parameters (and have it checked at compile time).
In this particular example, you'd declare the AService with a generic parameter which must be some subclass of A. Then you use that parameter to make some methods specific to the particular type - in this case the getValue method, as something like
public class AService<T extends A> {
// Now this takes a T - i.e. the type that a subclass is parameterised on
public abstract int getValue(T a)
// Execute will have to take a T as well to pass into getValue - an A
// wouldn't work as it might not be the right type
public int execute(T a)
{
return a.getA1() + getValue(a);
}
}
where the T is a type parameter (conventionally a single uppercase letter). Then you can declare the BService as
public class BService extends AService<B> {
// The type is checked by the compiler; anyone trying to pass an instance
// of A into this class would get a compile-time exception (not a class cast
// at runtime)
public int getValue(B b) {
return b.getB1();
}
}
Related
Here is a minimal code example. The interface:
interface Individual<T> {
public T getVariableValue(int index) ;
public void setVariableValue(int index, T value) ;
public int getNumberOfVariables() ;
public int getNumberOfObjectives() ;
public Individual<T> copy() ;
}
And the class:
public class minimalExample<S extends Individual> {
private List<S> doCrossover(List<S> s){
S mom = s.get(0);
S dad = s.get(1);
int crossoverPoint = 5;
S girl = mom.copy();
S boy = dad.copy();
for (int i = 0; i < mom.getNumberOfVariables(); i++) {
if(i > crossoverPoint){
boy.setVariableValue(i, mom.getVariableValue(i));
girl.setVariableValue(i,dad.getVariableValue(i));
}
}
return s;
}
}
If i try to compile this i get:
java: incompatible types: Individual cannot be converted to S
Which seems confusing. Doesn' the extends keyword mean that S has to be of type Individual or a subtype?
Which seems confusing. Doesn' the extends keyword mean that S has to be of type Individual or a subtype?
Yes, but that does not mean that the type returned by an S's copy() method is also an S. The Individual interface requires only that it be an Individual.
Moreover, I observe that your class minimalExample is using the raw type Individual, whereas it ought to use a properly parameterized version (or else Individual should be made non-generic).
You may be over-parameterizing here. Does minimalExample really need to use S instead of directly using Individual? Obviously, this example class does not, but perhaps the one that inspired the question doesn't, either.
On the other hand, if you do need a parameter for the specific type of Individual, then perhaps you need to further parameterize that interface to describe the kind of object its copy() method returns:
interface Individual<T,I extends Individual<T, I>> {
public T getVariableValue(int index) ;
public void setVariableValue(int index, T value) ;
public int getNumberOfVariables() ;
public int getNumberOfObjectives() ;
public I copy() ;
}
You could then declare your class MinimalExample with the needed additional information:
public class MinimalExample<T, S extends Individual<T, S>> {
// ...
}
And here is a dummy implementation of Individual that you could use with that:
public class ExampleIndividual<T> implements Individual<T, ExampleIndividual<T>> {
public T getVariableValue(int index) { return null; }
public void setVariableValue(int index, T value) {}
public int getNumberOfVariables() { return 0; }
public int getNumberOfObjectives() { return 0; }
public ExampleIndividual<T> copy() { return new ExampleIndividual<T>(); }
}
The method copy() returns an object of type "Individual", which cannot be assigned to the type "S" since S is a subtype.
Why are girl and boy declared to be of type "S" and not Individual?
Ok i have two enums:
public enum AnotherEnum
{
value1, value2, value3;
}
public enum MyEnum implements MyInterface
{
value1(AnotherEnum);
generic_reference_type a;
MyEnum ( ?? )
{
a = ??
}
GetGenericReference()
{
return this.a;
}
}
I want MyEnum to store a reference to the AnotherEnum class so I'll be able to do this:
MyEnum.value1.GetGenericReference().values();
Is this possible?
If I'm reading your question correctly. you would like to pass a different generic type to each instance of an enum... well you can't do that, because every instance of an enum is from the same class, which can be generic, but if generic must have the same generic parameter.
However, you can get something close to your intention by basing your code around an enum class, which is expressed as Class<? extends Enum<?>>:
public enum AnotherEnum {
A, B, C;
}
public enum YetAnotherEnum {
X, Y, Z;
}
public interface MyInterface {
public Enum<?>[] getGenericReferenceValues();
}
public enum MyEnum implements MyInterface {
value1(AnotherEnum.class),
value2(YetAnotherEnum.class);
final Class<? extends Enum<?>> a;
private MyEnum(Class<? extends Enum<?>> a) {
this.a = a;
}
public Enum<?>[] getGenericReferenceValues() {
return a.getEnumConstants();
}
}
And to see it working:
public static void main(String[] args) {
System.out.println(Arrays.toString(MyEnum.value1.getGenericReferenceValues()));
System.out.println(Arrays.toString(MyEnum.value2.getGenericReferenceValues()));
}
Output:
[A, B, C]
[X, Y, Z]
If you don't know the class, you get get the values of a generic enum with reflections
Object someEnum = ...
// get all the values for the same Enum type.
Object[] enums = someEnum.getClass().getEnumConstants()
I have two interfaces. An interface A, and interface B, which extends interface A. Now, I have class which likes to keep reference of object that either implements A or B. And I would like to provide setter for it. I tried below, but getting type mis match exception.
public interface A {
}
public interface B extends A {
}
public class AB {
private Class<? extends A> object;
public void setObject(Class<? extends A> o){
this.object = o;
}
}
So basically, I would like setObject method to accept an object that either implements interface A or B.
Simple answer:
Type it as A: setObject(A a).
A class that implements B also implements A. Full code:
public class UsesA {
private A a;
public void setObject(A a){
this.a = a;
}
}
Now, if you really want to work with B, you'd type it as B, which would also allow you to treat it as an A, since B inherits from it:
public class UsesB {
private B b; // can call A's methods on this field
public void setObject(B b) {
this.b = b;
}
}
But now you can't pass an A (static) reference to setObject. If you really want to do this, then you'd need to first downcast it as a B, which could fail at runtime. Generics will not improve on this.
If you have an object implementing B, it will also be an instance of A. Because of this, you can make setObject accept any A, which will allow instances of A or B to be passed to it.
public void setObject(A a){
this.object = a;
}
Your code doesn't actually match up with your question. You've stated that
I have class which likes to keep reference of object that either
implements A or B
but the field (called object) is actually a Class, not an Object (instance of a Class).
Your code works if you were truly trying to have your setter accept any interface that extends A. But as you probably realize now from the other answers, you actually want an instance of A :)
public class AB {
private Class<? extends A> type; // renamed from object for clarity
public void setObject(Class<? extends A> type) {
this.type = type;
}
#Test
public void testSetter() {
setObject(A.class); // no errors
setObject(B.class); // no errors
}
}
As suggested earlier if you will use (A a) it will work since B is a type of A. Hence child class can always be represents it's parent.
I have in mind an interface which declares a method for converting a raw score from a survey to a percentile value for a particular category, where the categories are described by more than one otherwise unrelated enum types. So I started with this:
public interface NormTable<E extends Enum<E>> {
Integer percentileForRawScore(E e, int score);
}
I've then got an implementing class for, say, the Foo survey and its Subscale enum:
public class FooSubscaleNormTable implements NormTable<Subscale> {
public Integer percentileForRawScore(Subscale e, int score) {
// Implementation
}
}
And finally, a factory class for creating the appropriate concrete class:
public class NormTableFactory {
public static <E extends Enum<E>> NormTable<E> normTableForSurveyAndType(
String surveyCode, Class<E> clazz) {
if ("Foo".equals(surveyCode) && Subscale.class.equals(clazz)) {
return (NormTable<E>) new FooSubscaleNormTable();
} else {
// ...
}
}
}
I suspect the cast there is wrong, as Eclipse flags it as unchecked, though lets me carry on. The Java 1.6 compiler on the build server, however, is not happy at all and flags them as inconvertible types.
Have I got the signatures in the factory class wrong, or is my whole architecture looking suspect? I note above that the enum types are "otherwise unrelated", though they all represent categories within surveys, and could conceivably implement an interface to unify their types. Would that help?
You shouldn't use a concrete Enum class in your declaring type.
Make FooSubscaleNormTable generic as well
public class FooSubscaleNormTable<E extends Enum<E>> implements NormTable<E> {
public Integer percentileForRawScore(E e, int score) {
if(e instanceof Subscale) {
switch((Subscale) e) {
case X:
// do something
break;
}
}
// return 0;
}
}
and change your factory to
public class NormTableFactory {
public static <E extends Enum<E>> NormTable<E> normTableForSurveyAndType(
String surveyCode, Class<E> clazz) {
if ("Foo".equals(surveyCode) && Subscale.class.equals(clazz)) {
return (NormTable<E>) new FooSubscaleNormTable<E>();
} else {
// whatever else
}
}
}
Then when you invoke it, that is when you pass in your desired enum type.
NormTable<Subscale> scale = NormTableFactory.normTableForSurveyAndType("surveyCode", Subscale.class);
Basically I want to do this:
public interface A {
void a();
}
public interface B {
void b();
}
public class SomeClass {
public SomeClass(<A&B> e) { // Note the type here
e.a();
e.b();
}
}
What I did on the commented line is obviously illegal. I know I can just require the passed object to implement interface A, or interface B, but is there a way to do both?
I guess there are workarounds (like requiring the parameter to be of type A and then check if it is also an instanceof B), but that way I don't get help from the compiler. Do you know of any way to do this? Or maybe a smarter workaround...
You can do it with generics enabled. For example, to accept an instance of some class that implements both CharSequence and Appendable:
public <T extends CharSequence & Appendable> void someMethod(T param) {
...
}
Depending on the design, you can do one of the following:
Make A : B or B : A.
Make an interface C : A, B.
Either way you'll want to have contract that includes both a() and b().
Well, there is the <T extends A & B> f(T ab) notation, but you should favour composition over inheritance. You don't really have to extend anything. Just make a type that is the joint union (product) of both types A and B, as follows:
public abstract class P2<A, B> {
public A _1();
public B _2();
}
Sometimes called a product-2, or a "pair" type. You can create a handy constructor for these:
public final class P {
private P() {}
public static <A, B> P2 p(final A a, final B b) {
return new P2<A, B>() {
public A _1() {
return a;
}
public B _2() {
return b;
}
}
}
}
Note that you can use the same object for both arguments, if A and B are interfaces and your object implements both of them:
P2<A, B> both = P.p(o, o);
Or you're free to use two different objects, making the design nice and decoupled.
You'll find this type, as well as products of up to 8 types, included in the Functional Java library. There's also a type called Either<A, B> that is the disjoint union (sum) of two types, such that it holds a value that is of either type A or B (or both).
Just shooting in the dark, I don't know if this is the correct syntax, ie if you have to redeclare the methods in C but what about this:
public interface A {
void a();
}
public interface B {
void b();
}
public interface C extends A, B{}
public class SomeClass{
public SomeClass(C e) { // Note the type here
e.a();
e.b();
}
}
If you have a method that needs two different interfaces as parameters, just make it take two parameters.
public void foo(A a, B b) {
....
}
It’s not that hard, believe me.