I am developing a big example case for teaching generics. A group of classes and interfaces that mimic the collections class in Java. Here's one of the source files:
package edu.brandeis.cosi12b.listdemo;
public class ArrayList<E extends Comparable<E>> extends AbstractList<E> implements List<E> {
private E[] list;
private int size;
private int capacity;
public ArrayList() {
this(20);
}
#SuppressWarnings("unchecked")
public ArrayList(int initialCapacity) {
list = (E[]) (new Object[initialCapacity]);
size = 0;
capacity = initialCapacity;
}
public int capacity() {
return capacity;
}
public int size() {
return size;
}
public void add(E val) {
list[size] = val;
size++;
}
public String toString() {
StringBuffer s = new StringBuffer();
s.append("[");
for (int i = 0; i < size - 1; i++) {
s.append(list[i]);
s.append(", ");
}
s.append(list[size - 1]);
s.append("]");
return (s.toString());
}
public void set(int index, E value) {
expandIfNecessary(index);
for (int i = size; i > index; i--) {
list[i] = list[i - 1];
}
list[index] = value;
if (index > size)
size = index + 1;
}
#SuppressWarnings("unchecked")
private void expandIfNecessary(int index) {
if (index < capacity)
return;
int newCapacity = capacity * 2 + index;
E[] oldArray = list;
list = (E[]) (new Object[newCapacity]);
for (int i = 0; i < size; i++)
list[i] = oldArray[i];
capacity = newCapacity;
}
public E get(int index) {
if (index < 0 || index >= size)
throw new ArrayIndexOutOfBoundsException("i: " + index + " s: " + size);
return list[index];
}
public void remove(int index) {
for (int i = index; i < size; i++)
list[i] = list[i + 1];
size--;
}
public boolean isEmpty() {
return size() == 0;
}
public int indexOf(E value) {
for (int i = 0; i < size; i++) {
if (list[i] == value)
return i;
}
return -1;
}
public boolean contains(E value) {
return (indexOf(value) != -1);
}
#Override
public void add(int index, E value) {
// TODO Auto-generated method stub
}
}
When I run this in a test case I get this error. I know it's something pretty subtle and it exceeds my knowledge of Java.
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
at edu.brandeis.cosi12b.listdemo.ArrayList.<init>(ArrayList.java:14)
at edu.brandeis.cosi12b.listdemo.ArrayList.<init>(ArrayList.java:9)
at edu.brandeis.cosi12b.listdemo.TestSuite.arrayListtest1(TestSuite.java:134)
at edu.brandeis.cosi12b.listdemo.TestSuite.runArrayListTests(TestSuite.java:15)
at edu.brandeis.cosi12b.listdemo.TestSuite.runAll(TestSuite.java:9)
at edu.brandeis.cosi12b.listdemo.ListDemo.runTests(ListDemo.java:13)
at edu.brandeis.cosi12b.listdemo.ListDemo.main(ListDemo.java:6)
Use
list = (E[]) new Comparable<?>[initialCapacity];
and
list = (E[]) (new Comparable<?>[newCapacity]);
Java doesn't have fully reified generics at runtime (it uses erasure), so it doesn't actually know what E is - only that it extends Comparable, so that is what the compiler inserts for the casts.
The bytecode generated by the compiler for your code looks like this if decompiled:
list (Comparable[]) new Object[initialCapacity];
which fails.
Related
This question already has answers here:
How to compare two double values in Java?
(7 answers)
Closed 11 months ago.
I was messing around with data structures and while creating a Dynamic Array in Java from scratch, I figured out that my delete method (in the DynamicArray class) was not working for doubles.
I've read some documentation and I realized that doubles in Java are treated differently when it comes to comparison.
So I found ways to compare just doubles, but what do you do when the comparison is part of random data (Object type)?
Here is my code:
---Main---
public class Main {
public static void main(String[] args) {
//ArrayList<String> dynamicArray = new ArrayList<>();
DynamicArray dynamicArray = new DynamicArray();
System.out.println(dynamicArray.isEmpty());
dynamicArray.add(7);
dynamicArray.add(15);
dynamicArray.add(13);
dynamicArray.add("A");
dynamicArray.add('C');
dynamicArray.add(3.14159);
System.out.println("size: "+ dynamicArray.size());
System.out.println("capacity: "+ dynamicArray.capacity());
System.out.println(dynamicArray.toString());
dynamicArray.insert(2, "Hello");
System.out.println(dynamicArray.toString());
dynamicArray.delete(3.14159);
System.out.println("After removing 3.14159: "+ dynamicArray.toString( ));
dynamicArray.delete(7);
System.out.println(dynamicArray.toString());
}
}
---DynamicArray---
public class DynamicArray {
final double EPSILON = 0.000001d;
private int size;
private int capacity = 7;
Object[] array; // created an array of Objects named array
public DynamicArray() {
this.array = new Object[capacity];
}
public DynamicArray(int capacity) {
this.capacity = capacity;
this.array = new Object[capacity];
}
public void add(Object data) {
if (size >= capacity) {
grow();
}
array[size] = data;
size++;
}
public void insert(int index, Object data) {
if (size >= capacity) {
grow();
}
for (int i = size; i > index; i--) {
array[i] = array[i-1];
}
array[index] = data;
size++;
}
public void delete(Object data) {
for(int i = 0; i < size; i++) {
if(array[i] == data) {
for(int j = 0; j < (size - i - 1); j++){
array[i + j] = array[i + j + 1];
}
array[size - 1] = null;
size--;
if(size <=(int) (capacity/3)) {
shrink();
}
break;
}
}
}
public int search(Object data) {
return -1;
}
public void grow() {
}
public void shrink() {
}
public boolean isEmpty() {
return size == 0;
}
public Object peek() {
return array[size-1];
}
public String toString() {
String string = "[";
for (int i = 0; i < capacity; i++) {
string += array[i] + ", ";
}
if (string != "[") {
string = string.substring(0,string.length()-2);
}
return string+"]";
}
public int size() {
return size;
}
public int capacity() {
return capacity;
}
}
Am I missing something?
Objects in Java must be compared with equals(), not ==.
public void delete(Object data) {
for(int i = 0; i < size; i++) {
if(array[i] == data) {
for(int j = 0; j < (size - i - 1); j++){
The if(array[i] == data) will compare object references, not the objects' values.
you can use equals method of object, this way you don't need to use comparisons but you should check for null values.
public void delete(Object data) {
for(int i = 0; i < size; i++) {
if(array[i]!=null && array[i].equals(data)) {
for(int j = 0; j < (size - i - 1); j++){
array[i + j] = array[i + j + 1];
}
array[size - 1] = null;
size--;
if(size <=(int) (capacity/3)) {
shrink();
}
break;
}
}
}
This is my Arraylist I'm having trouble how to make a new class to check if my methods work.
Any help will be useful I need to know how to make a start my new class .
I create a class but I keep getting it wrong.
Do I have to extend it our in my new class am only?
Any assistance will be greatly useful.
public class MyArray<E extends Comparable<E>> {
// No other data fields necessary.
private E[] data;
private int size;
public MyArray(int size) {
this.data = (E[]) (new Comparable[size]);
size = 0;
}
public void add(E item) {
if (size == data.length)
resize();
data[size] = item;
size++;
}
private void resize() {
int len = data.length * 2;
E[] temp = (E[]) new Comparable[len];
for (int i = 0; i < size; i++)
temp[i] = data[i];
data = temp;
}
public boolean contains(E item) {
for (int i = 0; i < size; i++) {
if (data[i].equals(item))
return true;
}
return false; // not found
}
public void delete(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException();
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
}
public boolean delete(E item) {
if (item == null)
return false;
for (int i = 0; i < size; i++) {
if (data[i].equals(item)) {
delete(i); // delete at index i
return true;
}
}
return false;// not found
}
}
Since your class is defined with generics (the E), you have to provide an actual type for E. Actually, it should work pretty much like ArrayList class.
MyArray<String> a = new MyArray<String>(10);
a.add("Foo");
a.add("Bar");
I have a jagged array.
How can I override next(), so I can get its elements step-by-step?
This might be a wrong answer to your question. I'll remove it in that case, but maybe you can use it for what you want to achieve:
int[][] it = {{1,2}, {3,4,5}};
OfInt iterator = Arrays.stream(it).flatMapToInt(x -> IntStream.of(x)).iterator();
iterator.forEachRemaining((IntConsumer) System.out::print);
Stream the jagged array, flatmap it into one single IntStream and then do what you want with it. In this example I fetched the iterator but you might only want:
Arrays.stream(it).flatMapToInt(x -> IntStream.of(x)).forEach((IntConsumer) System.out::print);
In forEach you can do what you need, or use some other method of IntStream
Thank you all for your answers, I've found my answer in russian stackoverflow:
https://ru.stackoverflow.com/questions/867881/java-iterator-%D0%B4%D0%BB%D1%8F-%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0
public class IteratorFor2DArray implements Iterator {
private int size;
private int i = 0;
private int j = 0;
private int[][] values = new int[i][j];
private int position = 0;
public IteratorFor2DArray(int[][] values) {
this.values = values;
this.size = countOfElements(values);
}
private int countOfElements(int[][] values) {
int count = 0;
for (int[] row : values) {
count += row.length;
}
return count;
}
#Override
public boolean hasNext() {
return position < size;
}
#Override
public Integer next() {
if (position >= size) {
throw new NoSuchElementException();
}
int element = values[i][j];
position++;
j++;
while (i < values.length && j >= values[i].length) {
j = 0;
i++;
}
return element;
}
}
I've also found another way:
public class IteratorFor2DArray implements Iterator {
private int[][] data;
private int i, j;
public IteratorFor2DArray(int[][] data) {
this.data = data;
}
#Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
int element = data[i][j];
j++;
while (i < data.length && j >= data[i].length) {
j = 0;
i++;
}
return element;
}
#Override
public boolean hasNext() {
return (i < data.length && j < data[i].length);
}
}
So I was trying to return the max value within an type "T" array list and got an error while using compareTo. This is the full code.
package myUtil;
public class SimpleListAry<T extends java.lang.Comparable<T>> extends java.lang.Object implements SimpleList<T> {
private T[] myList;
private int size;
public SimpleListAry(){
myList = (T[])new Comparable[10];
}
public SimpleListAry(int capacity){
if (capacity <= 0){
throw new IllegalArgumentException();
}
myList = (T[]) new Object [capacity];
}
#Override
public int size() {
size = myList.length;
return size;
}
#Override
public T get(int i) {
return myList[i];
}
#Override
public T set(int i, T item) {
return myList[i] = item;
}
#Override
public int indexOf(Object item) {
for (int i = 0; i < size; i++){
if (get(i).equals(item)){
return i;
}
}
return -1;
}
#Override
public void add(int at, T item) {
if (at < 0 || at > size)
throw new ArrayIndexOutOfBoundsException(at);
for (int i = size; i > at; i--){
myList[i] = myList [i-1];
}
// myList[at] = item;
size++;
}
#Override
public T remove(int at) {
if (at < 0 || at >= size)
throw new ArrayIndexOutOfBoundsException(at);
T item = myList[at];
for (int i = at; i<size-1; i++)
myList[i] = myList[i+1];
size--;
return item;
}
#Override
public T max() {
T max = myList[0];
for (int i = 1; i < myList.length; i++){
if(myList[i].compareTo(max) == 1)
max = myList[i];
}
return max;
}
#Override
public T min() {
T min = myList[0];
for (int i = 1; i < size -1; i++){
if (myList[i].compareTo(min) == -1)
min = myList[i];
}
return min;
}
}
and the error is at Public T max():
public T max() {
T max = myList[0];
for (int i = 1; i < myList.length; i++){
if(myList[i].compareTo(max) == 1)
max = myList[i];
}
return max;
}
I also tried using ">" to compare them but that was not working either. It may be because of the data type but there's no error in the IDE only when I attempt to run it and it points directly to this line in T max(){
if(myList[i].compareTo(max) == 1)
Three possibilities of null pointer in if(myList[i].compareTo(max) == 1)
myList - being initialized in constructor, not null
myList[i] - list initially filled with null !
max, depending on how compareTo is implemented - initialized to myList[0], can be null if list empty
The second case is the problem since the elements of the whole underlying array are being compared without considering the real size of the list.
The size() method is wrong since it sets the size variable, which is returned, to the length of the array overwriting the correct value.
Just remove the assignment statement inside the size() method (and use that method in the comparison loop)
I am reading from SQLite in android some name of Files, I have like 3000 names that are added to an ArrayList but I discovered that I can't have more than 1000.
Is 1000 maximum size of an ArrayList<String> ? Searching over the internet I found that depends.
I found some math operations here (http://www.coderanch.com/t/524745/java/java/Maximum-capacity-arrayList-String-objects ) with 1000, and I found that the maximum capacity of an ArrayList<String> is given by Java Virtual Machine Memory.
Is there a way how to increase this ?
I have created an arrayList, its unlimited. you can also manipulate it to your desire, its has all the basic features of an arraylist.
here is the code.
public class BetterArray<E> {
private E[] array;
private final int DEFAULT_ARRAY_SIZE = 10;
private int size;
private void copyArray(E[] copyFrom, E[] copyTo) {
for (int i = 0; i <= copyFrom.length-1; i++) {
copyTo[i] = copyFrom[i];
}
}
private void createAnotherArray(){
int newSize = 2 * array.length;
E[] newArray = (E[])(new Object[newSize]);
copyArray(array, newArray);
array = newArray;
}
public BetterArray() {
array = (E[]) (new Object[DEFAULT_ARRAY_SIZE]);
this.size = 0;
}
public E get(int index){
if(index < 0 || index > size){
throw new RuntimeException("index not valid");
}
else{
return array[index];
}
}
public boolean isEmpty() {
if (size == 0)
return true;
else
return false;
}
public void insert(int position, E element) {
if(isFull())
createAnotherArray();
E previous_temp = get(position);
array[position]= element;
for(int k = position+1; k<= size; k++){
E current_temp = get(k);
array[k] = previous_temp;
previous_temp = current_temp;
}
size++;
}
public void append(E element) {
insert(size, element);
}
public void remove(int index){
for (int i = index; i <= size-1; i++){
array[i] = get(i+1);
}
size--;
}
public void shift(E element){
insert(0, element);
}
public boolean isFull() {
if (size == array.length)
return true;
return false;
}
public int size(){
return size;
}
public String toString(){
StringBuilder returnString = new StringBuilder();
for(int i= 0; i <= size-1; i++){
returnString.append(get(i).toString() + ", ");
}
return returnString.toString();
}
// public int index(E element){
// return 1;
// }
public void reverse(){
E temp_storage;
int halfSize = (size/2) ;
for (int k= 0; k<= halfSize; k++ ){
temp_storage = array[k];
array[k] = array[size-k-1];
array[size-k-1] = temp_storage;
}
}
}