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?
Related
I was wondering what is the best way to structure code to ensure compiler knows in very simple cases that passed variable is of correct type. I have created very simple code where class O has its execute method execute that accepts some kind of payload (that extends class P) and performs some kind of operation. The thing is that I do not know how to structure my code to ensure that compiler knows what kind of specific payload I am passing to execute method.
First thing that came to my mind was to introduce method that would return classType of used payload just to came to realization that it is of no use because I am trying to pass some potentially different type of payload to execute method that accepts specific payload.
By the end of the day I could just use reflection but I was wondering how to solve this kind of problem without the use of reflection - whether there is some kind of pattern to solve this problem or some other way to structure my code,...
I know that this kind of simple in terms of printing payload can be solved by introducing method that would print desired payload,... but let's say that I would like to do something more than just printing to console.
Thanks in advance!
import java.util.List;
class Scratch {
public static abstract class O<I extends P> {
public abstract void execute(I payload);
}
public static class O1 extends O<P1> {
#Override
public void execute(P1 payload) {
System.out.println(payload.a);
}
}
public static class O2 extends O<P2> {
#Override
public void execute(P2 payload) {
System.out.println(payload.b);
}
}
public static abstract class P {
abstract Class<? extends P> getClassType();
}
public static class P1 extends P {
public String a = "a";
#Override
Class<? extends P> getClassType() {
return P1.class;
}
}
public static class P2 extends P {
public Integer b = 1;
#Override
Class<? extends P> getClassType() {
return P2.class;
}
}
public static void main(String[] args) {
List<O<? extends P>> os = List.of(new O1(), new O2());
List<P> ps = List.of(new P1(), new P2());
for (int i = 0; i < 2; i++) {
var p = ps.get(i);
// this line would prevent compilation
os.get(i).execute(p);
// this line would also prevent compilation
os.get(i).execute(p.getClassType().cast(p));
}
}
}
The problem with your current code is that you have a list of "any Os" and a list of "any Ps" that aren't related in any way as far as the compiler is concerned. You seem to want to tell the compiler, that actually, os.get(i).execute accepts the same type as ps.get(i) for any valid index i.
To do that, you need to create another class that "groups" an O and a P together, then you can create one list containing these groups:
public static class OPGroup<PType extends P> {
private final O<? super PType> o;
private final PType p;
public OPGroup(O<? super PType> o, PType p) {
this.o = o;
this.p = p;
}
public O<? super PType> getO() {
return o;
}
public PType getP() {
return p;
}
}
List<OPGroup<?>> ops = List.of(
new OPGroup<>(new O1(), new P1()),
new OPGroup<>(new O2(), new P2())
);
for (int i = 0; i < 2; i++) {
var op = ops.get(i);
execute(op);
}
where execute can just be a static method declared anywhere you like:
// you can also make this an instance method of "OPGroup"
public static <PType extends P> void execute(OPGroup<PType> group) {
group.getO().execute(group.getP());
}
The purpose of this is to capture the wildcard in OPGroup<?>.
Anyway, if you can't introduce a new class for some reason, then your code is inherently unsafe. The contents of the lists can be literally any P and any O, so os.get(i).execute(p); could very well fail. If you are willing to accept that, you can do an unsafe (unchecked) cast:
((O<? super P>)os.get(i)).execute(p);
I have an assignment in my Java class, we are learning Generics, I have looked in my notes, my lessons, and even on the internet and I still cant figure out what this last assignment question is asking me to do, which is:
Write a generic “greater-than” function that takes two objects as arguments, each of which has a “value” method which returns an integer and returns the argument whose “value” method returns the larger integer. Your generic function should constrain its type argument so that types without a “value” method cannot be used.
Is there a reason why "value" in quotation marks and how can a method constrain its type argument so that types without a "value" method cant be used. I'm mainly asking for clarification or maybe a little example.
Am I creating a Value class and then doing something like this:
public static <T> int greaterThan(Value obj1, Value obj2){ // Value will have the "value" method?
// do I compare the objects here or in the Value class?
}
They are apparently asking you to implement a generic maxByValue method. Since greater-than contains a hyphen, and is thus an invalid Java identifier anyway, I'll stick to maxByValue.
The requirement of having a value method is mentioned a few times, so let's encode it as an interface:
interface Value {
int value();
}
Now, the main point of having a generic parameter here is to make sure that the return type of the maxByValue is specific enough to be useful. Let's call this type T. In order for the arguments to be comparable, T must be a subtype of Value. The only meaningful source for obtaining the return type is from the types of arguments. Putting together the three points:
Type parameter T subtype Value
Type inferred from the arguments
Result type is T
gives you the signature:
public static <T extends Value> T maxByValue(T a, T b)
There are basically just two meaningful ways of implementing this. Let's take the left-biased one (i.e. left argument is returned if value is the same):
public static <T extends Value> T maxByValue(T a, T b) {
if (a.value() < b.value()) {
return b;
} else {
return /* left as an exercise */;
}
}
Let's try it on a trivial integer example:
class IntValue implements Value {
final int v;
public IntValue(int v) {
this.v = v;
}
public int value() {
return v;
}
#Override
public String toString() {
return "" + v;
}
}
IntValue a = new IntValue(42);
IntValue b = new IntValue(58);
IntValue c = max(a, b);
System.out.println(c); // prints "58"
So far so good. Let's see how precise the type inference is:
static interface Vehicle extends Value {
String doGenericVehicleSound();
}
static abstract class Car implements Vehicle {
public abstract String doCarSpecificSound();
public String doGenericVehicleSound() {
return doCarSpecificSound();
}
}
static class Train implements Vehicle {
public String doGenericVehicleSound() {
return "tk-tk-------tk-tk--tk-tk--------------tk-tk";
}
public int value() {
return 10000000;
}
}
static class Ferrari extends Car {
public String doCarSpecificSound() {
return "rr-rrr-rrrr-rrrrrrr-rrrrrrrrrrrrrrrrrrrr-RRRRRRRRRR";
}
public int value() {
return 222000;
}
}
static class Tesla extends Car {
public String doCarSpecificSound() {
return "... ... ¯\\_(ツ)_/¯";
}
public int value() {
return 50000;
}
}
public static void main(String []args){
System.out.println(maxByValue(new Ferrari(), new Tesla()).doCarSpecificSound());
System.out.println(maxByValue(new Tesla(), new Train()).doGenericVehicleSound());
// System.out.println(maxByValue(new Tesla(), new Train()).doCarSpecificSound());
}
The point to see here is the following. We have the following subtyping relation:
Train extends Vehicle
Car extends Vehicle
Ferrari extends Car
Tesla extends Car
and the following least upper bounds for the concrete instances:
LUB(Train, Train) = Train
LUB(Train, Ferrari) = Vehicle
LUB(Train, Tesla) = Vehicle
LUB(Ferrari, Ferrari) = Ferrari
LUB(Ferrari, Tesla) = Car
LUB(Tesla, Tesla) = Tesla
(and all symmetric cases too).
Now, when we
put two cars into maxByValue, we get out a car (first example), but
when we put a car and a train into maxByValue, we get a more general Vehicle,
so that the car-specific methods become unavailable (examples two and three; third does not compile - rightly so, because a train has no car-methods).
Let's define the interface with value() method
and provide default implementation of isGreaterThan
We could make this interface generic (to work with the types bounded to HasValue)
public interface HasValue<T extends HasValue<T>> {
int value();
default boolean isGreaterThan(T that) {
return this.value() > that.value();
}
}
Now generic methods should be upper-bound T extends HasValue:
static <T extends HasValue> boolean isGreaterThanGeneric(T arg1, T arg2) {
return arg1.value() > arg2.value();
}
static <T extends HasValue> T getGreaterGeneric(T arg1, T arg2) {
return arg1.isGreaterThan(arg2) ? arg1 : arg2;
}
Let's provide some test implementations of HasValue interface and test them.
Note: implementations should be bound HasValue<MyClass> to restrict the interface to be applied to the same type (thanks #Kayaman)
class Apple implements HasValue<Apple> {
final String type;
Apple(String t) {
this.type = t;
}
#Override
public int value() { return 10; }
#Override
public String toString() {
return "apple " + type;
}
}
class Orange implements HasValue<Orange> {
#Override
public int value() { return 20; }
#Override
public String toString() {
return "orange";
}
}
Test:
public static void main(String args[]) {
Apple apple = new Apple("Golden");
Apple apple1 = new Apple("Jonagold");
Orange orange = new Orange();
System.out.println("apple greater than orange = " + getGreater(apple, orange));
System.out.println("apple greater than another apple generic = " + getGreaterGeneric(apple, apple1));
// System.out.println("apple greater than orange generic = " + getGreaterGeneric(apple, orange)); // <-- won't compile:
// required: T,T
// found: Apple,Orange
// reason: inference variable T has incompatible bounds
}
Output:
apple greater than orange = orange
apple greater than another apple generic = apple Jonagold
The previous example is a little complex, but all you're doing is binding your generic value so that it won't accept something that doesn't compile.
With your code...
public static <T> int greaterThan(Value obj1, Value obj2){ }
...the generic here is useless since you only ever use Value objects. This might incidentally work because if you have a FooValue extends Value object, because FooValue is-a Value, it'd be seen as a valid parameter here.
(Note: this is how Java pre-generics was done: inheritance.)
What you're probably looking for is this instead:
public static <T extends Value> int greaterThan(T obj1, T obj2) { }
This is a bound such that the generic type T is bound to all values that are Value and its subclasses.
public class BinaryVertex {
public BinaryVertex parent,left,right;
}
public class BSTVertex extends BinaryVertex {
public void foo() {
left = new BSTVertex();
if(Math.floor(Math.random()*2) == 0) left.foo();
}
}
I'm making a tree / graph api for school, approaching it from a oop standpoint. But im trying to figure out a way for the inherited class to treat some of its base class variables as its own type (i.e. parent,left,right should be treated as BSTVertex when called from BSTVertex but treated as BinaryVertex when called from BinaryVertex) without casting.
I'm thinking of generics but I'm not sure how to implement that in this situation.
UPDATE
Nice, didnt know you could use extend in generics. But I'm getting a BSTVertex<T> cannot be converted to T error with this:
public class Test {
public static void main(String[] args) {
new AVLVertex();
BSTVertex<BSTVertex> v = new BSTVertex<BSTVertex>();
v.foo();
}
class BinaryVertex<T extends BinaryVertex> {
public T parent, left, right;
}
class BSTVertex<T extends BSTVertex> extends BinaryVertex<T> {
public T foo() {
return this; //error here
}
}
class AVLVertex extends BSTVertex<AVLVertex> {
// this might probably end up being abstract too
}
foo needs to return a vertex of the same type as caller, i.e. if AVLVertex calls foo its expecting to get AVLVertex not BSTVertex
Yes, you can use generics like this:
public class BinaryVertex<T extends BinaryVertex<T>> {
public T parent, left, right;
}
public class BSTVertex extends BinaryVertex<BSTVertex> {
public void foo() {
left = new BSTVertex();
if(Math.floor(Math.random()*2) == 0) left.foo();
}
}
The same way the Comparable interface implemented, so subclasses receive the same type to compareTo method. For example, Integer implements Comparable<Integer>, so its compareTo method receives Integer argument.
Also please note the it would be better to create your own random number generator like this:
public class BSTVertex extends BinaryVertex<BSTVertex> {
private static final Random r = new Random();
public void foo() {
left = new BSTVertex();
if(r.nextBoolean()) left.foo();
}
}
UPDATE
In your updated code (in future please ask new question instead) you cannot safely cast, because you can potentially write later:
class RBVertex extends BSTVertex<RBVertex>{}
class AVLVertex extends BSTVertex<RBVertex>{}
This is ok from the compiler's point of view, but your AVLVertex generic argument is actually not an AVLVertex. That's why you have a compilation error in foo() method: your class can be later possibly extended in the way that would make your T incompatible with this.
You can fix this problem by doing an unchecked cast:
#SuppressWarnings("unchecked")
public T foo() {
return (T) this;
}
In this way if you mistakenly create class AVLVertex extends BSTVertex<RBVertex>{}, it will still compile, but upon calling AVLVertex.foo() you may have a runtime ClassCastException.
I am trying to implement and override a method with different return types without being forced to cast the return type.
public abstract class A {
public abstract Object getValue(String content);
}
public class B extends A {
public String getValue(String content) {...}
}
public class C extends A {
public int getValue(String content) {...}
}
public class D extends A {
public boolean getValue(String content) {...}
}
// Main loop:
for (A a : allAs)
{
// I want to use the method getValue() and corresponding to the type return a String, int or boolean without casting the return type
}
My question:
Is it possible to return different types without being forced to cast?
How has the abstract method look like to solve the problem?
I think there has to be a solution because the compiler should know the return type...
In your example, classes C and D will not compile. The overridden methods in them violate the Liskov substitution principle, aka, their return type is incompatible with their parent class. What you are looking to do can be accomplished with generics, as long as you are willing to forego the use of primitives as your return type.
abstract class A<T> {
public abstract T getValue(String content);
}
class B extends A<String> {
public String getValue(String content) { }
}
class C extends A<Integer> {
public Integer getValue(String content) { }
}
class D extends A<Boolean> {
public Boolean getValue(String content) { }
}
What you describe is not possible in general. However, if the subclass returns a "narrower" subtype of the superclass method return, this is called a "covariant return type" and is allowed in Java since JDK 1.5. However, based on your example I do not think covariant return is what you are looking for.
I assume what you want is
for (A a : allAs)
{
String b = a.getValue();
int c = a.getValue();
}
The problem here is, of course, that the compiler has no way of knowing at compile time which of those two statements is correct, and they can't both be correct.
You could use generics.
public abstract class A<T> {
public abstract T getValue(String content);
}
public class B extends A<String> {
public String getValue(String content) {...}
}
etc... int doesn't work as a return type for this, but Integer would.
I'm not typing at a compiler so there may be typos...
As noted by Jim and Chris, if you are looping over As, you can only get the "A" result, which is Object.
In your example, the definition of class B is ok, since String is a subclass of Object. The other two wont compile, since they are primitive types. You could replace them with Integer and Boolean returns to resolve that though.
As for your main loop, if you're iterating over them as references to A, you'll only be able to use A's definition of the method, which returns Object.
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();
}
}