I have these classes:
class Parent {
public Parent() {
}
}
class ChildA extends Parent {
public ChildA() {
super();
}
}
class ChildB extends Parent {
public ChildB() {
super();
}
}
public ListClas(List(Parent) list) {
this.list=list;
}
}
And I want to run ListClas constructor as below.
List<ChildA> list_childA = new ArrayList<ChildA>();
List<ChildB> list_childB = new ArrayList<ChildB>();
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
But the compiler throws an error. How do I do this correctly using polymorphism?
If you want a function that accepts List containing subclasses of a superclass you should use syntax.
public ListClas(List<? extends Parent> list){
this.list=list;
}
It will accept both of them.
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
If you change to List<? extends Parent> list (also change ListClas.list field definition) in your ListClas then it will compile and work.
All of them: List<Parent>, List<ChildA> and List<ChildB> are different concrete parameterized type.
You can read more about this here: https://stackoverflow.com/a/20940807/516167
I think you want your ListClas to look something like this:
class ListClas<T>
{
private List<T> list;
public ListClas(List<T> list)
{
this.list = list;
}
}
Then to create them:
ListClas<ChildA> listClasA = new ListClas<ChildA>(list_childA);
ListClas<ChildB> listClasB = new ListClas<ChildB>(list_childB);
The T is a generic type designation. It allows you to use the same class for multiple runtime types. So you can do the above instead of having to write this:
class AListClas
{
private List<ChildA> list;
public AListClas(List<ChildA> list)
{
this.list = list;
}
}
class BListClas
{
private List<ChildB> list;
public BListClas(List<ChildB> list)
{
this.list = list;
}
}
If you don't need quite as much flexibility you could write your ListClas like this:
class ListClas
{
private List<? extends Parent> list;
public ListClas(List<? extends Parent> list)
{
this.list = list;
}
}
and use it like this:
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
Related
I am trying to make a generic handling of different service implementations and I constantly receive the "Unchecked call due to raw type" error.
I have tried several implementations, but could not quite understand what is the issue here.
I have the following model:
public abstract class Fruit {
public List<String> vitamins;
public String originCountry;
// getters and setters omitted
}
The concrete implementation are the following:
public class Kiwi extends Fruit {
}
public class Pineapple extends Fruit {
}
I have the following interface:
public interface FruitCheckService<T extends Fruit> {
List<String> compareVitaminsFromDifferentCountries(T firstFruit, T secondFruit);
Class<T> getImplementation();
}
With implementations for the 2 models given above:
#Service
public class KiwiCheckServiceImpl implements FruitCheckService<Kiwi> {
#Override
public List<String> compareVitaminsFromDifferentCountries(Kiwi firstFruit, Kiwi secondFruit) {
// some implementation
return new ArrayList<>();
}
#Override
public Class<Kiwi> getImplementation() {
return Kiwi.class;
}
}
And pineapple:
#Service
public class PineappleCheckServiceImpl implements FruitCheckService<Pineapple> {
#Override
public List<String> compareVitaminsFromDifferentCountries(Pineapple firstFruit, Pineapple secondFruit) {
// some implementation
return new ArrayList<>();
}
#Override
public Class<Pineapple> getImplementation() {
return Pineapple.class;
}
}
I have the following class which is manupulating with the different beans:
#Service
public class FruitServices {
private Map<Class, FruitCheckService> beansMap;
#Autowired
public FruitServices(List<FruitCheckService> fruitCheckServices) {
beansMap = new HashMap<>();
fruitCheckServices
.forEach(
fruitCheckService -> {
Class implementation = fruitCheckService.getImplementation();
beansMap.put(implementation, fruitCheckService);
}
);
}
public FruitCheckService getFruitCheckService(Class clazz) {
return beansMap.get(clazz);
}
}
At the end, this is the service where I am calling this:
#Component
public class BusinessService {
#Autowired
private FruitServices fruitServices;
public void compareVitamins(Fruit one, Fruit two) {
Class<? extends Fruit> aClass = one.getClass();
FruitCheckService fruitCheckService = fruitServices.getFruitCheckService(aClass);
List<String> result = fruitCheckService.compareVitaminsFromDifferentCountries(one, two);
}
}
How to use correctly the fruitCheckService without receiving "Unchecked call to 'compareVitaminsFromDifferentCountries(T, T)' as a member of raw type 'exercise2.service.FruitCheckService'"?
The problem is that you are using the raw type Class in your service definition. To get around this problem, you can use the bounded wildcard type ?, as such:
class FruitServices {
private Map<Class<? extends Fruit>, FruitCheckService<? extends Fruit>> beansMap;
public FruitServices(List<FruitCheckService<? extends Fruit>> fruitCheckServices) {
beansMap = new HashMap<>();
fruitCheckServices
.forEach(
fruitCheckService -> {
Class<? extends Fruit> implementation = fruitCheckService.getImplementation();
beansMap.put(implementation, fruitCheckService);
}
);
}
public FruitCheckService<? extends Fruit> getFruitCheckService(Class<? extends Fruit> clazz) {
return beansMap.get(clazz);
}
}
For class BusinessService things are going to be trickier. First, it is necessary to make compareVitamins a generic method to ensure both fruits are of the same type. But even then, I don't believe you can avoid an unchecked cast from the result of getFruitCheckService because, as FruitServices has to deal with services for different types of fruit, you can't have a precise type parameter for the return value of getFruitCheckService.
class BusinessService {
private FruitServices fruitServices;
public <T extends Fruit> void compareVitamins(T one, T two) {
#SuppressWarnings("unchecked")
FruitCheckService<T> fruitCheckService =
(FruitCheckService<T>) fruitServices.getFruitCheckService(one.getClass());
List<String> result = fruitCheckService.compareVitaminsFromDifferentCountries(one, two);
}
}
How to add a generic object to list in java?
Currently, I have two classes doing the same function and would like to integrate them together
public class MyClass1 {
private List<Object1> myList = new ArrayList<>();
public void addList(Object1 o) {
myList.add(o);
}
}
public class MyClass2 {
private List<Object2> myList = new ArrayList<>();
public void addList(Object2 o) {
myList.add(o);
}
}
something like
public class MyClass {
private List<Object> myList = new ArrayList<>();
public void addList(Object o) {
myList.add(o);
}
}
You could make your own class generic:
public class MyClass<T> {
private List<T> myList = new ArrayList<>();
public void addList(T o) {
myList.add(o);
}
}
You can make both classes Object1 and Object2 implement the same interface 'ObjInterface'
public class MyClass {
private List<ObjInterface> myList = new ArrayList<>();
public void addList(ObjInterface o) {
myList.add(o);
}
}
If you want the class to contain only Object1 or only Object2 and never anything else, you can combine the other two answers:
interface ObjInterface {
// may be empty
}
public class MyClass<T extends ObjInterface> {
private List<T> myList = new ArrayList<>();
public void addList(T o) {
myList.add(o);
}
}
MyClass<Object1> object1only = new MyClass<>();
MyClass<Object2> object2only = new MyClass<>();
and add implements ObjInterface to the definitions of Object1 and Object2.
If you add methods common to both classes to ObjInterface, you can call those methods on the T objects in MyClass, since they're guaranteed to be a subclass of ObjInterface.
I'm trying to define an abstract class that takes in a List of things and does stuff. Something like:
abstract public class AbstractClass {
private final List<?> list;
public AbstractClass(List<?> list) {
this.list = list;
}
public List<?> getList() { return list; }
abstract void addToList(List<?> list);
}
public class Class1 extends AbstractClass {
public Class1(List<Integer> list) {
super(list);
}
#Override
void addToList(List<Integer> list) {
// do stuff
}
}
public class Class2 extends AbstractClass {
public Class2(List<String> list) {
super(list);
}
#Override
void addToList(List<String> list) {
// do stuff
}
}
List<Integer> a = new List<Integer>();
Class1 c1 = new Class1(a);
List<Integer> b = c1.getList();
c1.addToList(a);
List<String> c = new List<String>();
Class2 c2 = new Class2(c);
List<Integer> d = c2.getList();
c2.addToList(c);
Having addToList with specific types in the subclasses is generating errors, but I don't know if that's a matter of syntax (with my poor knowledge of generics) or what I'm trying to do itself (is it possible to overload an abstract method like that)?
You should make AbstractClass a typed class instead of using the ? wildcard.
abstract public class AbstractClass<T> {
private final List<T> list;
public AbstractClass(List<T> list) {
this.list = list;
}
public List<T> getList() { return list; }
abstract void addToList(List<T> list);
}
In this case, you would have
public class Class1 extends AbstractClass<Integer> { ... }
public class Class2 extends AbstractClass<String> { ... }
What should be the signature of a method that takes a generic object and returns another generic object, one that either is the same or a sub class of the original class? That is, if the method takes some generic class A, the returned object is guaranteed to be either A or B such that B extends A (directly or indirectly)?
The code below exemplifies what I'm trying to do, in the function getList():
package com.company;
import java.util.ArrayList;
public class Main {
private Main(){
List<String> stringList = new GenericMessageListCreator.getList(StringGenericMessage.class);
}
private class GenericMessageListCreator() {
public List<GenericMessage<T1>> getList(Class<T1 extends GenericMessage> clazz) {
return new ArrayList<T1>();
}
}
private class GenericMessage<T> {
public GenericMessage(){};
private T internalValue;
public void setValue(T value) {
this.internalValue = value;
}
public void echoValue() {
System.out.println("I contain " + internalValue);
}
}
private class StringMessage extends GenericMessage<String>{}
private class IntegerMessage extends GenericMessage<Integer>{}
}
Example aside, in actuality I'm writing a registry of classes that are used for Commands in a command pattern. When I get an object by its class I want to fetch the appropriate Command and pass the object to it.
I think you are looking for this signature:
public <T1 extends GenericMessage> List<GenericMessage<T1>> getList(Class<T1> clazz) {
return new ArrayList<T1>();
}
You'll find more info about generic methods here.
EDIT
Based on what I understand from your sample code, I would go for something like (I corrected some syntax errors in your code):
private class GenericMessageListCreator {
public <U, V extends GenericMessage<U>> List<U> getList(Class<V> clazz){
return new ArrayList<U>();
}
}
private class GenericMessage<T> {
public GenericMessage(){};
private T internalValue;
public void setValue(T value)
{
this.internalValue = value;
}
public void echoValue() {
System.out.println("I contain " + internalValue);
}
}
private class StringMessage extends GenericMessage<String>{}
private class IntegerMessage extends GenericMessage<Integer>{}
Thus, you'll be able to create a List<String from `StringMessage like this:
List<String> stringList = new GenericMessageListCreator().getList(StringMessage.class);
I'm not even sure which method you want to have this behavious on, but I've assuming it's getList():
private class GenericMessageListCreator() {
public <T extends GenericMessage<?>> List<T> getList(Class<T> clazz) {
return new ArrayList<T>();
}
}
Let's assume I have a class A that can be extended. Within that Class A I have a List List<A>. So this class will contain a list with elements A. Now If I subclass this class B extends A, I want class B to have the same member List<B>, ie the same list but this type containing items of type B. Is this possible using generics ? I can see something like A <T extends A>, while declaring List<T>, but I don't like as the information about the class type are already there. Is there another better solution ? Example below:
public class A {
List<A> list = new ArrayList<A>();
}
public class B extends A {
}
I want list to have the generic type of B in class B.
If you want to put the behaviour in the super class, then you're going to have to tell the super class what type of class the subclass is. This can be done by adding a generic type to the super.
public class A<E> {
protected List<E> items;
public A() {
this.items = new ArrayList<E>();
}
}
public class B extends A<B> {
public static void main(String[] args) {
B b = new B();
b.items.add(b);
}
}
You can use extends keyword in generic.
For example:
public class A {
protected List<? extends A> list;
public A() {
list = new ArrayList<A>();
}
public <T extends A> List<T> getList() {
return (List<T>) list;
}
public void setList(List<A> list) {
this.list = list;
}
}
public class B extends A {
public B() {
list = new ArrayList<B>();
}
public static void main(String[] args) {
A a = new A();
a.getList().add(new A());
B b = new B();
b.getList().add(new B());
}
}