I have an error occuring with a program for an assignment. In it, I have to create an own generic
public class LinkedList<E extends Comparable<T>> implements List<E> {
the implemented Interface is:
public interface List<E extends Comparable<T>> { }
Now, whenever I try to create a new object of the type LinkedList as follows:
LinkedList<Termin> k = new LinkedList<Termin>();
eclipse gives me the following error:
Bound mismatch: The type Termin is not a valid substitute for the bounded parameter > of the type
LinkedList
the class declaration of the class Termin is as follows:
public class Termin implements Comparable<T> { }
in case you need the constructor and variables of the LinkedList object:
private E item;
private LinkedList<E> next;
//Constructor
public LinkedList() {
item = null;
next = null;
}
With a little google magic, I also found out that there once was a bug involving generics in eclipse that gave the same error for no reason.
I suppose some of my declarations aren't entirely correct.
The way the code is written, it cannot compile for a number of reasons, including the lack of specification of the T type, which is not explicitly declared.
One solution is to remove T and replace it with a known Java type (e.g., Object).
A more generic solution is to include T, which means two generic types have to be used.
For the latter case, the code could be something like:
// LinkedList class
public class LinkedList<T, E extends Comparable<T>> implements List<T, E> {
private E item;
private LinkedList<T, E> next;
// Constructor
public LinkedList() {
item = null;
next = null;
}
public static void main(String[] args) {
// Example statement, where T = Long.class and E = String.class
LinkedList<Long, Termin<String>> k = new LinkedList<Long, Termin<String>>();
}
}
and
// List interface
public interface List<T, E extends Comparable<T>> { }
and
// Termin class
public class Termin<T> implements Comparable<T> {
#Override
public int compareTo(T o) {
return 0; // Actual comparison needs to be implemented
}
}
Related
I have kind of problem with generics inheritance. Below is the dependency tree:
public class Attributes {
}
public abstract class Feature<T extends Attributes> {
private T attributes;
public T getAttributes() {
return attributes;
}
public void setAttributes(T attributes) {
this.attributes = attributes;
}
}
public abstract class AbstractFeatureRepository<T extends Feature<? extends Attributes>> {
public abstract String getType();
public abstract boolean create(T feature);
}
And I have implementations of these feature repositories, like this:
public class NodeAttributes extends Attributes {
private String startPoint;
public String getStartPoint() {
return startPoint;
}
public void setStartPoint(String startPoint) {
this.startPoint = startPoint;
}
}
public class Node extends Feature<NodeAttributes> {
}
public class NodeRepository extends AbstractFeatureRepository<Node> {
public String getType() {
return "Node";
}
public boolean create(Node node) {
return true;
}
}
public class LinkAttributes extends Attributes {
private String uri;
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}
public class Link extends Feature<LinkAttributes> {
}
public class LinkRepository extends AbstractFeatureRepository<Link> {
public String getType() {
return "Link";
}
public boolean create(Link link) {
return true;
}
}
I'm injecting these repositories with Spring to Controller via constructor (but in this example I'm manually creating in constructor for the sake of simplicity):
public class Controller {
private final Map<String, AbstractFeatureRepository<? extends Feature>> featureRepositories;
public Controller() {
this.featureRepositories = Arrays.asList(new NodeRepository(), new LinkRepository()).stream()
.collect(Collectors.toMap(AbstractFeatureRepository::getType, Function.identity()));
}
public Node createNode() {
Node newNode = new Node();
newNode.getAttributes().setStartPoint("Berlin");
createFeature("Node", newNode);
return newNode;
}
public Link createLink() {
Link newLink = new Link();
newLink.getAttributes().setUri("/home/local");
createFeature("Link", newLink);
return newLink;
}
private void createFeature(String type, Feature<? extends Attributes> feature) {
featureRepositories.get(type).create(feature);
}
}
All is good untill I want to call "create" method in generic "createFeature" where I'm getting compilation error that
The method create(capture#5-of ? extends Feature) in the type AbstractFeatureRepository<capture#5-of ? extends Feature> is not applicable for the arguments (Feature<capture#6-of ? extends Attributes>)
What I'm doing wrong? Is this because potentially I can pass some other kind of "Feature" than particular "Repository" can work with? How then should I change my map Repositories in Controller so compiler doesn't complain? I though I should operate exact classes as a key for map but have no idea how to make all of this working. Any suggestions?
Thank you.
Update 1. I changed Map to
private final Map<Class<?>, AbstractFeatureRepository<? extends Feature>> featureRepositories;
Changed AbstractFeatureRepository so it now looks this way:
public abstract class AbstractFeatureRepository<T extends Feature> {
public abstract Class<T> getClazz();
public abstract boolean create(T feature);
}
And changed the methods in controller:
public Link createLink() {
Link newLink = new Link();
createFeature(Link.class, newLink);
return newLink;
}
private <T extends Feature> void createFeature(Class<T> class1, T feature) {
AbstractFeatureRepository<? extends Feature> abstractFeatureRepository = featureRepositories.get(feature.getClass());
abstractFeatureRepository.create(abstractFeatureRepository.getClazz().cast(feature));
}
It still doesn't allow me to do that.
This code:
featureRepositories.get(type)
returns an object whose type is the V in Map<K, V>, as per the docs of java.util.Map. In your code, that means that expression is of type AbstractFeatureRepository<? extends Feature<? extends Attributes>>.
Let's simplify matters a tad, and assume we have List<? extends Number> instead.
This is valid java code:
List<? extends Number> list = new ArrayList<Integer>();
that's sort of the point of ? extends, really. This does not compile:
List<Number> list = new ArrayList<Integer>();
Now, imagine you called, on your List<? extends Number>:
List<? extends Number> list = new ArrayList<Integer>();
Number n = Double.valueOf(5.0);
list.add(n);
uhoh. There is a non-integer in my list of integers. Whoops.
That's why you can't call add() here, at all. You cannot call add on a List<? extends whatever>, at all. Any method that takes as argument a T where your type is Foo<? extends T> cannot be invoked*.
Let's go back to your code now:
You have a AbstractFeatureRepository<? extends Feature<? extends Attributes>> - therefore any method that AbstractFeatureRepository has that takes a T cannot be invoked from this. at all. And create is such a method.
The solution is a bit tricky. You can use a type-safe container, if you somehow have a reference to a class representing T (careful; things can be a T that cannot be a Class: List<Integer> is a T, but only List.class exists, you can't write List<Integer>.class! - You can use that:
public <T extends Attribute> void createFeature(Class<T> typeDesired, Feature<T> feature) {
featureRepositories.get(type).create(typeDesired.cast(feature));
}
is one way.
In general your method signature is problematic: There is just no guarantee that your stringly-typed String type implies that the kind of feature desired Feature<? extends Attribute> is handled by the repository matching that type.
A second option is to have each AbstractFeatureRepository responsible to deal with type mismatches. In that case, you can update the interface to read create(Object feature) throws TypeMismatchException instead. Or, have it return a type (public Class<T> getType()) and you can go back to the cast construct.
*) Well, you can invoke it, if you pass literally null, as null is all data types. But that clearly isn't what you intend to do here, thus, not relevant.
If you've only got 2 things in a Map (or N things, where N is a small number, you mention 4 in a comment), and you use fixed keys to indicate a particular type, using a Map is making it harder than necessary.
Maps are necessarily homogeneously typed, that is, all the keys have a common supertype, and all the values have a common supertype. The issue that you're facing is that you want a key's type to relate to the value's type: this can be done with a type-safe heterogeneous container (essentially: a map which you construct such that you can impose the constraints on the relationships between the types). But even this is overly-complex for the problem described.
Use two (N) fields instead:
public class Controller {
private final NodeRepository nodeRepository = new NodeRepository();
private final LinkRepository linkRepository = new LinkRepository();
This is still sort-of a map: the key is the field, the value is the field value.
But the advantage of this is that you've retained the concrete types of the repositories, so you can pass these to the method:
private <A extends Attributes> void createFeature(AbstractFeatureRepository<A> repo, Feature<A> feature) {
repo.create(feature);
}
e.g.
public Node createNode() {
Node newNode = new Node();
newNode.getAttributes().setStartPoint("Berlin");
// Or, easier, nodeRepository.create(newNode);
createFeature(nodeRepository, newNode);
return newNode;
}
public Link createLink() {
Link newLink = new Link();
newLink.getAttributes().setUri("/home/local");
// Or, easier, linkRepository.create(newNode);
createFeature(linkRepository, newLink);
return newLink;
}
To arrive at a working solution that is as close to your original code as I could get it, I made three or four relatively minor refactors.
The most significant change though was in Controller.createFeature()…
private <T extends Feature<?>> void createFeature(Class<T> class1, T feature) {
AbstractFeatureRepository<T> abstractFeatureRepository = (AbstractFeatureRepository<T>)featureRepositories.get(feature.getClass());
abstractFeatureRepository.create(feature);
}
The cast there is the simplest, most type safe solution in my opinion. The reason I'm convinced the cast is type safe is because of the compilation error you'd get if the cast weren't there:
Controller.java:31: error: incompatible types: AbstractFeatureRepository<CAP#1> cannot be converted to AbstractFeatureRepository<T>
AbstractFeatureRepository<T> abstractFeatureRepository = featureRepositories.get(feature.getClass());
where T is a type-variable:
T extends Feature<?> declared in method <T>createFeature(Class<T>,T)
where CAP#1 is a fresh type-variable:
CAP#1 extends Feature<?> from capture of ? extends Feature<?>
1 error
If you read the bottom part of the error message carefully, you'll see that the only difference between T extends Feature<?> and CAP#1 extends Feature<?> is the names of the two type variables. They both have the same upper bounds (extends Feature<?>). That tells me it's reasonable to infer that a cast would be type safe.
So, I annotated that method with SuppressWarnings("unchecked").
To confirm that the solution is usable, I fleshed out Node and Link classes with toString(). Calling Controller.createNode() and Controller.createLink() in the solution demo gets you…
Node: [NodeAttributes - Start Point: 'Berlin']
Link: [LinkAttributes - URI: 'urn::foo::bar']
I have to admit that what problem you're trying to solve isn't crystal clear to me. So I've made some assumptions based on only my general Java knowledge. Please let me know if the solution meets your requirements?
Here is the approach I used:
public class Controller {
private final Map<Class<?>, AbstractFeatureRepository<? extends Feature>> featureRepositories;
public Controller3(List<AbstractFeatureRepository<? extends Feature>> featureRepositories) {
this.featureRepositories = featureRepositories.stream()
.collect(Collectors.toMap(AbstractFeatureRepository::getClazz, Function.identity()));
}
public Node createNode() {
Node newNode = new Node();
createFeature(Node.class, newNode);
return newNode;
}
public Link createLink() {
Link newLink = new Link();
createFeature(Link.class, newLink);
return newLink;
}
private <T extends Feature> void createFeature(Class<T> clazz, T feature) {
AbstractFeatureRepository<T> repository = getRepository(clazz);
repository.create(feature);
}
#SuppressWarnings("unchecked")
private <T extends Feature, V extends AbstractFeatureRepository<T>> V getRepository(Class<T> clazz) {
return (V) featureRepositories.get(clazz);
}
public static void main(String[] args) {
Controller3 controller = new Controller3();
controller.createLink();
}
}
It doesn't satisfy completely no-cast approach(especially no #SuppressWarnings) but it is the least evil for me, since cast is done only in one method in controller, all the rest methods work no cast and no #SuppressWarnings.
Try
private static <T extends AbstractFeatureRepository> void createFeature(Class<T> clazz, Feature<? extends Attributes> feature) {
((T) featureRepositories.get(clazz)).create(feature);
}
You should modify the featureRepositories accordingly
private static final Map<Class<?>, AbstractFeatureRepository<? extends Feature>> featureRepositories
But I don't recommend using generics like this.
public class arr<T>
{
class comp <T extends Comparable<T>> implements Comparator<T>
{
public int compare(T lObj,T rObj)
{
return lObj.compareTo(rObj);
}
}
ArrayList<T> list;
Comparator<T> comparator;
public arr()
{
list = new ArrayList<T>();
comparator = new comp();
}
public void add(T data)
{
list.add(data);
}
public int getLength()
{
return list.size();
}
public T get(int index)
{
return list.get(index);
}
public void sort()
{
list.sort(comparator);
}
}
Hello, I am trying to make the sort function work but have a problem.
In the arr constructor, if I write
comparator = new comp<T>();
it gives me an error saying
"type argument T#1 is not within bounds of type-variable T#2 comparator =
new comp<T>(); ^
where T#1,T#2 are type-variables:
T#1 extends Object declared in class arr
T#2 extends Comparable<T#2> declared in class arr.comp"
And if I take out the type and write like this
comparator = new comp;
then it does work but gives me a warning that says
warning: [rawtypes] found raw type: arr.comp
comparator = new comp();
I can see what it means by raw types. I am not specifying the type, but somehow it works and if I try to fix the warning by specifying the type then, it throws an error. Could you please help me figure it out? I know... I am a noob my code must be a pain in your eyes. I am playing with generic comparators and trying many things to get familiar. Thank you.
Your code is confusing you, because the T defined by comp is hiding the T defined by arr. For the explanation below, I'll call them Tcomp and Tarr.
Tcomp is required to extend Comparable, but Tarr isn't required to do so, which means that Tarr cannot be "mapped" to Tcomp.
To fix, change Tarr so it is also required to extend Comparable:
public class arr<T extends Comparable<T>>
On a side note:
You comp class is an inner class, but it doesn't use anything from the outer class, so it should be a static nested class:
static class comp<T extends Comparable<T>> implements Comparator<T>
Alternatively, leave comp as an inner class, and let it reuse the T from the outer class:
class arr<T extends Comparable<T>>
{
class comp implements Comparator<T>
But, since Java (8 or higher) comes with an implementation of Comparator for comparing Comparable objects, you should use it:
public class arr<T extends Comparable<T>>
{
ArrayList<T> list;
Comparator<T> comparator;
public arr()
{
list = new ArrayList<T>();
comparator = Comparator.naturalOrder();
}
// rest of code
}
I have an interface Node that asks for the method:
public HashSet getNeighbour();
NodeVariable implements Node, and its neighbours are of type NodeFunction (that implements Node, too), and I wrote the method:
public HashSet<NodeFunction> getNeighbour();
(and viceversa in NodeFunction class).
I found out that if I change the signature of method in Node to:
public HashSet<Node> getNeighbour();
then on the methods in NodeVariable and NodeFunction I get the error:
Error getNeighbour() in factorgraph.NodeFunction cannot implement getNeighbour() in factorgraph.Node return type java.util.HashSet is not compatible with java.util.HashSet NodeFunction.java
This is not really clear.
I found:
Overriding return type in extended interface - Bad idea?
and
Java - Overriding return type of extended interface when return type uses generics for own method parameter types
and now I changed the Node method signature in:
public HashSet<? extends Node> getNeighbour();
thus the compiler stops complaining.
Is it right? Why HashSet is not considered like an "extension" of HashSet?
First, it's a better idea to define the methods in your interfaces in terms of other interfaces and not concrete implementations. What I want to say is that the getNeighbour() method should be:
public Set getNeighbour();
And since we know that it can only return Nodes (or subtypes of Node), we might as well define it like this:
public Set<? extends Node> getNeighbour();
HashSet<Node> and HashSet<NodeFunction> aren't compatible, even though NodeFunction implements/subclasses Node. Similarly, neither are List<Number> and List<Integer>. Integer subclasses Number.
static List<Number> getNumberList(int size) {
//ArrayList<Integer> numList = null; //Doesn't compile
ArrayList<Number> numList = null; //Compiles
return numList;
}
If the compiler allowed what your trying to do, then I could do the following and a ClassCastException would be thrown, which is the exact reason generics was created.
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main( String[] args ) {
Node nd = getInstance();
Set<Node> ndSet = nd.getNeighbour();
ndSet.add( new NodeSign() );
nd.removeSingleNeighbor(); //throws ClassCastException
}
static Node getInstance() {
return new NodeVariable();
}
}
interface Node {
public Set<Node> getNeighbour();
public void removeSingleNeighbor();
}
class NodeVariable implements Node {
Set<NodeFunction> ndFuncList = new HashSet<NodeFunction>();
public Set<NodeFunction> getNeighbour(){ return ndFuncList; } //wont' compile
//HERE!!!!
public void removeSingleNeighbor() {
NodeFunction ndFunc = (NodeFunction)ndFuncList.toArray()[ndFuncList.size()-1]; //throws ClassCastException
}
}
class NodeFunction implements Node {
public Set<NodeFunction> getNeighbour(){ return null; } //won't compile
public void removeSingleNeighbor() {}
}
class NodeSign implements Node {
public Set<NodeFunction> getNeighbour(){ return null; } //won't compile
public void removeSingleNeighbor() {}
}
Everything is semantically/syntactically valid except public Set<NodeFunction> getNeighbour(){}. The Java tutorials cover this issue.
I want to have a generic class that implements Iterable (let's call it ImplIterable) of type T that implements an Iterable interface over some class (that isn't of the generic class type); for example:
public class ImplIterable <T> implements Iterable<A> {
private A[] tab;
public Iterator<A> iterator() {
return new ImplIterator();
}
// doesn't work - but compiles correctly.
private class ImplIterator implements Iterator<A> {
public boolean hasNext() { return true; }
public A next() { return null; }
public void remove() {}
}
}
Where A is some class. Now, this code won't compile:
ImplIterable iable = new ImplIterable();
for (A a : iable) {
a.aStuff();
}
But this will:
Iterable<A> = new ImplIterable();
for (A a : iable) {
a.aStuff();
}
I don't understand why the latter doesn't compile and why can't I iterate over ImplIterable if it properly implements iterable. Am I doing something wrong/is there some workaround for this type of problems?
When you use a generic class without a generic parameter, all generics in that class are disabled.
Since ImplIterable is generic, and you're using it as a non-generic class, the generic parameters inside of it vanish, and it becomes an Iterable (non-generic) of Objects.
My code cannot convert from E to E. I can do a cast to type E but it seems redundant at this stage. My array is already declared as E-type.
import java.util.Iterator;
public class DataTypeDemo<E>
{
private E[] data = (E[]) new Object [10];
public MyIterator newIterator()
{
return new MyIterator();
}
private class MyIterator<E> implements Iterator<E>
{
private int location;
public boolean hasNext()
{
return location < data.length;
}
public E next()
{
return (data[location++]); // error here
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
}
Compiler, throws this error:
DataTypeDemo.java:23: incompatible types
found : E
required: E
Your inner type introduces it's own type variable:
private class MyIterator<E /* this is the problem*/> implements Iterator<E>
And thereby overwrites the outer class type variable
Change your type declaration to this:
private class MyIterator implements Iterator<E>
Reference:
Generics FAQ (although this problem is not mentioned literally, it is implied by this FAQ entry)
The root of your problem is that an inner class of yours.
For the compiler, there are no guarantees that the two E's are of the same type.
import java.util.Iterator;
import java.util.ArrayList;
public class DataTypeDemo<E>
{
private ArrayList<E> data = new ArrayList<E>(10);
private class MyIterator implements Iterator<E>
{
private int location;
public boolean hasNext()
{
return location < data.size();
}
public E next()
{
return data.get(location++);
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
}
Though once you are aware of the problem, feel free to implement your own solution ;)
Happy hacking.
That's because you've given the inner class MyIterator its own type parameter E. Note that that E is a different type parameter than the E of the enclosing class (you've named them both E, but they are two different type parameters).
Just leave off the type parameter for the inner class:
private class MyIterator implements Iterator<E> {
I think that the problem is that your nested iterator type is defined as a generic class also parameterized over an unrelated type named E. To fix this, change
private class MyIterator<E> implements Iterator<E>
To
private class MyIterator implements Iterator<E>
This first declaration says that the iterator for your type can be parameterized over any type, not just the type of the outer container. It also introduces a new type variable called E that is separate from the E in the outer declaration. This second definition says that the for any container type, there is one iterator type that isn't generic with respect to the outer type. This is probably what you intended.