Usage of generic classes - java

I'm trying to understand generics via Java but I have some questions that is on my mind.
For example, let's think about the priority queue ADT. We can represent this ADT by an interface, which we can call MyPriorityQueue. Now, if I am not wrong, every element that we will put in a priority queue must have two components, namely the "priority value" and the "value".
We can create a type called Entry to represent the entries that will be put in a priority queue. Since the priority values and values can be of any type, if I am not wrong the Entry class should be generic.
Now, back to the priority queue ADT, if I want to implement the MyPriorityQueue interface with a class named, say MyPQ, since every priority queue's elements must be Entries, should MyPQ be generic or not?
From this point of view, it looks like should not because it will support only one type of element, which is Entry but on the other hand, it looks like it should be generic. Because, say two types of MyPQ instances, first is a to do list named toDoList and second is an airport boarding queue named boardingQueue should not be allowed to have one instance's Entries in another, meaning that one should not be allowed to attempt to put an Entry of the boardingQueue to the toDoList and vice versa.
This suggests that MyPQ should be generic. Also should MyPriorityQueue interface be generic or not? If yes, why so?
I know this has been a kind of long text but I would very much appreciate it if you could explain this to me.

Yes, you HAVE TO make MyPQ generic; you will run into compiler issues if you don't. Remember that Entry is generic, so its declaration will look something like:
public class Entry<K, V> {}
Then, your MyPQ class will use your Entry class, forcing it to be generic, like this:
public class MyPQ<K, V> implements MyPriorityQueue<K, V> {
#Override
public void add(Entry<K, V> entry){}
}
If you don't declare MyPQ as generic, then what do you replace K and V with in add(Entry<K, V> entry)? So you get a compile error.
As far as the MyPriorityQueue interface goes, you will also have to make it generic, since in there you will probably have methods with generic arguments that implementations will have to override, like public void add(Entry<K, V> entry);.

If you look at PriorityQueue, you'll see a good implementation. It's generic, but requires Comparable (or a Comparator) objects in it. Priority comes directly from the comparison and there's no need for a special Entry object.
You could recreate this in a more academic way, but it would be worthless to have an Entry class when it's not needed (unlike Map.Entry).

Related

How to allow a generic class method to be executed only by certain types of parameters?

I am trying to add a method to an existing class BinaryTree<T> to simple add the values of all the elements in the tree. The problem is that being the class a generic one, not all the types that can be send at the time of creating a tree can be added. I mean, for example It wouldn't make any sense to try to add the values of a class people.
So my question is, how do I make a method public T addAllElements() that only allows T to be an specific kind of type, in this case, only the types that is possible to add it's value, like Integer, Float, Long, etc? I guess there have to be some kind of numerical interface or maybe some kind of declaration provided by the language to do something like that.
By the way, it seems to be a solution without having to create a child class, in case that it could help in anything, because I was asked to solve a similar problem and the instructions says that the method have to be in the same class.
Trying to be more clear, I'll ask another question , because I think that both of them have the same answer.
I found that the method sort() in java.util.Arrays class can be used by a class if the class implements the interface Comparable<T>. So if I hava a class, lets say
public class People {
implements Comparable<People>
private String name;
public int compareTo(People o) {
...
}
...
}
This class can be sorted with the sort() method from the Arrays class, but if the class dind't implement the Comparable<T> interface it couldn't. So what is making this restriction in the Arrays class definition? Is it what I need to solve the first problem I asked?
So my question is, how do I make a method publicTaddAllElements() that only allows T to be an specific kind of type, in this case, only the types that is possible to add it's value, like int, float, long, etc? I guess there have to be some kind of numerical interface or maybe some kind of declaration provided by the language to do something like that.
You're looking for Number.
So your declaration would look something like this, if the class is generic:
public BinaryTree<T extends Number> {
// ...
}
or if you want to make just the method generic:
public <T extends Number> T addAllElements() {
// ...
}
That said, for better or for worse Number does not define arithmetic operations in terms of methods. To my knowledge there is no such built-in type which does.
Do note that the types you listed are all primitives, which mean they're not compatible with generics at all. Subtypes of Number (and types that can be used with generics) will all be wrapper types: Integer, Float, Long, etc.
Your examples are related, but they're not the same.
To address the latter concern first, the reason that Arrays.sort with a specific signature requires that things be Comparable is because it needs to sort them based on that natural ordering. There is another signature that you could provide to the method which allows you to pass a custom Comparator to it, to sort on whatever other property of the class you liked.
To your main concern, you need to have an upper-bound generic, specifically one of type T extends Number. The reason for this is that Number is the parent class to all of the numeric wrapper classes, as well as BigDecimal and BigInteger.
There's two things you'd want to be sure of before you did this:
Your generic type was bound at the class level. Since we're dealing with a tree, it makes no sense to have non-homogeneous data throughout.
You did a math operation according to a specific data type (int, long, or double).
You would then declare your method(s) as such:
public int addAsInteger() {}
public double addAsDouble() {}
public long addAsLong() {}
You'd make use of Number's methods: intValue, longValue and doubleValue for your respective methods.
You wouldn't be able to simply return T since you can't guarantee what kind of Number you're getting back, or what T is specifically bound to (it can't be Number since it's an abstract class, so it is a non-inclusive upper bound).

Function clash when implementing multiple interfaces

I have a variant-style object foo that is capable of behaving as a java.util.Map and a java.util.List as well as other plain-old-data types. This object is written in C++ (modelled on the composite pattern) and I'm building a JNI so that I can use it in Java.
In Java, I'm motivated to write
public class foo implements
Streamable,
java.util.Map<String, foo>,
java.util.List<foo>
Then I encounter trouble. For example, I need to implement 3 flavors of remove:
public foo remove(int index)
public boolean remove(Object key)
public foo remove(Object key)
The first two are for java.util.list, the final one for java.util.map. This, of course, is a problem since you cannot have two functions with the same name and parameters but different return types.
Is there a way round this?
An adapter would work. Have one class implement Map and Stream, and another class implement List and Stream. All operations required by these adapter's respective interfaces would draw from a common underlying foo instance.
You could use a LinkedHashMap.
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries.
Please refer to this question as it discusses the same problem you're having.

Java Collections of Interfaces

I'm writing a small API to deal with objects that have specific 'traits' In this case, they all have an interval of time and a couple of other bits of data, So I write an interface TimeInterval with some getters and setters.
Now most of these API methods deal with a Set or List of Objects. Internally these methods use the Java Colletions Framework (HashMap/TreeMap in particular). So these API methods are like:
getSomeDataAboutIntervals(List<TimeInterval> intervalObjects);
Couple of Questions:
a) Should this be List<? extends TimeInterval> intervalObjects instead?
Is it mostly a matter of style? The one disadvantage of taking strictly an interface that I can see is, you need to create your list as a List<TimeInterval> rather than List<ObjectThatImplementsTimeInterval>.
This means potentially having to copy a List<Object..> to List<TimeInterval> to pass it to the API.
Are there other pros & cons to either approach?
b) And, one dumb question :) The collections framework guarantees I always get out the same instance I put in, the collections are really a collection of references, correct?
1) Yes.
Method parameters should be as general as possible. List<? extends A> is more general than List<A>, and can be used when you don't need to add things to the list.
If you were only adding to the list (and not reading from it), the most general signature would probably be List<? super A>
Conversely, method return types should be as specific as possible. You rarely to never want to return a wildcard generic from a method.
Sometimes this can lead to generic signatures:
<T extends MyObject> List<T> filterMyObjects(List<T>)
This signature is both as specific and as general as possible
2) Yes, except possibly in some rare very specific cases (I'm thinking of BitSet, although that isn't technically a Collection).
If you declare your list as List<? extends A>, then you can pass in any object which static type is List<X>, where X extends A if A is a class, or X implements A id A is an interface. But you'll not be able to pass in a List or a List<Object> to it (unless A is Object) without force-casting it.
However, if you declare the parameter as a List<A>, you'll only be able to pass lists which static type is strictly equivalent to List<A>, so not List<X> for instance. And by "you are not able to do otherwise", I really mean "unless you force the compiler to shut up and accept it", which I believe one should not do unless dealing with legacy code.
Collections are really collections of references. The abstraction actually is that everything you can put in a variable is a reference to something, unless that variable is of a primitive type.
1) I would recommend ? extends TimeInterval. Because of Java's polymorphism, it may not actually make a difference, but it is more robust and better style
2) Yes
a) No. List<? extends TimeInterval> will only accept interfaces that extend the interface TimeInterval. Your assertion that "you need to create your list as a List<TimeInterval> is wrong, unless I misunderstand your point. Here's an example:
List<List> mylist= new ArrayList<List>();
mylist.add(new ArrayList());
b) Yes.
Should this be List intervalObjects instead?
You only do that if you want to pass in a List<TimeIntervalSubclass>. Note you can put instances of subclasses of TimeInterval into a List<TimeInterval>. Keep in mind that the type of the list is different than the types in the list.
If you do List<? extends A> myList -- that only affects what you can assign to myList, which is different than what is in myList.
And, one dumb question :) The collections framework guarantees I
always get out the same instance I put in, the collections are really
a collection of references, correct?
When you create a collection Map myMap = new HashMap(), myMap is a reference to the underlying collection. Similarly, when you put something into a collection, you are putting the reference to the underlying object into the collection.

Generics - Legal alternative for (elements instanceof List<? extends Comparable>)

I have this method which unique parameter (List elements) sets elements to a ListModel, but I need to make a validation to see if the generic type implements comparable and since such thing like:
if (elements instanceof List<? extends Comparable>)
is illegal, I don't know how to do the proper validation.
Update
I already have done this validation using:
(elements.size() > 0 && elements.get(0) instanceof Comparable)
but I want to know if is there a cleaner solution for that, using for example reflection?
Thanks in advance.
The generic type of a list is erased at runtime. For this to work you need to either require the parameter in the method signature or test each element individually.
public void doSomething(List<? extends Comparable> elements) {}
OR
for (Object o : elements) {
if (o instanceof Comparable) {}
}
If you have control over the code, the former is preferred and cleaner; the later can be wrapped in a utility method call if needed.
That's not possible. instanceof is a runtime operator whereas generic information is lost at runtime (type-erasure).
I'm not a Generics guru, but to my understanding the reason you can't do that is that at runtime, there's no distinction between an ArrayList and, say, an ArrayList<String>. So it's too late to perform the test you want.
Why not just declare your method to accept a List<? extends Comparable> instead of a List?
In particular, the way you phrased your question makes it sound like you expect the list to always contain homogeneous elements, but a plain old List doesn't give you any sort of assurance like that.
To your update: simply making sure that one element implements Comparable is not enough (what if the other ones don't?) And making sure that all of the elements implement Comparable is also not enough to validate (what if they are of different classes that implement Comparable but cannot compare with each other?).
But the bigger question is, why bother validating at runtime anyway? What benefit does that give compared to simply trying to use it and then seeing that it fails (i.e. throws an Exception, which maybe you can catch)?

Java, declare variable with multiple interfaces?

In Java, is it possible to declare a field/variable whose type is multiple interfaces? For example, I need to declare a Map that is also Serializable. I want to make sure the variable references a serializable map. The Map interface does not extend Serializable, but most of Map's implementations are Serializable.
I'm pretty sure the answer is no.
Follow up: I'm fully aware of creating a new interface that extends both Map and Serializable. This will not work as existing implementations (such as HashMap) do not implement my new interface.
You can do it with generics, but it's not pretty:
class MyClass<T,K,V extends Serializable & Map<K,V>> {
T myVar;
}
There is no need to declare the field/variable like that. Especially since it can only be tested runtime and not compile time. Create a setter and report an error should the passed Map not implement Serializable.
The answers recommending that you create your own interface are of course not very practical as they will actively prohibit sending in things that are Maps and Serializable but not your special interface.
It's possible to do this using some generics tricks:
public <T extends Map<?,?> & Serializable> void setMap(T map)
The above code uses generics to force you to pass a map which implements both interfaces. However, note that a consequence of this is that when you actually pass it the maps, they will probably need to be either marked as serializable or of a map type which is already serializable. It also is quite a bit more difficult to read. I would document that the map must be serializable and perform the test for it.
public interface MyMap extends Map, Serializable {
}
will define a new interface that is the union of Map and Serializable.
You obviously have to then provide a suitable implementation of this (e.g. MyMapImpl) and you can then provide variable references of the type MyMap (or Map, or Serializable, depending on the requirements).
To address your clarification, you can't retrofit behaviour (e.g. a serializable map). You have to have the interface and some appropriate implementation.
I voted up Brian's answer, but wanted to add a little higher-level thought..
If you look through the SDK, you'll find that they rarely (if ever) pass around actual collection objects.
The reason for that is that it's not a very good idea. Collections are extremely unprotected.
Most of the time you want to make a copy before passing it off and pass the copy so that any modifications to the collection won't change the environment for something else that's relying on it. Also, threading becomes a nightmare--even with a synchronized collection!
I've seen two solutions, one is to always extract an array and pass it. This is how the SDK does it.
The other is to ALWAYS wrap collections in a parent class (And I mean encapsulate, not extend). I've gotten into this habit and it's very worth while. It doesn't really cost anything because you don't duplicate all the collection methods anyway (actually you rarely duplicate any of them). In fact what you end up doing is moving "Utility" functionality from other classes distributed all over your code into the wrapper class, which is where it should have been in the first place.
Any method with a signature that matches "method(collection,...)" should almost certainly be a member method of that collection, as should any loops that iterate over the collection.
I just have to throw this out every now and then because it's one of those things I didn't get for a while (because nobody championed the concept). It always seems like it's going to have some drawback but having done this for a while and seeing the problems it solved and code it eliminated, I can't even imagine any possible drawbacks myself, it's just all good.
You can achieve this by making your own Interface, which extends the interfaces you want
public interface SerializableMap<K, V> extends Map<K, V>, Serializable {
}
In my case it worked just to declare the concrete type:
HashMap<String, String> mySerializableMap = new HashMap<>();
It allowed me to use the Map methods (like put) and pass the map to methods that required a Serializable, without casting. Not perfect when we’ve learned to program towards interfaces, but good enough for me in the situation I was in.
If you really insist: As has been noted, declaring a combined interface alone does not solve the problem since the concrete classes we already have do not implement our combined interface even when they do implement each of the two interfaces we combine. I use it as a first step on the way, though. For example:
public interface SerializableMap<K, V> extends Map<K, V>, Serializable {
// No new methods or anything
}
The next step is also declaring a new class:
public class SerilizableHashMap<K, V> extends HashMap<K, V> implements SerializableMap<K, V> {
private static final long serialVersionUID = 4302237185522279700L;
}
This class is declared to implement the combined interface and thus can be used wherever one of those types is required. It extends a class that already implements each of the interfaces separately, therefore there’s nothing more we need to do. And now we have got what you asked for. Example of use:
public static void main(String[] args) {
SerializableMap<String, String> myMap = new SerilizableHashMap<>();
// myMap works as a Map
myMap.put("colour1", "red");
myMap.put("colour2", "green");
// myMap works as a Serializable too
consumeSerializable(myMap);
}
public static void consumeSerializable(Serializable s) {
// So something with the Serializable
}
For most purposes I suggest that this is overkill, but now I have at least presented it as an option.
Link: What does it mean to “program to an interface”?
You can't really do it if you want to keep using the existing Map implementations.
An alternative would be to make a helper class, and add a method like this one:
public static Serializable serializableFromMap(Map<?, ?> map) {
if (map instanceof Serializable) {
return (Serializable)map;
}
throw new IllegalArgumentException("map wasn't serializable");
}
Nope, you'll pretty much need to cast.

Categories

Resources