//project.java
import MULTISET;
public class Bag<E extends Keyed> implements Iterable<E> {
//cannot find symbol. symbol: class Iterator. location: class project.Bag<E>
public Iterator<E> iterator() {
return new ArrIterator(this);
}
//same error as above
public class ArrIterator implements Iterator<E> {
Bag<E> arr;
int coun;
public ArrIterator(Bag<E> arr) {
this.arr = arr;
this.coun = 0;
}
public boolean hasNext() {
return this.coun < arr.cardinality();
}
public E next() {
if (!hasNext()) {
throw new NoItemException();
}
return arr.getArray()[coun+1];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
//MULTISET.java
//cannot find symbol. symbol: class Iterator. location: interface MultiSet<E>
public interface MultiSet<E extends Keyed> extends Iterable<E> {
public Iterator<E> iterator();
}
I'm trying to do foreach loops on type Bag, and I get the two commented errors. I'm not too familiar with ADT, generics, or iterators, but I thought I did the correct thing.
What is missing and/or wrong here? This isn't my complete code, but everything else I've left out works. There's a problem somewhere in the above code snippet. An example I was following is more or less 1:1 with my own code, but mine doesn't seem to work.
The problem is that your inner class ArrIterator is re-defining another generic type parameter <E> when it's still in scope from your outer class, Bag. This causes the new E not to match the old E.
According to Section 6.3 of the JLS:
The scope of a class's type parameter (ยง8.1.2) is the type parameter section of the class declaration, the type parameter section of any superclass or superinterface of the class declaration, and the class body.
Remove the re-declaration of E in your inner class ArrIterator and let its extends clause use the E already in scope.
public class ArrIterator implements Iterator<E> {
Then your iterator() method doesn't have to return a generic ArrIterator.
public Iterator<E> iterator() {
return new ArrIterator(this);
}
Also, your hasNext method in your iterator should return boolean to match the Iterator interface.
Related
I am attempting to make a class that sub-classes Iterable. This is similar to this question. However, I need to have the objects in the list be sub-classes of a specific class, e.g. QObject in my example below. In addition, I need my iterator to implement specific methods related to the ListIterator interface.
The problem is that my inner class that implements the ListIterator interface does not "return" the base generic type QObject in my implementation. There is something wrong with how I am doing the QueueListIterator generics.
Now, if I declare the Queue in my example code with Queue <QObject> it works. This must be providing the information needed to allow the iterator to get the type correct. However, just declaring it as Queue does not, even though the base generic type is QObject AND my other methods in the Queue class use the base generic type.
So, my question is why does this happen and is there a way to specify QueueListIterator to discern the base generic type?
public class Queue<T extends QObject> implements Iterable<T> {
/**
* The list of items in the queue.
*/
protected List<T> myList;
// other methods and defs
public final Iterator<T> iterator() {
return (new QueueListIterator());
}
public final ListIterator<T> listIterator() {
return (new QueueListIterator());
}
private class QueueListIterator implements ListIterator<T> {
protected ListIterator<T> myIterator;
protected QueueListIterator() {
myIterator = myList.listIterator();
}
#Override
public void add(T o) {
throw new UnsupportedOperationException("The method add() is not supported for Queue iteration");
}
#Override
public boolean hasNext() {
return myIterator.hasNext();
}
#Override
public boolean hasPrevious() {
return myIterator.hasPrevious();
}
#Override
public T next() {
return myIterator.next();
}
#Override
public int nextIndex() {
return myIterator.nextIndex();
}
#Override
public T previous() {
return myIterator.previous();
}
#Override
public int previousIndex() {
return myIterator.previousIndex();
}
#Override
public void remove() {
throw new UnsupportedOperationException("The method remove() is not supported for Queue iteration");
}
#Override
public void set(T o) {
throw new UnsupportedOperationException("The method set() is not supported for Queue iteration");
}
}
}
// testing code
public static void test(){
Queue q = new Queue();
// put some stuff in the Queue
QObject r1 = new QObject(q.getTime(), "A");
q.enqueue(r1);
QObject r2 = new QObject(q.getTime(), "B");
q.enqueue(r2);
// Does not work!
// incompatible object types, Object cannot be converted to QObject in the for( : ) construct
for (QObject qo : q) {
System.out.println(qo);
}
}
What if you declare q this way:
Queue < QObject > q
Using the raw type Queue is the same as using the erasure of Queue. The reason that T removeFirst() allows you to retrieve a QObject but Iterator.next() does not is that T removeFirst() and Iterator<T> iterator() erase differently. The erasure of a type variable is the erasure of its left-most bound, so T erases to QObject, but the erasure of a parameterized type is that type without any type arguments, so Iterator<T> erases to Iterator. (source)
There is no way to get that working with the raw type, and you should use Queue<QObject> instead. In some cases you may also be able to use Queue<?> as a reference type. (See PECS.)
Also see What is a raw type and why shouldn't we use it?
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
}
}
I have the follow code
public class SBag<Item> implements BagInterface<Item>, Iterable<Item> {
And when I try to compile I get
SBag.java:12: error: SBag is not abstract and does not override abstract method
iterator() in Iterable
public class SBag<Item> implements BagInterface<Item>, Iterable<Item>{
^
where Item is a type-variable:
Item extends Object declared in class SBag
My task is to implement Iterable without using an inner-iterator class, but I am unsure of how to do this because I get that error when compiling. I have the followin methods add(), isFull(), toArray(), isEmpty(), getCurrentSize(), remove(), clear(), and toString(). The overall goal is to be able to use a for-each loop, but I am unsure of how to proceed from here.
An Iterator as an inner class would look like this:
class MyIterable implements Iterable {
public Iterator iterator() {
return new Iterator() {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
}
}
In contrast, an Iterator that's not an inner class might look more like:
class MyIterable implements Iterable {
public Iterator iterator() {
return new MyIterator();
}
}
class MyIterator {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
This is another way that's technically speaking not an inner class, but some people will look at you funny if you say that:
class MyIterable implements Iterable {
public Iterator iterator() {
return new MyIterator();
}
static class MyIterator {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
}
When you implement Iterable, you can then use for:each loop syntax:
Implementing this interface allows an object to be the target of the
"foreach" statement.
Iterable is a generic interface, you should implement the method it contains:
public class MyIterable<E> implements Iterable<E>{
public Iterator<E> iterator() { // <--- Implement me!
return new CustomIterator<E>();
}
}
And then, for example, you can do something like this:
public class CustomIterator<T> implements Iterator<T> {
public boolean hasNext() {
//...
}
public T next() {
//...
}
public void remove() {
//...
}
}
While [this answer] provides the regular syntax for Iterable implementations, an Iterator can be useful without an Iterable-implementing class. For example:
public class DoesntIterate{
public void coolMethod(){
//Do stuff
Iterator iter = getMyIterator();
while(iter.hasNext()){
//Do stuff with iter.next()
}
}
private Iterator getMyIterator(){
return new MyIterator();
}
private class MyIterator implements Iterator{
...
}
}
With this sort of paradigm, it's conceivable that you might use different iterators for different purposes all within the same class.
From an OOP perspective, you should never be making a class implement Iterable when it doesn't make sense for that to be an class on which you would iterate (i.e. if the class is not a data/storage structure).
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.