Overriding method with Generics - java

I have a base class called GenericOrder that can be used to create an order with any type of products, then I have subclasses of that order that are more specific. My problem is with my ComputerOrder class and a method that I'm overriding. Here's the base class code.
import java.util.List;
import java.util.ArrayList;
public class GenericOrder<T> {
private long orderNumber;
private List<T> products;
private T theClass;
public GenericOrder()
{
products = new ArrayList<T>();
orderNumber = System.currentTimeMillis();
}
public long getOrderNumber() {
return orderNumber;
}
public void addProduct(T newProduct) {
products.add(newProduct);
}
public int getNumberOfProducts() {
return products.size();
}
public List<T> getProducts()
{
return products;
}
public void setProducts(List<T> products)
{
this.products = products;
}
public T get()
{
return theClass;
}
public void set(T theClass)
{
this.theClass = theClass;
}
}
And here is my subClass code. The getProducts is the method I'm having trouble with.
import java.util.ArrayList;
import java.util.List;
public class ComputerOrder<T> extends GenericOrder<T> {
private List<ComputerPart> computerParts = new ArrayList<ComputerPart>();
private String orderType = "Computer Parts";
public ComputerOrder() {
super();
}
public void addProduct(ComputerPart newProduct) {
computerParts.add(newProduct);
}
public String getOrderType() {
return orderType;
}
public int getNumberOfProducts() {
return computerParts.size();
}
public List<T> getProducts()
{
return computerParts;
}
}
The Error I get says cannot convert from List(ComputerPart) to List<T>

The error is pretty clear: getProducts() is declared to return a List<T> yet you're returning a List<ComputerPart>. I think we agree that these two are not equivalent.
Looking at your code it looks like that you actually don't want a generic class since ComputerOrder only accepts ComputerParts. What you want is something like the following:
public class ComputerOrder extends GenericOrder<ComputerPart> {
#Override
public List<ComputerPart> getProducts() {
return computerParts;
}
}

Design wise, I think you should reconsider whether products should be in the GenericOrder class. If GenericOrder is meant only to handle the orders, then it might not make sense to have any product related methods or fields defined there. As it is now you have a products List array in GenericOrder that is not being used because you have defined computerParts List array in ComputerOrder. This makes for bad code. In this case your classes would look like:
public class GenericOrder<T> {
private long orderNumber;
private String orderType;
private T theClass;
public GenericOrder(String orderType) {
this.orderType = orderType;
orderNumber = System.currentTimeMillis();
}
public String getOrderType() {
return orderType;
}
public long getOrderNumber() {
return orderNumber;
}
public T get() {
return theClass;
}
public void set(T theClass) {
this.theClass = theClass;
}
}
and
import java.util.ArrayList;
import java.util.List;
public class PartOrder<T> extends GenericOrder<T> {
private List<T> parts = new ArrayList<T>();
public PartOrder(String orderType) {
super(orderType);
}
public void addProduct(T newProduct) {
parts.add(newProduct);
}
public int getNumberOfProducts() {
return parts.size();
}
public List<T> getProducts() {
return parts;
}
}
and you would have a ComputerPartOrder class like so:
public class ComputerPartOrder extends PartOrder<ComputerPart> {
public ComputerPartOrder() {
super("Computer Parts");
}
}
Otherwise, you might also define the GenericOrder.getProducts method as abstract as per this stackoverflow post.

It actually looks like you don't want your ComputerOrder to be generic.
While a GenericOrder<T> is generic and can be an order of anything, ComputerOrder seems specific to ComputerPart(s) and should extend GenericOrder<ComputerPart>.
This way you will only have to implement List<ComputerPart> getProducts() and your code will be fine.

As your ComputerOrders class looks more specific, consider refactoring your code as below :
public class ComputerOrder extends GenericOrder<ComputerPart> {
#Override
public List<ComputerPart> getProducts() { return computerParts; }
}

Related

How to make this method more generic

i am having some trouble figuring something regarding inheritance in Java. I thought it would be straightforward but it has stumped me.
I have this superclass..
public class MyItem {
private String barCode;
private String price;
public String getBarCode() {
return barCode;
}
public void setBarCode(String barCode) {
this.barCode = barCode;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
And i have these 2 subclasses
public class PromotionalItem extends MyItem {
private String promotion;
public String setPromotion(String promotion) {
this.promotion = promotion;
}
public void getPromotion() {
this.promotion = promotion;
}
}
public class SellableItem extends MyItem {
private String quantity;
public String setQuantity(String quantity) {
this.quantity = quantity;
}
public void getQuantity() {
this.quantity = quantity;
}
}
Now i have a method that i want to make generic, i thought something like this could work...
public void processItem(MyItem item){
if(item.getClass().isAssignableFrom(PromotionalItem.class)){
processPromotionalItem((PromotionalItem)item);
}
else{
processSellableItem((SellableItem)item);
}
}
But I am getting a ClassCastException when i try to cast these items as their respective subclasses. I thought something like this would be do-able. Am i missing something? What is the alternative do something like this?
The code looks like an anti-pattern. What I would do is have an abstract method called process in MyItem and have both subclasses implementing that method:
public class MyItem {
private String barCode;
private String price;
public String getBarCode() {
return barCode;
}
public void setBarCode(String barCode) {
this.barCode = barCode;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public abstract void process();
}
Now if you have a subclass you are forced to implement the process method, and then instead of checking what class it is you can just call the process method directly.
public void processItem(MyItem item){
item.process();
}
Make MyClass abstract and add an abstract process method, like #JoakimDanielson suggested. Then, in your child classes, override that method and implement your own logic.
public abstract class MyItem {
...
public abstract void process();
}
public class PromotionalItem extends MyItem {
...
#Override
public void process() {
// do whatever
}
}
public class SellableItem extends MyItem {
...
#Override
public void process() {
// do whatever
}
}
Then, in your processItem method, just call process:
public void processItem(MyItem item) {
item.process();
}
In your case you should use instanceof instead of isAssignableFrom (be careful though, the syntax is different, more on that below).
isAssignableFrom checks if the parameter object can be written to the object the function has been called from. instanceof checks if the left object is from the same class or a subclass of the right class. This will make more sense once you've seen the syntax of instanceof:
if(item instanceof PromotionalItem){
processPromotionalItem((PromotionalItem)item);
}
So in a nutshell, your logic was just a little off. You were trying to cast from one subclass of your item class to a completely different subclass.
Use the instanceof keyword
if(item instanceof PromotionalItem){
processPromotionalItem((PromotionalItem) item);
} else if(item instanceof SellableItem) {
processSellableItem((SellableItem) item);
}
Make sure you use else if not only else because item might be
something else other than PromotionalItem and SellableItem if you
cast it to a class from which it wasn't build from, you will get a ClassCastException
instanceof is a keyword that is used for checking if a reference variable is containing a given type of object reference or not.
I‘ll only address the issue, as there are enough solutions (I think #Major Ben s one is nice)
item.getClass().isAssignableFrom(PromotionalItem.class)
What this line means is:
„Can I assign to the dynamic class of item an instance of PromotionalItem.“
But now consider this - is it legal?
MyItem item = new PromotionalItem();
Yes, it is. So this will always be true. Hence, you then try to cast to PromotionalItem, even when it is actually not ok.
Also have a look at this. https://stackoverflow.com/a/3657960/2995907
Using abstract class which is great. We can think also with generices like
public class MyItem<T extends MyItem> {
private String barCode;
private String price;
public String getBarCode() { return barCode; }
public void setBarCode(String barCode) { this.barCode = barCode; }
public String getPrice() { return price; }
public void setPrice(String price) { this.price = price; }
public void process(T item) {
if(item instanceof PromotionalItem){
System.out.println("PromotionalItem");
//do something for promotionalItem
} else if(item instanceof SellableItem) {
System.out.println("SellableItem");
//do something for SellableItem
}
}
}
public class PromotionalItem extends MyItem {
private String promotion;
public void setPromotion(String promotion) {
this.promotion = promotion;
}
public String getPromotion() {
return promotion;
}
}
public class SellableItem extends MyItem {
private String quantity;
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public String getQuantity() {
return quantity;
}
}
#Test
public void test_porecessItem() {
PromotionalItem promotionalItem = new PromotionalItem();
SellableItem sellableItem = new SellableItem();
MyItem<PromotionalItem> promotionalItemMyItem = new MyItem<>();
MyItem<SellableItem> sellableItemMyItem = new MyItem<>();
promotionalItem.process(promotionalItem);
sellableItemMyItem.process(sellableItem);
}
By the way, this is just an option which we can think.

java.util.LinkedHashMap cannot be cast to com.common.pojo.myDataDetails

My java class is throwing some error. In my class i am using this to get my data.
((myDataDetails) Names.get(0)).InputParamNames().add("SomeValue");
But it is throwing error
Here is my Pohjo Class.
package common.pojo;
import java.util.Date;
import java.util.List;
public class myDataDetails
{
private String myID;
private List<String> InputParamNames;
private List InputParamData;
public String getmyID() {
return this.myID;
}
public void setmyID(String myID) {
this.myID = myID;
}
public List<String> getInputParamNames() {
return this.InputParamNames;
}
public void setInputParamNames(List<String> InputParamNames) {
this.InputParamNames = InputParamNames;
}
public List getInputParamData() {
return this.InputParamData;
}
public void setInputParamData(List InputParamData) {
this.InputParamData = InputParamData;
}
}
What should I need to change in pojo to avoid this exception.
Your class 'myDataDetails' needs to extend from LinkedHashMap in order to cast it.
What you have right now is a regular POJO class that is not an instance of LinkedHashMap, so you can't cast it as such.
EDIT: It should look like this
package common.pojo;
import java.util.Date;
import java.util.List;
import java.util.LinkedHashMap;
public class myDataDetails extends LinkedHashMap<Object, Object>
{
private String myID;
private List<String> InputParamNames;
private List InputParamData;
public String getmyID() {
return this.myID;
}
public void setmyID(String myID) {
this.myID = myID;
}
public List<String> getInputParamNames() {
return this.InputParamNames;
}
public void setInputParamNames(List<String> InputParamNames) {
this.InputParamNames = InputParamNames;
}
public List getInputParamData() {
return this.InputParamData;
}
public void setInputParamData(List InputParamData) {
this.InputParamData = InputParamData;
}
}

Extend a generic holder class, have it accept only specific objects?

I am trying to understand and accomplish the task of trying to create a class that extends a generic class that accepts all types of classes. So far I have that working. I am trying to create a class that extends a generic holder class and have this class accept only specific objects.
Example, a class called "ComputerOrder" that will not accept an Apple or Orange object but only a ComputerPart or Peripheral object, such as Motherboard or Printer objects. Been stuck on this for 2 weeks. I can't for the life of me figure this concept out. Any help would be appreciated.
abstract class Product{
protected float price;
abstract float price();
public String toString() {
return "Price = " + String.valueOf(price) + " ";
}
}
class Apple extends Product{}
class Orange extends Product{}
class ComputerPart extends Product{
public ComputerPart(float p){
price = p;
}
public float price() {
return price;
}
}
class Motherboard extends ComputerPart{
protected String manufacturer;
public Motherboard(String mfg, float p) {
super(p);
manufacturer = mfg;
}
public String getManufacturer() {
return manufacturer;
}
}
class Peripheral extends Product{
public Peripheral(float p) {
price = p;
}
public float price() {
return price;
}
}
class Printer extends Peripheral{
protected String model;
public Printer(String model, float p) {
super(p);
this.model = model;
}
public String getModel() {
return model;
}
}
class Cheese extends Product{
public Cheese(float p) {
price = p;
}
public float price() {
return price;
}
}
class Cheddar extends Cheese{
public Cheddar(float p) {
super(p);
}
}
class GenericOrder<T>{
public ArrayList<T> storage = new ArrayList<T>();
private static int counter = 1;
public final int id;
public T obj;
public GenericOrder(){
id = counter;
counter++;
}
public void add(T item){
storage.add(item);
}
public T get(int in){
return obj;
}
public void getId(){
System.out.println(this.id);
}
public String toString(){
String ret = "";
Iterator<T> it = storage.iterator();
while (it.hasNext()) {
ret += it.next() + "\n";
}
return ret;
}
}
class ComputerOrder extends GenericOrder {
public void add(ComputerPart in){
if(in instanceof ComputerPart){
storage.add(in);
}
}
}
public class Tme2{
public static void main(String[] args){
ComputerOrder com = new ComputerOrder();
com.add(new Motherboard("bla", 3.33f))
}
}
You can do it like this:
class ComputerOrder<T extends ComputerProduct> extends GenericOrder<T> {
//...
}
Here, ComputerProduct is a class that extends Product and all your computer products like ComputerPart or Peripheral extend ComputerProduct. Similarly, you could create a class FoodProduct derived from Product, from which Apple, Orange and Cheese are derived:
class FoodOrder<T extends FoodProduct> extends GenericOrder<T> {
//...
}
The declaration <T extends ComputerProduct> is a type restriction, which ensures that all types of T are derived from ComputerPart, otherwise you will get a compiler error.
The ComputerOrder class is still generic, so you could instance an order for all computer products:
ComputerOrder order = new ComputerOrder<ComputerProduct>();
// Add peripherals, printers, motherboards...
// Apples, ... will throw compiler errors...
But you could also restrict it to peripherals only:
ComputerOrder order = new ComputerOrder<Peripheral>();
// Add peripherals, printers,...
// Apples, motherboards (ComputerProduct, but NOT Peripheral) will fail...

generic (non-static) method with Class parameter for typesafety, how does it work?

this is my code, Control is an swt-ui-widget, the method find should return a component with the type passed in "clazz". I know how to do this with static methods, but it doesn't work if it's an instance method.
package org.uilib.swt.templating;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
public class Component<T extends Control> {
public final String name;
public final T control;
public Component(String name, T control) {
this.name = name;
this.control = control;
}
public String getName() {
return name;
}
public T getControl() {
return control;
}
public Component<E> find(String query, Class<E extends Control> clazz) {
return null;
}
}
i want to do the following:
Component<Button> x = this.find("asd", Button.class);
As far as I understand, you need the following generic method:
public <E extends Control> Component<E> find(String query, Class<E> clazz) { ... }
public <T extends Component> T find(String query, Class<T> clazz) {
return null;
}

Error when adding HashMap values to TreeSet

Here is some sample code...I always seem to get a ClassCastException...anybody point out what I am doing wrong?
package com.query;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Test;
import com.google.common.collect.Sets;
public class ClassCastExceptionTest {
#Test
public void test() {
A<SomeType> a1 = new A<SomeType>(1);
A<SomeType> a2 = new A<SomeType>(2);
A<SomeType> a3 = new A<SomeType>(3);
Map<String, A<SomeType>> map = new HashMap<String, A<SomeType>>();
map.put("A1", a1);
map.put("A2", a2);
map.put("A3", a3);
Collection<A<SomeType>> coll = map.values();
Set<A<SomeType>> set = Sets.newTreeSet(coll);
System.out.println("Done.");
//EXCEPTION...
//com.query.ClassCastExceptionTest$A cannot be cast to
//com.query.ClassCastExceptionTest$BaseType
}
private class A<T extends BaseType> extends Base<T> {
public A(int i) {
super(i);
}
}
private class Base<T extends BaseType> implements Comparable<T> {
private Integer id;
public Base(int id) {
this.id = id;
}
/**
* #return the id
*/
public Integer getId() {
return id;
}
/**
* #param id the id to set
*/
#SuppressWarnings("unused")
public void setId(int id) {
this.id = id;
}
#Override
public int compareTo(T o) {
return getId().compareTo(o.getId());
}
}
private class SomeType extends BaseType {
#Override
public Integer getId() {
return 0;
}
#Override
public int compareTo(BaseType o) {
return this.getId().compareTo(o.getId());
}
}
private abstract class BaseType implements Comparable<BaseType> {
public abstract Integer getId();
}
}
In order to be added to TreeSet (with natural ordering) a class should be comparable with itself:
private class Base<T extends BaseType> implements Comparable<Base> { ... }
whereas in your case Base is comparable with T:
private class Base<T extends BaseType> implements Comparable<T> { ... }
A TreeSet uses the objects compareTo method for sorting. So when adding the second A instance to the TreeSet, A#compareTo is invoked with the other A instance as argument, but as this method is expecting BaseType (or a subclass of BaseType) as argument, a ClassCastException is thrown.

Categories