I have a class implementing List interface and storing data in an array of Objects. Now I need to write Iterator method for my class. How to get started ? I thought about writing a subclass implementing Iterator interface. Object of the class will have parameters of current index and last index. At each call to next/hasNext those parameters will be modified. Is this approach correct ? But then there is a problem with remove() method, since it should allow to delete object of class calling my iterator. How to solve this ? Also what should happen in iterator() method of my main class ?
My pseudocode:
class MyCollection<T> implements List<T>{
T[] tab;
MyCollection(int len) {
tab = (T[])new Object[len];
}
public Iterator iterator(){
}
}
class MyIterator<T> implements Iterator {
private int current;
private int last;
public void remove(){
}
public T next(){
}
public boolean hasNext(){
}
}
I have a class implementing List interface and storing data in an array of Objects.
It looks like you are reimplementing ArrayList. Is there a good reason for doing this?
Object of the class will have parameters of current index and last index. At each call to next/hasNext those parameters will be modified. Is this approach correct ?
You should only need one index, I think. But the basic idea is correct.
But then there is a problem with remove() method, since it should allow to delete object of class calling my iterator. How to solve this ?
There are two approaches:
Remove the element from the array and somehow arrange that the "hole" is filled. Either a) copy all elements to a new array of size tab.length - 1, b) use System.arraycopy or equivalent to move the elements after the deleted element, or c) assign null to the slot and change the classes to skip over null elements. (The last is probably a really bad idea ...)
Have MyIterator.remove() throw an UnsupportedOperationException. The remove method is an optional method according to the Iterator API spec.
Also what should happen in iterator() method of my main class ?
It should create and return an instance of the MyIterator class.
Take a look at java.util.ArrayList.
class MyCollection<T> implements List<T>{
T[] tab;
MyCollection(int len) {
tab = (T[])new Object[len];
}
public Iterator iterator(){
return new MyIterator(tab);
}
}
class MyIterator<T> implements Iterator {
private int current = 0;
private int last ;
private T[] tab;
public MyIterator(T[] tab){
this.tab = tab;
}
public void remove(){
throw UnsupportedException();
}
public T next(){
current ++ ;
return tab[current];
}
public boolean hasNext(){
current == tab.length - 1;
}
}
How about extending java.util.AbstractList? After all that's what all sun List implementations in java.util (but not in java.util.concurrent) do.
That way you only need to implement
get(int) and
add(E) (if you want to make the list mutable)
and some Constructors
You get all other methods (including iterator()) for free.
Related
I can't seem to find exactly how to do this anywhere. I am writing a class that takes a comparator as a parameter/argument for the constructor of a class. I want to use that to order items in a list. But I'm not sure what to do with the comparator in the new class.
I have imported java.util.Comparator
In the class declaration I said "impements Comparator<T>"
I have written (Comparator<T> c) as the argument for the constructor of the class.
I have never used a comparator this way--I've used it as an inner class and that is it so I'm not sure how to make the compare method work in this class when I take the comparator in as an argument to the constructor.
The only things I've done that are the three bulleted items above. Anytime I try to do something with comparator I am taking in as an argument, I get an error message.
Here is the code for the constructor:
public class SortedList<T> implements Comparator<T>
//value, position and array are instance variables
//I am switching array to a List to deal with generics
private int position;
private Integer[] array;
public SortedList(Comparator<T> c){
this.position = 0;
this.array = new Integer[25];
}
public void sort(Integer num){
boolean valid = false;
int i = 0;
while(!valid && i < array.length-1){
if(num.compareTo(array[i] > 0)){
array[i+1] = array[i];
array[i] = num;
}else{
i++;
}
}
The error messages I have been getting are:
Cannot find symbol - method compareTo
I would like to be able to compare any two objects, not just integers, that was why I wanted to take a comparator as a parameter.
It's not clear from your question, but the only collection-ish construct in your snippet is an array of integer objects. Thus, the only sane thing to sort here is that array.
You'd need a Comparator<Integer> to sort that, not a Comparator<T>.
Once you have that, to sort that array, all you need to do is..
Arrays.sort(array, c);
Your SortedList<T> class must not implement the Comparator<T> interface, because this class is not used for comparing objects. However, it will use a given Comparator<T> instance to sort its entries. This means the classes and methods should have the following definitions:
public class SortedList<T> {
// ...
}
The class does not implement the Comparator<T> interface anymore.
private T[] array;
The array field should be of type T[] since this SortedList<T> object is used to sort/hold objects of type T, not Integer objects.
public SortedList(Comparator<T> c){
// ...
this.comparator = c;
}
That's correct. The constructor receives a Comparator<T> instance. You should store this reference to a field so you can later use it in your sort() method.
public void sort(){
// ...
}
The Integer argument on the sort() method doesn't make any sense, so delete it. Now you can use the stored Comparator<T> instance in your sort() method and call its compare() method to compare two objects from your stored array. A code fragment might look like this:
// ...
if (this.comparator.compare(this.array[i], this.array[i+1])) {
// it should be on the left
} else {
// it should be on the right
}
// ...
while i was looking for something else i came across the below post in stackoverflow - How to convert int[] to Integer[] in Java?
here there is a code snippet as mentioned below,
int[] mInt = new int[10];
Integer[] mInteger = new Integer[mInt.length];
List<Integer> wrapper = new AbstractList<Integer>() {
#Override
public int size() {
return mInt.length;
}
#Override
public Integer get(int i) {
return mInt[i];
}
};
wrapper.toArray(mInteger);
Can someone please explain the above code for me?
am i missing something very fundamental in java language?
when i run through debugger, i see that get and size method gets called automatically, i.e without them being called explicitly from anywhere within or outside of the class !!
how so?!
You created an anonymous inner class that extends AbstractList and inherits all the methods from that class.
https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
It just overrides the size() and the get() method and everything else you can find in the class hierarchy.
So it is a good idea to look at the source code of AbstractList.
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/AbstractList.java
As you can see, this class does not imlement a toArray() method. So you have to look at the next class in the hierarchy:
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/AbstractCollection.java
And this class has an implementation of toArray() and inside this method the size() method is called.
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
But there is no get() call in the method. So you have to dig a little deeper. Receiving elements in the method is done through an iterator. AbstractCollection does not implement the method iterator() to receive one. This is an abstract method. It is implemented in the AbstractList class.
private class Itr implements Iterator<E> {
...
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
This is the place where get(i) is called.
When I debug the code and set breakpoints in my IDE, I get the following stacktraces:
size:14, CopyToArray$1
toArray:180, AbstractCollection (java.util)
main:23, CopyToArray
and
size:14, CopyToArray$1
hasNext:364, AbstractList$Itr (java.util)
toArray:187, AbstractCollection (java.util)
main:23, CopyToArray
Where CopyToArray is my class with main method to call from the IDE. As you can see there is a class with the name CopyToArray$1 which is the anonymous class that extends AbstractList.
Ok, here you deal with something called anonymous class:
You create a class "on-the-fly" that extends from AbstractList and override two methods : size and get
when i run through debugger, i see that get and size method gets called automatically, i.e without them being called explicitly from anywhere within or outside of the class !! how so?!
I don't really know what do you mean by "automatically" by its possible that IDE calls these methods to show the content and size of that list in a debugger "variables" window or something. For example if you run them (not debugging) and place some System.out.println inside the overriden methods you won't see any prints on console unless you really call this array.
Now as for the referred question. This approach is not really a good idea to convert things, the answer with streams or with loops are much better.
I am having a hard time finding this anywhere if this is a common problem but I am dealing with what is essentially a cascading type problem.
public class Graph<E> {
private LinkedList<Node<E>> nodes;
public Graph() {
this.nodes = new LinkedList<>();
}
public E[] getNodes() {
ArrayList<E> list = new ArrayList<>();
for (Node<E> node : nodes)
list.add(node.getObject());
return list.toArray(new E[0]); // any way to make this line work?
}
// other important stuff
}
I want to do something like this, however I can't instantiate the generic array this way. Where the getNodes() returns the content of the Nodes, not the Nodes themselves, but I can't figure out how.
I was thinking that the Node generic being defined by the Graph generic would mean that the Node class always has the same type as the Graph class. Is that not the case?
The Node class looks like
public class Node<E> {
private LinkedList<Edge> edges;
private E obj;
public E getObject() {
return obj;
}
// other useful stuff
}
Thanks for any help!
EDIT: all that is needed now is to make the returned Array of the right type. Is there a way to get an Array from an ArrayList that has a generic type assignment?
You need some form of reification of E in your getThings method.
If you want to keep the signature of getThings as it is, you can add a construtor parameter to provide the actual class E. With that class you can create an array to pass to the toArray(E[]) method of List<E>
private final Class<E> type;
private final List<E> list;
public CustomClass(Class<E> type) {
this.type = type;
this.list = new ArrayList<>();
}
#SuppressWarnings("unchecked")
public E[] getThings() {
Object[] reference = (Object[]) Array.newInstance(type, list.size());
return (E[]) list.toArray(reference);
}
Someone else came up with an answer that did not work but gave me an idea that ended up working, but they also put it in the comments section of the question so I will reiterate here and answer my own question.
This code works to solve the problem. I more or less lifted the logic from the ArrayList source code for their toArray(E[] a) function (with some of the meat of it cut out of course).
#SuppressWarnings("unchecked")
public E[] getNodes(E[] a) {
int size = nodes.size();
// creates an empty array of the right size and type
E[] arr =(E[]) java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
// fills that array with the correct data
for (int i = 0; i < size; i++)
arr[i] = nodes.get(i).getObject();
return arr;
}
Look at the ArrayList source code in order to see some logic that goes a step farther and accomplishes the same task in a way that is also Thread safe.
I have the following code:
public abstract class Heap {
Comparable<?> data[];
int count, size;
public Heap( int size ) {
this.size = size;
data = new Comparable<?>[ size + 1 ];
this.count = 0;
}
public abstract void insert( Comparable<?> item );
}
class MinHeap extends Heap {
public MinHeap (int size ) { super(size); }
public void insert( Comparable<?> item ) {
//this line here is giving me an error
//due to how I am storing the array in Heap
int k = data[ 0 ].compareTo( item );
}
}
The line indicated above is giving me this error: The method compareTo(capture#1-of ?) in the type Comparable<capture#1-of ?> is not applicable for the arguments (Comparable<capture#2-of ?>). I cannot figure out a way to make it work while maintaining these conditions: 1) I want the MinHeap to work with any data that implements Comparable, 2) I do NOT want to pass a pre-initialized array into the constructor. I say this because I do not want to do the following:
abstract class Heap< T extends Comparable<T> > {
T data[];
public Heap( T data[], int size ) {
this.data = data;
//I do not want to have to pass an instantiated array.
//I want the constructor to handle the instantiation. If I do this I know the issue with the
//compareTo will be solved, but I really prefer to avoid this.
}
}
My question is this: In my code, why am I getting this error? Does anyone know a way besides the way that is described in the second example? I would like to be able to create a min heap data structure with any comparable data. All helpful comments are appreciated. Thank you.
Side note: do not worry about the access modifiers of the instance variables. I left them as default for simplicity. I do know that they should be private with setters/getters or protected.
First of all, this code is invalid for creating a generic array:
data = new Comparable<?>[ size + 1 ];
This link in the Java Trails explains why it's illegal, but it boils down to the fact that arrays must know their type at compilation, and generics work based off of type erasure and can be inferred at runtime.
But before we can fix that, there's an issue with your generics - they're not really...generic. You're only using the wildcard generic here with no bounds.
If you want to have your abstract class with a generic array that is full of Comparable, then you want to have your abstract class with a bound to Comparable<T>, and have your data simply be bound to T. With this, we can finally fix the array initialization into a compilable (but unchecked cast) form:
data = (T[]) new Comparable[size + 1];
Here's the full class for reference. It's close to your second form, and doesn't require that you pass in an instantiated array. Further, since T is bound to Comparable<T>, we don't need to declare it as an argument in the method - we can simply provide T.
public abstract class Heap<T extends Comparable<T>> {
T data[];
int count, size;
public Heap(int size) {
this.size = size;
data = (T[]) new Comparable[size+1];
this.count = 0;
}
public abstract void insert(T item);
}
Further to this example, you would also want to add the generic type to your subclass as well:
class MinHeap<T extends Comparable<T>> extends Heap<T>
Try this one:
First compareTo() return int not boolean value.
public abstract void insert( Comparable<?> item ); is wrong.
Use List in case of generic instead of static array. For more info read How to create a generic array?
Sample code:
abstract class Heap<T> {
List<Comparable<T>> data;
public Heap(int size) {
data = new ArrayList<Comparable<T>>();
}
public abstract void insert(T item);
}
class MinHeap<T extends Comparable<T>> extends Heap<T> {
public MinHeap(int size) {
super(size);
}
public void insert(T item) {
int k = data.get(0).compareTo(item);
}
}
Your data can contain any kind of object, as long as its class implements Comparable. So you could have Strings, Integers, Longs, or Bananas inside your array.
And comparing an Integer with a String or with a Banana doesn't make sense. That's why the compiler doesn't let you compile this code.
The second way is the right way. You can use an array of objects internally, and cast each object to a T. If all your methods only accept instances of T, then the casts are guaranteed to succeed. Or you can use a List instead, which is much more generic-friendly than arrays.
I am trying to implement my own ArrayList without using java collections for practice purposes. At this stage I want to implement two of main methods, add(E) and get(int) tp get the idea. My code is given below. However I encountered few issues:
The line "return (E) myData[index]" issues warning "Type safety: Unchecked cast from Object to E". How can I address that
The Java 7 implementation of ArrayList.add(T), returns a boolean. Under what circumstances the add() has to return false. Under what logic it return false and when returns true?
Where can I find the source code of java 7 implementation of ArrayList
PS. Kindly don't just answer question 3 and refer me to the sucrose code for one and two!
import java.util.Arrays;
public class MyArrayList<E>{
private final int DEFAULT_SIZE=2;
private Object[] myData = new Object[DEFAULT_SIZE];
private int actSize=0;
public boolean add(E data){
if (actSize>=myData.length/2){
increaseSize();
}
myData[actSize++] = data;
return true;//when can it be false?
}
private void increaseSize()throws RuntimeException{
myData = Arrays.copyOf(myData, myData.length*2);
}
public E get(int index) throws RuntimeException{
if (index >= actSize){
throw new IndexOutOfBoundsException();
}
return (E) myData[index];
}
public static void main(String[] args) {
MyArrayList<String> arList = new MyArrayList<>();
arList.add("Hello");
arList.add("Bye bye!");
System.out.println(arList.get(1));// prints Bye bye! which is correct
}
}
The line "return (E) myData[index]" issues warning "Type safety:
Unchecked cast from Object to E". How can I address that
Suppress the warning
#SuppressWarnings("unchecked")
The Java 7 implementation of ArrayList.add(T) returns a boolean.
Under what circumstances the add() has to return false. Under what
logic it return false and when returns true?
See the javadoc
Returns:
true (as specified by Collection.add(E))
It always returns true.
Where can I find the source code of java 7 implementation of ArrayList
In your JDK installation's src.zip archive or find it online by simply searching
java ArrayList source code
The line "return (E) myData[index]" issues warning "Type safety: Unchecked cast from Object to E". How can I address that?
You're always going to have this unchecked cast warning, since you're working with a generic array. Generics and arrays don't really mix all that well, but the better convention is to have the generic type attached to the array anyway:
private E[] myData = (E[]) new Object[DEFAULT_SIZE];
You could always add #SuppressWarnings("unchecked") to the field itself to get that warning to go away.
#SuppressWarnings("unchecked")
private E[] myData = (E[]) new Object[DEFAULT_SIZE];
The Java 7 implementation of ArrayList.add(T), returns a boolean. Under what circumstances the add() has to return false. Under what logic it return false and when returns true?
This is a bit of an interesting question. Typically, one would expect that the restrictions on add come from Collections#add:
Collections that support this operation may place limitations on what elements may be added to this collection. In particular, some collections will refuse to add null elements, and others will impose restrictions on the type of elements that may be added. Collection classes should clearly specify in their documentation any restrictions on what elements may be added.
...but, since ArrayList is special in that it's designed to always expand its space when it's about to run out, it will (in theory) always be able to add something in. So, it should always return true.
Where can I find the source code of Java 7 implementation of ArrayList?
Grepcode is usually a good resource. You could also find it in src.zip if you downloaded the JDK with sources.
I do not think you could avoid that Type safety warning using a generic type. If it is really bothering you, you could add #SupressWarnings("unchecked").
Hmmm, I'm not sure about this one, but the Android implementation of Java, which isn't exactly the same says that it "always returns true". This is weird to me, but here's the link: http://developer.android.com/reference/java/util/ArrayList.html#add(E).
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java, but definitely download the source and check it out.
I have done little explanation in comments because it is clear to understand.
public class MyArrayList<E extends Object> {
private static int initialCapacity = 5;
private static int currentSize;
private Object[] myArrayList = {}, temp = {};
private static int currentIndex = 0;
public static void main(String[] args) {
MyArrayList arrList = new MyArrayList();
arrList.add("123"); //add String
arrList.printAllElements();
arrList.add(new Integer(111)); //add Integer
arrList.printAllElements();
arrList.add(new Float("34.56")); //add Integer
arrList.printAllElements();
arrList.delete("123");
arrList.printAllElements();
arrList.delete(123);
arrList.printAllElements();
arrList.delete(123);
arrList.printAllElements();
}
public MyArrayList() { //creates default sized Array of Objects
myArrayList = new Object[initialCapacity]; //generic expression
/* everytime I cross my capacity,
I make double size of Object Array, copy all the elements from past myObject Array Object
*/
}
public MyArrayList(int size) { //creates custom sized Array of Objects
myArrayList = new Object[size];
}
public void add(Object anyObj) {
//add element directy
myArrayList[currentIndex] = anyObj;
currentSize = myArrayList.length;
currentIndex++;
if (currentIndex == currentSize) {
createDoubleSizedObjectArray(currentSize);
}
}
//print all elements
public void printAllElements() {
System.out.println("Displaying list : ");
for (int i = 0; i < currentIndex; i++) {
System.out.println(myArrayList[i].toString());
}
}
private void createDoubleSizedObjectArray(int currentSize) {
temp = myArrayList.clone();
myArrayList = new MyArrayList[2 * currentSize]; //myObject pointer big size data structure
// myObject = temp.clone(); //probably I can do this here as well. Need to check this
System.arraycopy(temp, 0, myArrayList, 0, currentSize);
}
void delete(Object object) {
//if already empty
if (currentIndex == 0) {
System.out.println("Already empty!");
return;
}
//you don't need to delete anything. I can simply override the storage
currentIndex--;
}
}