I have three classes: abstract A and two B and C which extends the A.
class A<T> {
ArrayList<T> someField;
A() {
someField = new ArrayList<T>();
}
ArrayList<T> getSomeField() { return someField; }
}
Now I have B and C
class B<T> extends A {
B() {
super();
}
}
class C<T> extends A{
C() {
super();
}
}
When I try to use getSomeField which is different type for B and C I have to specify which type it is. And my question is how to transfer the T parameter from B class to A to avoid specify the type of ArrayList using for example for each loop. If it is possible at all.
Example:
I wish:
B obj = new B<T>();
for (T item: B.getSomeField) {
do something
}
I have to:
B obj = new B<T>();
for (T item: (ArrayList<T>)B.getSomefield) {
do something
}
With your B and C definitions, you are extending the raw form of class A and creating each class's own T generic type parameter. The raw for of class A means that type erasure occurs on all generic in that class, and the casting becomes necessary.
You need to specify that your subclass's T is the same as the superclass's T:
class B<T> extends A<T> {
and
class C<T> extends A<T> {
Related
I want to bind the type parameter of the child classes. Let's suppose these are the classes:
class A {}
class B extends A {}
class C extends A {}
I want to bind the above classes so if someone creating a class should only be able to pass self class name. Eg:
class B extends A<B> {} // valid
class C extends A<B> {} // invalid
class C extends A<C> {} // valid
The closest I could get to this is:
class A<T extends A<? super T>> {}
class B extends A<B> {}
class C extends A<B> {} // allows it, but I don't want to allow this.
How can this be achived?
Use case:
class A<T extends A<? super T>> {
private T t;
private A() {}
protected A(T t) {this.t = t;}
public T something() { return t; }
}
class B extends A<B> {
public B(B b) {super(b);}
public B anotherthing() { return this.something(); }
}
There's no way to do this at compile-time.
If you really want, you can enforce it at run-time (preventing problematic classes from being instantiated) by adding logic to A's non-private constructor:
protected A(T t) {
validateClass(getClass());
this.t = t;
}
private static void validateClass(final Class<?> clazz) {
final Type superclass = clazz.getGenericSuperclass();
if ((superclass instanceof ParameterizedType)
&& ((ParameterizedType)superclass).getRawType() == A.class
&& ((ParameterizedType)superclass)getActualTypeArguments()[0] == clazz
) {
// OK
} else {
throw new IllegalStateException(
clazz + " does not extend A<" + class.getName() + ">");
}
}
. . . but I don't think that's a great idea.
In general, although Java provides lots of features for compile-time protections, a Java program ultimately relies on developers to voluntarily write correct code. Many aspects of class contracts are documented, but not enforced. (For example, nothing forces the hashCode() and equals() methods to be consistent with each other; but if you're writing Java code, you'll read the documentation of those methods before overriding them, so will know what you need to do.) In your case, you're best off just telling developers that subclasses of A should pass themselves as the type argument to A, giving them an example, and trusting them to do it.
How to get T type after extends?
The code below.
class A<T>{
void method(){
// how to get T type ?
}
}
class B extends A<String> {
}
class C extends B {
}
class D<T> extends A<List<T>>{
}
class E extends D<String>{
}
class Main{
public static void main(String[] args){
C c = new C();
c.method();// I want to get T type here is String.
E e = new E();
e.method();// I want to get T type here is List<String> but I can only get String.
}
}
If I create a B, I can use getGenericSupperclass to get T, but when I create a C, I can't.
You should either pass an object of the generic type with the constructor of your A or create an abstract method that returns an object.
Then, your method uses the object to get the class.
Passing an object with the constructor:
class A<T>{
private T dummy;
public A(T dummy){
this.dummy = dummy;
}
void method(){
System.out.println("Our type T is a " + dummy.getClass().getName());
}
}
Using an abstract method:
abstract class A<T>{
public abstract T getDummy();
void method(){
System.out.println("Our type T is a " + getDummy().getClass().getName());
}
}
Instead of an instance of T the various solutions could also pass the class of T.
For instance:
abstract class A<T>{
public abstract Class<T> getGenericClass();
void method(){
System.out.println("Our type T is a " + getGenericClass().getName());
}
}
Personally, I prefer this solution.
Of course, al derived classes should be adapted.
For instance:
class B extends A<String> {
#Override
public Class<String> getGenericClass(){
return String.class;
}
}
You can not.
This problem is caused by something called Type Erasure, which means that Java doesn't store any information about class' generics at runtime, and therefore there is no way to acquire them.
One possibility to work-around this is adding a constructor to A which takes a parameter of type Class and passing the class explicitly by the extending class:
class B extends A<String> {
public B() {
super(B.class)
}
}
This is what I want:
interface A {}
abstract class B implements A {}
class C extends B { /*few fields*/ }
class D extends B { /*few different fields*/ }
public void doSomething(Class<A> clazz) {
if(clazz.isAssignableFrom(B)) {
doSomethingElse((Class<? extends B>)clazz); // casting is good, but cannot pass this way to doSomethingElse
}
}
public <T extends B> void doSomethingElse(Class<T> clazz) {
if(clazz.isAssignableFrom(C)) {
// do something with C fields
} else if(clazz.isAssignableFrom(D)) {
// do something with D fields
}
}
But obviously I cannot cast the class type this way.
Is there a way to do it? I am very curious...
Thanks!
First of all, a value of type Class<A> can only be the class object for the exact class A, it cannot be any other class. The class object for some other class B would be Class<B>, and Class<B> is never a subtype of Class<A>. You probably want a Class<? extends A> parameter instead.
Second, your use of .isAssignableFrom() seems backwards (besides the fact that it's syntactically invalid as B is not a valid expression). clazz.isAssignableFrom(B.class) means that the class represented by clazz is a superclass of B, in which case it makes no sense to cast clazz to Class<? extends B>. You probably want B.class.isAssignableFrom(clazz) instead.
Once you make the first change above (make clazz type Class<? extends A>), the cast will compile, although it will be an unchecked cast. If you don't want an unchecked cast, instead of (Class<? extends B>)clazz, you can do clazz.asSubclass(B.class).
I am with a sort of trouble when using java generics in the visitor pattern.
My code is something like that:
public interface MyInterfaceVisitor<A, B> {
public A visitMyConcreteObject(MyConcreteObject object, B parameter);
}
public interface MyObject {
public <A, B> A accept(MyInterfaceVisitor<A, B> visitor, B parameter);
}
public class MyConcreteObject implements MyObject {
#Override
public <A, B> A accept(MyInterfaceVisitor<A, B> visitor, B parameter) {
return visitor.visitMyConcreteObject(this, parameter);
}
}
public class MyConcreteVisitor implements MyInterfaceVisitor<????> {
#Override
public <X extends C> X visitMyConcreteObject(MyConcreteObject object, Class<X> parameter) {
// Do a lot of things.
// Return an instance of the given class.
}
// This method is the entry point of the MyConcreteVisitor.
public <X extends C> void someOtherMethod(Class<X> parameter) {
MyObject m = ...;
X x = m.accept(this, parameter);
...;
}
}
public class C {}
public class Dog extends C {}
public class Cat extends C {}
public class Client {
public static void main(String... args) {
MyConcreteVisitor v = new MyConcreteVisitor();
v.someOtherMethod(Cat.class);
v.someOtherMethod(Dog.class);
}
}
// We have other implementations of the visitor that does not matters, like this one.
public class SomeOtherConcreteVisitor implements MyInterfaceVisitor<String, Integer> {
#Override
public String visitMyConcreteObject(MyConcreteObject object, Integer parameter) {
return "foo";
}
}
I need to find what is the generic signature in the ???? that makes the code compilable allowing the overriden method in MyConcreteVisitor class to match the signature in MyInterfaceVisitor interface.
I can't change the signature of the visitMyObject in the MyInterfaceVisitor interface, nor its generics. This happens because others implementations of MyInterfaceVisitor exists and their generics have nothing to with the ones from MyConcreteVisitor.
The MyConcreteVisitor class should not have a generic per-se, so the compiler must allow a MyConcreteVisitor v = new MyConcreteVisitor(); without generating the unchecked or rawtypes warning.
If I change the concrete visitMyObject to public C visitMyObject(MyObject object, Class<? extends C> parameter) and declare the ???? as <C, Class<? extends C>>, I would need to add a cast in the someOtherMethod.
How to define the generic type making it compilable without getting the unchecked or rawtypes warning, changing the interface or adding a cast? Is this even possible in java or I am abusing the generics too much?
The issue is that your implementation is trying to introduce another type parameter X extends C to the method visitMyConcreteObject and resolve the B parameter with it. You can't make visitMyConcreteObject generic with X but try to resolve B with a type parameterized by X, e.g. Class<X>, because B is resolved at the class declaration but X is only declared by a method of the class.
From what I can see, you have two options. Either make MyConcreteVisitor generic on X:
public class MyConcreteVisitor<X extends C> implements MyInterfaceVisitor<X, Class<X>> {
#Override
public X visitMyConcreteObject(MyConcreteObject object, Class<X> parameter) {
// Do a lot of things.
// Return an instance of the given class.
}
}
Or get rid of X and lose type safety (beyond the concrete type C):
public class MyConcreteVisitor implements MyInterfaceVisitor<C, Class<? extends C>> {
#Override
public C visitMyConcreteObject(MyConcreteObject object, Class<? extends C> parameter) {
// Do a lot of things.
// Return an instance of the given class.
}
}
i think this is what you are looking for:
public class MyConcreteVisitor implements MyInterfaceVisitor<Object,Class<?>> {
#Override
public Object visitMyConcreteObject(MyConcreteObject object, Class<?> parameter) {
// Do a lot of things.
// Return an instance of the given class.
}
// This method is the entry point of the MyConcreteVisitor.
public <X> void someOtherMethod(Class<X> parameter) {
MyObject m = ...;
X x = parameter.cast(m.accept(this, parameter));
...;
}
}
I would like to take the contents of the G.myUglyList list here and pass it to the Outer.send() method. I do not understand why this gives a compiler error. ? extends Inner is the type I parameterize Outer with. So why is it rejecting an Inner passed to it? It wants a "? extends Inner", which isn't a type.
I want the list declared as List<Outer<? extends Inner>> so it can take subtypes of Inner. (Please see the edit below for why this is)
interface Outer<T> {
void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}
public class G {
List<Outer<? extends Inner>> myUglyList;
void foo() {
Inner xxx = null;
for (Outer<? extends Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}
I get this error:
error: method send in interface Outer<T#2> cannot be applied to given types;
required: CAP#1
found: Inner<T#1>
reason: actual argument Inner<T#1> cannot be converted to CAP#1 by method invocation conversion
where T#1,T#2 are type-variables:
T#1 extends Object declared in class G
T#2 extends Object declared in interface Outer
where CAP#1 is a fresh type-variable:
CAP#1 extends Inner<T#1> from capture of ? extends Inner<T#1>
edit: I got a lot of answers saying just make the list of type List<Outer<Inner>>, but that is incorrect. I will not be able to add subtypes of Inner if I do that. If I try to add an Outer<Inner2>, it would fail. So list must be of type List<Outer<? extends Inner>>.
interface Inner2 extends Inner {}
class G {
void foo() {
Outer<Inner2> foiled = null;
myUglyList.add(foiled); //this will fail if list is of type List<Outer<Inner>>
Inner xxx = null;
for (Outer<? extends Inner> outer : myUglyList) {
outer.send(xxx); //error
}
Change your code for:
interface Outer<T> {
void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}
public class G {
List<Outer<Inner>> myUglyList;
void foo() {
Inner2 xxx = null;
for (Outer<Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}
And it will compile
Update:
// No matter if you put 'T extends Inner' here, the 'add' won't compile
interface Outer<T extends Inner> {
void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}
public class G {
List<Outer<Inner>> myUglyList;
void foo() {
Outer<Inner2> foiled = null;
// This way, the 'add' invocation will compile, but it
// breaks the generic and generates a warning.
//
// Casting 'foiled' to (Outer<Inner>) will also fail
// because the compiler sees Outer<Inner2> as complete different type
// from Outer<Inner>
myUglyList.add((Outer) foiled);
Inner xxx = null;
for (Outer<Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}
Just declare
List<Outer<Inner>> myUglyList;
You can then add subtypes of Inner without restriction. By declaring it
List<Outer<? extends Inner>> myUglyList;
you are saying that myUglyList is "a list of Outer<some specific (but unknown) subtype of Inner>". That's not what you want.
outer is of type Outer<? extends Inner>, i.e. of some unknown subtype of Inner and its send method takes an object of that same subtype.
For example outer may be of type Outer<OtherInner> and then outer.send needs a OtherInner, so outer.send(xxx) would be wrong.
PECS - Producer extends Consumer super
Because outer is parameterized with extends, you cannot pass anything (except null) into its send method.
for (Outer<? extends Inner> outer : myUglyList) {
outer.send(xxx); //error
}
In that, Outer<? extends Inner> outer, so the actual type is unknown (?). send takes something unknown that extends Inner, and also outer has something that extends Inner but still unknown.
Update
interface Outer<T extends Inner> {
void send(T message); //this can take instance of subtype of Inner
}
interface Inner {}
interface Inner2 extends Inner {}
class G {
List<Outer<Inner>> myUglyList; //you can add instances of subtypes of Inner
void foo() {
Inner xxx = null;
for (Outer<Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}