Class Generics method definition [duplicate] - java

This question already has answers here:
How do I make the method return type generic?
(19 answers)
Closed 5 years ago.
Assuming that you have a lot of classes that extends the class Base.
class Base{}
class A extends Base[}
class B extends Base{}
class C extends Base{}
What must I write so that when I write a get method, I will get the class that I want?
public Base get(Class <? extends Base> clazz, final String key){
//not important.
}
I want the method to return Objects of class A, B, or C, depending on the input clazz.

public <T extends Base> T get(Class<T> clazz, final String key) {
}
is closer to what you need. Keep in mind that during method declared generic variables, to have more success you typically put the modifiers outside of the parameter list.

Related

Java Method Overwrite Lists [duplicate]

This question already has answers here:
interface and a class. name clash: same erasure, yet neither overrides other
(3 answers)
Closed 3 years ago.
I have the following structure
public interface A <T extends B> {
List<String> getVals();
void setVals(List<String> vals);
T getContext();
void setContext(T context);
}
public abstract class C <T extends B> implements A {
protected T context;
//Some code
}
public class Regex <T extends B> extends C <T> {
public List<String> getVals() {
//Some code
}
public void setVals(List<String> vals) {
//Some code
}
}
The thing is that, when I compile, I'm getting the following error:
Regex.java:[53,15]
name clash: setVals(java.util.List<java.lang.String>) in Regex and setVals(java.util.List<java.lang.String>) in A have the same erasure, yet neither overrides the other
Why is this? If I ask Intellij to "do the overwrite" for me and it replaces the setVals(List vals) with setVals(List vals) instead.
public void setVals(List vals) {
//Some code
}
It shouldn't be, "exactly the same definition of the method"?
Sorry in advance for my lack of interfaces knowledge
I am guessing you want to implement parameterized type but are actually implementing the raw one.
Replace
public abstract class C <T extends B> implements A
with
public abstract class C <T extends B> implements A<T>
An interesting observation to note here is, that the function setVals is not even using the type parameter T, even then there is a name clash. So it is not obvious at first why this is happening, and why simply extending, A<T> works. At least not to me.
The answer lies here,
The supertype of a class may be a raw type. Member accesses for the
class are treated as normal, and member accesses for the supertype are
treated as for raw types. In the constructor of the class, calls to
super are treated as method calls on a raw type.
and
The type of a constructor (§8.8), instance method (§8.4, §9.4), or
non-static field (§8.3) of a raw type C that is not inherited from its
superclasses or superinterfaces is the raw type that corresponds to
the erasure of its type in the generic declaration corresponding to C.
C in our case is also coincidentally C.
So without extending A<T> from Cs perspective the signature of A is,
void setVals(List vals)
and the compiler doesn't see void setVals(List<String> vals) in Regex as overriding that of A, instead it is considering it overloading, and that too an illegal overload because of type erasure. (You can't overload foo(List) with foo(List<String>)

Passing Child.class as argument [duplicate]

This question already has answers here:
Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?
(19 answers)
Closed 5 years ago.
I have a method that should receives a Class<A>, something like:
protected void method(final Class<A> clazz) {
}
Then when I try to call like method(A.class) it do works, but if I try method(B.class), where B is child of A, I get the message "incompatible types".
The solution is change to Class<B>, but I have another childs that I like to pass as argument to this method(), like C.class.
One solution would be to use a bounded wildcard when defining the parameter:
protected void method(final Class<? extends A> clazz) {
// Code here...
}
With this, you are allowed to pass A's class directly or any class that extends from A.
Or as Pavlo suggested:
protected <T extends A> void method(final Class<T> clazz) {
// Code here...
}
Both will work, but it would help to know what you plan to do with clazz so we can select one over the other.

Java Generics Name type parameter without requiring it [duplicate]

This question already has answers here:
Extract Generic types from extended Generic
(2 answers)
Closed 6 years ago.
Suppose I have some class Edge<A, B> with subclasses that provide the parameterization, e.g class MyEdge extends Edge<MyNodeType, MyOtherNodeType>
I am currently declaring another class that uses Edges as so:
class EdgeHolder<E extends Edge<A, B>, A, B> {
A getFirstNode();
B getSecondNode();
}
and using it as such:
EdgeHolder<MyEdge, MyNodeType, MyOtherNodeType> var = ...
This feels awfully clunky, especially since MyNodeType and MyOtherNodeType are specified in MyEdge's definition.
I'd love to be able to name the parameters A and B in the definition of EdgeHolder because I need compile-time type-checking on its methods' return type, but I don't want to have to specify A and B when I declare variables of type EdgeHolder.
Is there a way to do this (or something like it)?
If not, why not?
There is no type alias in Java, but you can try use this approach.
class Edge<A, B> {
class MyEdgeHolder<E extends Edge<A, B>> extends EdgeHolder<E, A, B> {}
}
class MyEdge extends Edge<MyNodeType, MyOtherNodeType> {
class MyEdgeHolder extends Edge<MyNodeType, MyOtherNodeType>.MyEdgeHolder<MyEdge> {}
}
Use it like this:
MyEdge.MyEdgeHolder var;
Edge<?, ?>.MyEdgeHolder<?> var2 = var;
This approach is very limited, but may fit your specific scenario.
The best idea I could come to reduce typing yet preserve type checking at compile time:
class Edge<A, B> {
A src;
B dest;
}
class EdgeHolderBase<A, B, E extends Edge<A,B>> {
Edge<A,B> in_hold;
}
// explicit specialization of generics
class MyEdge
extends Edge<Integer, Long> {
}
class MyEdgeHolder
extends EdgeHolderBase<Integer, Long, MyEdge> {
// --- One off excessive typing -- ^
}

Is it possible to make generic method signature implementing generic + interface? [duplicate]

This question already has answers here:
Why can't I use a type argument in a type parameter with multiple bounds?
(5 answers)
Closed 7 years ago.
Is it possible to use generics something like that in Java 1.7?
class Test<T> {
public <Z extends T & Serializable> void method(Z test) {
...
}
}
I would like my method to accept only objects of generic type which implements specific interface.
No, unfortunately it is not possible to use generic extends with a generic type and an interface. In fact, it is not even possible to use generic extends with multiple types. If you could, then you could do something like the following.
class Test<T, B extends Serializable> {
public <Z extends T & B> void method(Z test) {
...
}
}
This restriction against extending multiple types may be because of type erasure. At runtime the generics are removed and public <Z extends Serializable> simply becomes public Serializable. So what would <Z extends T & Serializable> be replaced with?
The most approximated form would be:
class Test<T extends Serializable>
{
public <Z extends T> void method(Z test)
{
}
}

Java Generic classes assignability [duplicate]

This question already has answers here:
Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
(3 answers)
Closed 8 years ago.
I have the following classes:
public interface ModelObject {
}
public interface Resource {
}
public interface Transformer <F,T>{
}
public interface WrapperFactory {
Transformer<Resource, Wrap<? extends ModelObject>> createMapper();
}
public class Wrap<E extends ModelObject> {
}
public class AbstractBaseTransformer<F,T> implements Transformer<F,T> {
}
public class ConcreteModel implements ModelObject {
}
public class ConcreteTransformer extends AbstractBaseTransformer<Resource, Wrap<ConcreteModel>> {
}
public class ConcreteFactory implements WrapperFactory {
#Override
public Transformer<Resource, Wrap<? extends ModelObject>> createMapper() {
return new ConcreteTransformer();
}
}
The ConcreteFactory doesn't compile stating that ConcreteTransformer is incompatible with returned
Transformer<Resource, Wrap<? extends ModelObject>>
I can't see what's wrong here. ConcreteTransformer binds 1st parameter to Resource (same as expected) while binding 2nd parameter to:
Wrap<ConcreteModel>
which should bind to:
Wrap<? extends ModelObject>
as ConcreteModel implements it.
Here is a simpler version, to narrow down the issue:
interface ModelObject {}
class ConcreteModel implements ModelObject {}
class Wrap<E extends ModelObject> {}
class SomeGeneric<T> {}
class Simple {
public SomeGeneric<Wrap<? extends ModelObject>> m() {
return new SomeGeneric<Wrap<ConcreteModel>>();
}
}
does not compile either.
Your problem is that a SomeGeneric<Wrap<ConcreteModel>> is not a SomeGeneric<Wrap<? extends ModelObject>>.
Wrap<ConcreteModel> is a subtype of Wrap<? extends ModelObject>? Yes.
Transformer<Resource, Wrap<ConcreteModel>> is a subtype of Transformer<Resource, Wrap<? extends ModelObject>>? No.
It's the same as:
String is a subtype of Object? Yes.
List<String> is a subtype of List<Object>? No.
Basically, for parameterized types to be compatible, if the top-level parameter is not wildcard, then the parameters must match exactly. In your case, the top-level parameter is not wildcard, and the parameters don't match exactly.
What you probably wanted instead was
Transformer<Resource, ? extends Wrap<? extends ModelObject>>
A Wrap<ConcreteModel> can be assigned to a variable of type Wrap<? extends ModelObject>. But the matter here is more complex.
Assume you have a ArrayList<Wrap<? extends ModelObject>> list. When you have such a type, it means that you can add a Wrap<ConcreteModel> to the list, but it also means that you can add a Wrap<ModelObject> to it. In brief, it means you have a list, that can contain a Wrap of anything that can be cast to a ModelObject.
On the other side, having a ArrayList<Wrap<ConcreteModel>> list means you can only add Wrap<ConcreteModel>s to it, while a Wrap<ModelObject> cannot be added to it, because the list can only contain wrapped ConcreteModels, and a wrapped ModelObject is not a wrapped ConcreteModel nor it can be cast to be one.
This is exactly your case. You declared your createMapper() method to return a Transformer<Resource, Wrap<? extends ModelObject>>. This means that the second argument of the returned Transformer must be able to be any subclass of ModelObject, including ModelObject itself. On the contrary, you are trying to return a Transformer<Resource, Wrap<ConcreteModel>>.
The compiler needs to enforce this because Transformer<F, T> could declare a method:
void myMethod(F fObject, T tObject);
If that was the case, the method myMethod of an object of type Transformer<Resource, Wrap<? extends ModelObject>> would accept an object of type ModelObject as its second argument. On the other side, the same method, in a object of type Transformer<Resource, Wrap<ConcreteModel>> cannot accept a ModelObject as its second argument.

Categories

Resources