I have a Super class and some Sub class that extend the super class. Every sub class have some constructor methods that accept a type of any Sub type.
abstract class Super {}
final class Sub1 extends Super {
public Sub1(Sub1 arg) {}
//...
public Sub1(Sub4 arg) {}
}
//...
final class SubN extends Super {
public SubN(Sub3 arg) {}
//...
public SubN(SubN arg) {}
}
}
Now I want to create a method in the Super class to cast from one Sub type to another. Let's say
public Super cast(Super arg) {
if (arg instanceof Sub1) {
return new Sub1(this);
} else if (arg instanceof Sub2) {
return new Sub2(this);
}//...
return null;
}
It would be stupid to repeat this pattern for all the sub classes. A solution that I found out is this one (using reflection) but is too slow.
public Super cast(Super arg) {
try {
Class<? extends Super> type = arg.getClass();
return type.getConstructor(this.getClass()).newInstance(this);
} catch (Exception e) {
return null;
}
}
Are there alternatives?
Why not do the reverse? Instead of super.cast(sub) do sub.copy(super) Example:
class Sub1 extends Super {
public Super copy(Super input) {
return new Sub1(input);
}
}
class Sub2 extends Super {
public Super copy(Super input) {
return new Sub2(input);
}
}
etc.
This is called in nearly the same way and prevents having any if statements, and gets exactly the same functionality.
If your old code was:
void doSomething(Super super, Super iAmActuallyASub) {
Super superDuper = super.cast(iAmActuallyASub);
}
The new code would be
void doSomething(Super super, Super iAmActuallyASub) {
Super superDuper = iAmActuallyASub.copy(super);
}
Related
How can I instantiate a new Object of a generic class inside of a generic method, exactly with the same type that is passed (as type) to that method?
(Something like passing a variable from method parameters to a class constructor.)
Example: Both B and C are derived from A. I want the T in the new instance of GenericClass (that is instantiated in the genericMethod and named genericClassT) to be B or C (dependent on genericMethod invoking).
class A {}
class B extends A {}
class C extends A {}
abstract class GenericClass<T extends A> { ... }
public static void main(String[] args) {
...
genericMethod(B.class);
genericMethod(C.class);
}
<T extends A> boolean genericMethod(Class<T> tClass) {
final GenericClass<T> genericClassT = new GenericClass<T>() {
#Override void test(T input) {}
}; // THE PROBLEM IS HERE:
// The T(s) in this statement aren't the same T that passed to method!
// They Are `A` always (not `B` or `C`). How can I pass the same T that passed to the method?
...
}
Full Test (genericMethod in the below code renamed for better meaning):
class A {}
class B extends A {}
class C extends A {}
abstract class GenericClass<T extends A> {
boolean is_T_equals_to_B() {
try {
test((T) new B());
return true;
} catch (ClassCastException e) {
return false;
}
}
abstract void test (T input);
}
public static void main(String[] args) {
final GenericClass<B> genericClassB = new GenericClass<B>() {
#Override void test(B input) {}
};
final GenericClass<C> genericClassC = new GenericClass<C>() {
#Override void test(C input) {}
};
// These work fine:
System.out.println(genericClassB.is_T_equals_to_B()); // prints true
System.out.println(genericClassC.is_T_equals_to_B()); // prints false
// These don't work:
System.out.println(is_T_equals_to_B_in_inner_instance(B.class)); // prints true
System.out.println(is_T_equals_to_B_in_inner_instance(C.class)); // prints true ... I don't want this!
}
<T extends A> boolean is_T_equals_to_B_in_inner_instance(Class<T> tClass) {
final GenericClass<T> genericClassT = new GenericClass<T>() {
#Override void test(T input) {}
}; // THE PROBLEM IS HERE:
// The T(s) in this statement aren't the same T that passed to method!
// They Are `A` actually (not `B` or `C`). How can I pass the same T that passed to the method?
return genericClassT.is_T_equals_to_B();
}
I have a doubt in my code :
public abstract class Jogador {
String nome;
int pontos;
Jogador (String n) {
nome = n;
}
void aumentaPontos () {
pontos++;
}
abstract <U extends Jogador> boolean melhor (U outro);
}
class JogadorAdivinha extends Jogador {
JogadorAdivinha (String n) {
super(n);
}
boolean melhor (JogadorAdivinha outro) {
if (this.pontos > outro.pontos)
return true;
return false;
}
}
class JogadorMemoria extends Jogador {
int rodadasGanhas;
JogadorMemoria(String n) {
super(n);
}
boolean melhor(JogadorMemoria outro) {
if (this.rodadasGanhas > outro.rodadasGanhas)
return true;
return false;
}
void aumentaRodadasGanhas() {
rodadasGanhas++;
}
}
I'll have compilation problem at both the child classes of Jogador.
But as you can see, only JogadorMemoria has rodadasGanhas.
So, I want to know a way to handle this situation .... if I put as parameter the class Jogador for the method melhor() , I won't be able to receive the children ...
What can I do about it to override the abstract method and to not create a bad smell ??
If you want to implement a method like this in subclasses:
abstract <U extends Jogador> boolean melhor (U outro);
You have to provide override-equivalent implementations, like:
<U extends Jogador> boolean melhor (U outro) { return true; }
You can't drop type variables in subclasses, as the abstract method's declaration says that it has to be able to accept any instance of Jogador as a parameter to the melhor method.
If you want to have specific parameter types on those methods, you define the type variable at class-level:
public abstract class Jogador<U extends Jodador<U>> {
abstract boolean melhor (U outro);
}
and then you can implement this in the subclasses:
class JogadorAdivinha extends Jogador<JogadorAdivinha> {
boolean melhor (JogadorAdivinha outro) { return true; }
}
How can I determine if a Java generic implements a particular interface?
I have tried a few different approaches, but they all results in a "cannot find symbol ... variable T" error.
First Attempt
public abstract class AbstractClass<T> {
public void doFoo() {
if (T instanceof SomeInterface){
// do stuff
}
}
}
Second Attempt
public abstract class AbstractClass<T> {
public void doFoo() {
if (SomeInterface.class.isAssignableFrom(T)) {
// do stuff
}
}
}
You can't.
Workaround 1
Add a constructor taking the class of the object.
public abstract class AbstractClass<T> {
private Class<T> clazz;
public AbstractClass(Class<T> clazz) {
this.clazz = clazz;
}
public void doFoo() {
if (clazz instanceof SomeInterface){
// do stuff
}
}
}
Workaround 2
Add a constraint to the type T with T extends SomeInterface, thereby restricting the type T to be a subtype of SomeInterface.
public abstract class AbstractClass<T extends SomeInterface> {
public void doFoo() {
// do stuff
}
}
Put a bound on it.
public abstract class <T extends SomeInterface> { }
Then you're guaranteed that it will be at least SomeInterface when passed through as an argument to a method.
From your approach, there's no way to do it, since you don't reference an instance of T anywhere in your code. If you added an argument to it, you'd be able to at least get further.
public void doFoo(T obj) { }
In the following code sample, is there a way to avoid the ugly SuppressWarnings annotations?
The code tests if parameter t is an instance of A and returns another instance of A if so. That satisfies the general contract of createCopy() to return an object of the same type as its parameter, so it is a safe operation. The same goes for the test for B.
I know about Wildcard Capture and Helper Methods but I'm not sure if and how that helps in this situation although the problem appears to be quite similar.
abstract class Base {
public static <T extends Base> T createCopy(T t) {
if (t instanceof A) {
#SuppressWarnings("unchecked")
T copy = (T) new A((A) t);
return copy;
}
if (t instanceof B) {
#SuppressWarnings("unchecked")
T copy = (T) new B((B) t);
return copy;
}
throw new IllegalStateException();
}
}
class A extends Base {
public A() { }
public A(A a) { }
}
class B extends Base {
public B() { }
public B(B b) { }
}
You can pass the class to the method, but that's still ugly:
abstract class Base {
public static <T extends Base> T createCopy(final T t,
final Class<T> klass) {
if (t instanceof A) {
final T copy = klass.cast(new A((A) t));
return copy;
}
if (t instanceof B) {
final T copy = klass.cast(new B((B) t));
return copy;
}
throw new IllegalStateException();
}
}
class A extends Base {
public A() {
}
public A(final A a) {
}
}
class B extends Base {
public B() {
}
public B(final B b) {
}
}
Calling t.getClass() doesn't work either. The reason is that T can be a subtype of A or B (that's why you code is not really type-safe).
EDIT :
Why your code is not really type-safe: imagine a class AA that extends A. If you call your method with an instance of this class, it will create an object of type A and try to cast it to AA.
Say, i have a generic type as below
public class GenericType<T> {
private T someVar;
public void setVar(T var) { this.someVar = var; }
//Rest of the code
}
I want to allow it to take only specific types(String/Integer/Double). I know about bounded wildcards but they don't help me here. In setVar(), I can check the instanceof and throw an Exception if type is not Integer/String etc. Is this the best way to do it?
I have the same problem when doing operations on this type. Depending on the type, I want to do different operations. Inheritance and bounded wildcards seem like the way to go in general for this kind of problem but these are primitive wrappers.
Using Inheritance:
Parent.java
public abstract class Parent<T> {
public abstract void display(T t);
}
ChildString.java
public class ChildString extends Parent<String> {
#Override
public void display(String t) {
// Do something here...
}
}
ChildInteger.java
public class ChildInteger extends Parent<Integer> {
#Override
public void display(Integer t) {
// Do something here...
}
}
ChildDouble.java
public class ChildDouble extends Parent<Double> {
#Override
public void display(Double t) {
// Do something here...
}
}
And access the class child rather than you directly access the parent class.
Update
Here another example:
GenericType.java
public class GenericType {
public void display(Object t) {
String msg;
if(t instanceof String) {
msg = "String";
} else if (t instanceof Integer) {
msg = "Integer";
} else if (t instanceof Double) {
msg = "Double";
} else {
msg = "Another Object";
}
System.out.println(msg);
}
}
SpecificGeneric.java
public class SpecificGeneric {
public static void main(String[] args) {
GenericType basicType = new GenericType();
basicType.display(new String());
basicType.display(new Integer(1));
basicType.display(new Double(0.1));
}
}
You cannot (more than extends something, but in your case you want few unrelated types, so it does not help).
What you can, is check instance passed to method (you already know it). If you want one instace of generic class for eg. String another for Integers, but don't allow eg. Point2D, you can make constructor with parameter Class clazz and check when constructing whether its allowed.
If you are more paranoid, you can store that clazz and in all function compare whether parameter is actualy that class.
This way, you can still create MyClass, but cannot create instance with this type. (But you can cast it, co its not fool proof)
Inferring the desired type say GenericType<Double> and using instanceof when neccesary is the quickest and easy option. Alternatively overload setVar(..) to accept the restricted types in your Generic class.
public static class GenericType<T>
{
private T someVar;
public void setVar(String var)
{
this.someVar = (T) var;
}
public void setVar(Integer var)
{
this.someVar = (T) var;
}
public void setVar(Double var)
{
this.someVar = (T) var;
}
}