I am given a class Shop that maintains a collection of items of type T. It provides buy and sell functions for single or multiple items and uses a List<T> as a container for buying and selling:
import java.util.*;
public class Shop<T> {
List<T> stock;
public Shop() { stock = new LinkedList<T>(); }
public T buy() {
return stock.remove(0);
}
void sell(T item) {
stock.add(item);
}
void buy(int n, List<T> items) {
for (T e : stock.subList(0, n)) {
items.add(e);
}
for (int i=0; i<n; ++i) stock.remove(0);
}
void sell(List<T> items) {
for (T e : items) {
stock.add(e);
}
}
}
Now, I need to modify this class so that I can buy/sell items with any Collection type...not just List. I figured I would start by commenting out most everything and trying to convert things one by one, beginning with the stock :
public class Shop<T> {
// List<T> stock;
Collection<T> stock;
// public Shop() { stock = new LinkedList<T>(); }
public Shop() { stock = new Collection<T>(); }
...
...
}
The first declaration works, but trying to instantiate the interface in the constructor, as expected, does not work. But as far as I can tell, stock needs to be a Collection so that I can use any Collection subtype in the other functions that deal with it. And I'm pretty sure I cannot use a wildcard as a type parameter in this case. So what exactly can I do to construct the stock here...or how should I declare the stock differently in the first place?
The actual collection implementation you use inside your class is completely immaterial to the clients/users of the class as long as your interface definition accepts Collection, i.e.
void buy(int n, List<T> items)
void sell(List<T> items)
should be
void buy(int n, Collection<T> items)
void sell(Collection<T> items)
This will not restrict anyone to use only List types. Then, your internal member stock can be and should be instantiated with any concrete subtype of Collection.
Related
first of all my code below just delivers an abstract view of my classes so that you can easily understand what my question is about :) -so also no equals, hashcode.
I have an ABC extended from Observable which has a List of AbstractObservers
Then I have some classes B and C inherit from AbstractObservers. AbstractObservers implements Observer.
The focus is now at the Recover class.
With the method recover() I try to return a List with the concrete type (B or C) instead of AbstractObservers.
I am not satisfies with my solution, I think it could be better, easier?
Have you any idea how I could solve that problem better? The Abstract classes must stay due to Hibernate.
Thank you in advance
public abstract class ABCObservable extends Observable {
List<AbstractObserver> abstractObserverList = new LinkedList<>();
public List<AbstractObserver> getAbstractObserverList() {
return abstractObserverList;
}
#Override
public synchronized void addObserver(Observer o) {
super.addObserver(o);
abstractObserverList.add((AbstractObserver) o);
}
}
AbstractObserver
public abstract class AbstractObserver implements Observer {
#Override
public void update(Observable o, Object arg) {
}
}
B
public class B extends AbstractObserver {
}
C
public class C extends AbstractObserver {
}
Recover
public class Recover {
public List<? extends AbstractObserver> recover(ABCObservable abcObservable) {
List<AbstractObserver> returnList = new LinkedList<>(); //does that delivers a List with AbstractObserver or B or C?
if (abcObservable.getAbstractObserverList().get(0) instanceof B) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
} else if (abcObservable.getAbstractObserverList().get(0) instanceof C) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
}
return returnList; // returns a List with B or C elements
}
}
In Java, you can't convert a list to a new type, what you can do, however, is create a new one and add the values to it. If you use a generic method, you should be able to accomplish this. I haven't test this code, but theoretically it should work:
public <T> List<T> recover(T abcObservable) {
List<AbstractObserver> list = abcObservable.getAbstractObserverList();
List<T> returnList = new LinkedList<>();
returnList = new LinkedList<>();
for(AbstractObserver a : list) {
if(a instanceof T) {
returnList.add(a);
}
}
return returnList;
}
Instead of using a defined class, this snippet uses T, you can find out more about how Java Generic Methods work on this Java Tutorial by Oracle.
EDIT: I think I'm confused about what you are asking for, this doesn't answer your question, if I understand it correctly.
I'm trying to modify the class below so its functions accept any from of collection the data type of those collection is also generic, allowing for maximally flexible:
public class Container<E> {
List<E> cont;
public Container() {
cont = new java.util.LinkedList<T>();
}
void add(E item) {
cont.add(item);
}
public E remove() {
return cont.remove(0);
}
void addMulti(List<E> items) {
for (E elem : items) {
cont.add(elem);
}
}
void removeMulti(int x, List<E> items) {
for (E elem : cont.subList(0, n)) {
items.add(elem);
}
for (int i=0; i<x; ++i) cont.remove(0);
}
}
I'm trying to make List accept multiple types using wildcard, like:
List<?> //Right??
In addition, the addAll, and removeAll function should accept any kind of lists as an argument, instead of List only, could t be like:
Collection<?> //Correct???
Thank you!
For addMulti, you do not want to accept a Collection<?>, because you cannot rightly say it contains elements compatible with E. For maximum generality, you might accept a Collection<? extends E>, which says that the collection contains E or some subclass of E.
void addMulti(Collection<? extends E> items) {...}
For removeMulti, yes, you could accept a Collection<?>, because if the type of some element in the collection is not compatible with E, it will simply not be removed.
void removeMulti(int x, Collection<?> items) {...}
Though, if you take a wildcard collection in removeMulti, you will not be able to add to items. (I don't really understand what your code is supposed to do there.)
This is the way Collection#addAll and Collection#removeAll are defined.
I have a class with generic type.
It is nice and easy to add any type of object I want on Mylist using addNode( ) since I am using generics. However, if I want to add in (int) 5 while I am in the class. How am I able to do that? (See comment in below codes for example).
class MyList <T>
{
Node <T> head = null;
public void addNode(T element) {
head = new Node <T> (element);
}
//Other methods removed for simplicity
public void myMethod () {
MyList <T> newList = new MyList <T>();
//Below code generate error: required: T, found: int
newList.addNode(5); //How to add an int 5 here when it is expecting Type:T?
}
}
class Node <T>
{
T element;
public Node(T item)
{
element = item;
}
//Other methods removed for simplicity
}
class MyList<T> {
// ...
public void addNode(T element) {
// ...
}
public void myMethod() {
MyList<T> newList = new MyList<T>();
newList.addNode(5); // <- can't do that!
}
}
If you could add an integer there, the class wouldn't be generic anymore. It would defeat the purpose.
In methods outside this class that use MyList, you could do this:
void another() {
MyList<Integer> list = new MyList<Integer>();
list.addNode(5);
MyList<String> list2 = new MyList<String>();
list.addNode("hello");
}
UPDATE
What if I need to add both Integer and Nodes object into the list? Is there any way we can do it?
You could do this, but then, what's the template parameter is becoming pointless, and you are losing proper type checking features. Normally you shouldn't do this.
MyList<Object> list3 = new MyList<Object>();
list3.addNode(12);
list3.addNode("heya");
My applications consists of Vehicle class and Customer class where I have an interface to add delete and search for each.
Because of this I implemented my interface for add as follows:
public void add(Object newObject, List<Object> myList);
and therefore this accepts all objects. However when I am trying to pass a Vehicle list from my application I am getting an error as it is expecting an Object List. How can I convert my List to List and still update the lists.
This is my initialized list of allVehicles.
List<Vehicle> allVehicles = new ArrayList<Vehicle>();
This is the method I am using to add new Vehicle where I am getting the error on allVehicles.
addNewCycle.add(addNewCycle, allVehicles);
The method from the Vehicle class implemented from interface.
public void add(Object newObject, List<Object> myList) {
myList.add((Vehicle)newObject);
}
My question is how can I cast this list to an Object list and update it on Vehicles List.
Consider using generics for your interface
public interface Adder<T> {
public void add(T newObject, List<T> myList);
}
Then you can do this
public class Vehicle implements Adder<Vehicle> {
#Override
public void add(Vehicle newObject, List<Vehicle> myList) {
myList.add(newObject);
}
}
Try this.
List<Vehicle> allVehicles = new ArrayList<Vehicle>();
// add some vehicles
List<Object> allVehicles1 = new ArrayList<Object>();
allVehicles1.addAll(allVehicles);
// now use allVehicles1
Converting the Vehicle into Object is really futile. A better option would be redesigning your interface to support generics for add method:
public <T> add (T data, List<T> list);
In this case, your class can easily support this:
interface Foo {
public <T> boolean add(T data, List<T> list);
}
class Bar implements Foo {
#Override
public <Bar> boolean add(Bar data, List<Bar> list) {
return list.add(data);
}
}
public class TestBar {
Bar bar = new Bar();
List<Bar> list = new ArrayList<>();
bar.add(bar, list);
//prints the elements in the list
//override toString method in Bar for a "nicer" result
System.out.println(list);
}
A better implementation would be:
class Adder implements Foo {
#Override
public <T> boolean add(T data, List<T> list) {
//totally generic
return list.add(data);
}
}
the Collection are by default Objects but since 1.5 Sun adds new mechanism to deal with objects called Generics. In other words
If you write
ArrayList arr =new ArrayList();
without the generics it will work. Objects and this words for < 1.4
If you have
List<Vehicle> allVehicles = new ArrayList<Vehicle>();
and you wanna transfer it to ArrayList of Objects
List noremalArray = new ArrayList(allVehicles);
I have a method that takes a generic parameter type. The scenario I have is this method will be called with different parameter types.
class something{
public void someMethod(){
List<A> listA = ....; //Class A have a field String Id;
List<B> listB = ....; //Class B haave a field String Id;
testMethod(listA);
testMethod(listB);
}
private <T> void testMethod( List<T> list ){
for( T event : list ){
//TODO (something like): event.getId();
}
}
}
In the above code all the parameters will be be a List<someObjectType>. All the object types have a common field and need to use the getter to fetch its value. Now since the method definition is generic, how do I achieve this?
Have A and B implement a common interface that has a method getID:
interface SomeInterface {
String getID();
}
then you could have:
private <T extends SomeInterface> void testMethod(List<T> list) {
for (T event : list) {
// now you can use `event.getID()` here
}
}
There is no point in creating such a generic method without bounded type. Since T isn't bounded to any type, you can't use specific interface on the objects inside the list. So if you want testMethod to get list of objects of any type, you should use List<?> instead.
This cannot be done. You can't handle two different lists with incompatible interfaces the same way in your method, unless you do something with instanceof, i.e.
public void testMethod(List<? extends Object> list) {
if(list.get(0) == null) return;
if(list.get(0) instanceof A) {
// Do the A stuff
} else {
// Do the B stuff
}
}
Define your method like this with T extending your common class/interface BaseType:
private <T extends BaseType> void testMethod( List<T> list ){
for( T event : list ){
//TODO (something like): event.getId();
}
}
Example:
public void someMethod() {
List<Integer> listA = Arrays.asList( new Integer[] {1, 4, 9} );
List<Double> listB = Arrays.asList( new Double[] {1.5, 4.2, 9.3} );;
testMethod(listA);
testMethod(listB);
}
private <T extends Number> void testMethod( List<T> list ){
for( T event : list ) {
// Note intValue() method is being called here which is provided
// in the base class Number that is being extended by T
System.out.println(event.intValue());
}
}
As other answers said, you need to bound the type parameter by some interface. But for what you're using it for, you don't actually need to have a T:
private void testMethod(List<? extends SomeInterface> list) {
for (SomeInterface event : list) {
// now you can use `event.getID()` here
}
}
I don't know if i really understand what you want.
But if you know, you will store for example Strings into your List and want to use the toUpperCase() method, how about just casting it?