Converting Collections to Arrays Every Java collection can be converted to an array This is part of the basic Collection<T> interface The most elementary form of this method produces an array of base-type (java.lang.object): Class #12: Converting Collections to Arrays; Linked Lists public Object[] toarray(); This method can be quite simple, although there are some complications to which we must pay attention Software Design III (CS 340): M. Allen, 19 Feb. 19 Tuesday, 19 Feb. 2019 Software Design III (CS 340) 2 A Bad Approach to Array Conversion The simplest approach to such a method, for something like an ArrayList, is actually a bad idea public Object[] toarray() return theitems; This seemingly simple approach essentially makes the array contained by the list object a public entity After running this method, other classes would be able to directly access the array, adding data wherever desired, including in places that are outside of the bounds given by the size() of the list This goes against the whole idea of encapsulating data as private members of a class A Better Approach to Array Conversion Instead of direct access to the contained array, a better approach is to create a new one, and copy over public Object[] toarray() Object[] copy = new Object[theSize]; for (int i = 0; i < thesize; i++) copy[i] = theitems[i]; return copy; Tuesday, 19 Feb. 2019 Software Design III (CS 340) 3 Tuesday, 19 Feb. 2019 Software Design III (CS 340) 4 1
Important: Java Copies are Shallow A method like the one just shown creates a brand-new array At the same time, the items inside the array are not new This is default Java Collection behavior: copies and array conversions are always shallow copies: changes made to such items will change the objects in both collections in which they are referenced ArrayList<JFrame> framelist = new ArrayList<>(); for (int i = 0; i < 5; i++) framelist.add(new JFrame("Old Title")); System.out.println(frameList.get(0).getTitle()); Object[] framearray = framelist.toarray(); ((JFrame) framearray[0]).settitle("new Title"); System.out.println(frameList.get(0).getTitle()); Old Title New Title (Changing in array also changes in list) Complication: Generic Arrays Cannot Be Instantiated Suppose we want to convert a generic ArrayList<T> to an array of the same type: public T[] toarray() T[] array; array = new T[theSize]; for (int i = 0; i < thesize; i++) array[i] = theitems[i]; return array; This won t compile! While we can declare the array to have generic type, we cannot instantiate it: we are required to give it an actual type first error: Cannot create a generic array of T Tuesday, 19 Feb. 2019 Software Design III (CS 340) 5 Tuesday, 19 Feb. 2019 Software Design III (CS 340) 6 Getting around the Generic Array Issue To set the return type, we need to supply something that is guaranteed to have a non-generic specified type: import java.lang.reflect.array;... We can use Java s ability to do reflection to create a new array of the same class-type as the input array (works even if empty) public T[] toarray(t[] a) T[] array = (T[]) Array.newInstance(a.getClass().getComponentType(), size()); Getting Around the Generic Array Issue The reason to include the input array, rather than just get the type of the list data itself is that we can use the input array to provide type-checking at the calling site: MyArrayList<Integer> lsti = new MyArrayList<Integer>(); MyArrayList<Double> lstd = new MyArrayList<Double>(); Integer[] ints = lsti.toarray(new Integer[0]); Double[] dubs = lstd.toarray(new Double[lstd.size()] ); for (int i = 0; i < size(); i++) array[i] = theitems[i]; return array; Since newinstance() returns an Object, we must cast to T[] getclass(): from java.lang.object getcomponenttype(): from java.lang.class (used specifically to get type of an array element) Since the array typing and casting occurs inside of toarray() method, we can be certain that, if the method completes, we have actual (non-erased) arrays of the given types (Integer or Double) While we can convert even with an empty array, there turns out to be a reason to use the second version of this sort of call in most cases. Tuesday, 19 Feb. 2019 Software Design III (CS 340) 7 Tuesday, 19 Feb. 2019 Software Design III (CS 340) 8 2
A Small Efficiency All else being equal, we will prefer: Double[] dubs = lstd.toarray(new Double[lstd.size()] ); This turns out to save on object typing, creation and casting, and can run significantly faster overall. The Linked List ADT head: public T[] toarray(t[] a) if (a.length >= size()) for (int i = 0; i < size(); i++) a[i] = theitems[i]; if (a.length > size()) a[size()] = null; return a; // code to create new array if needed... If we can fit the current list into the input array, then simply copy over without need for typing, array creation, casting. If input array larger than needed, set element at end of list-data to null. Warning: this will be a problem when list could contain null items itself, so we always prefer to use size of list for input array if at all possible. Tuesday, 19 Feb. 2019 Software Design III (CS 340) 9 General idea: an implementation of List interface/adt, using a set of linked nodes, with size() == # nodes Each node two basic attributes: Data: object that it stores (simple or complex) Next link: a variable reference to the next node in list End of list links to null object (can be used as a marker) Tuesday, 19 Feb. 2019 Software Design III (CS 340) 10 Doubly Linked Lists head: Actual java.util. class is slightly more complex, since each node has two separate links A bi-directional, doubly-linked list s link to both the next and previous nodes in list order Front: prev links to null object Back: next links to null object Tuesday, 19 Feb. 2019 Software Design III (CS 340) 11 One Last Complication: Sentinel s :head tail: For convenience, implementations will use one/more sentinel nodes These track the start (head) or end (tail) of the list (and have no data) Can make code easier to write, but don t generally change basic behavior Tuesday, 19 Feb. 2019 Software Design III (CS 340) 12 3
s private static class <T> private T data; private <T> prev; private <T> next; public ( T d, <T> p, <T> n ) data = d; prev = p; next = n; Basic data component of list is a nested, private static class Packaged inside list class itself private to that class, so it cannot be created anywhere else by itself It carries the type of the list class instance, <T> Making the class static separates it from the parent class, so it has no requirement for a linked instance of the parent to exist This simplifies things, and can improve memory management This is a good approach, so long as the nested class doesn t need direct access to other nonstatic members (variables, methods) of the containing class Containing List class does have direct access to elements, whether is static or not Creating the public class My<T> implements Iterable<T> private int thesize; private <T> head; private <T> tail; public My() clear(); public void clear() head = new <T>( null, null, null ); tail = new <T>( null, head, null ); head.next = tail; thesize = 0; Use head/tail nodes to indicate start/end of list Can access private next and prev link variables in directly, since it is a nested member class, contained entirely inside the List class itself. Tuesday, 19 Feb. 2019 Software Design III (CS 340) 13 Tuesday, 19 Feb. 2019 Software Design III (CS 340) 14 Creating the prev: :head tail: size: 0 head = new <T>( null, null, null ); tail = new <T>( null, head, null ); head.next = tail; Iterators private class Iterator implements java.util.iterator<t> private <T> current = head.next; public boolean hasnext() return current!= tail; public T next() if(!hasnext() ) throw new java.util.nosuchelementexception(); T nextitem = current.data; current = current.next; return nextitem; public void remove() My.this.remove( current.prev ); This private inner class is not static It can easily directly access any other elements of the List class it needs. Use the head/tail nodes as indicators of the start/end of the list Use the next/prev variable references to navigate from node to node in the list. Tuesday, 19 Feb. 2019 Software Design III (CS 340) 15 Tuesday, 19 Feb. 2019 Software Design III (CS 340) 16 4
This Week Topic: Lists Read: Text, chapter 03 Meetings: as usual Monday Wednesday: 2205 Centennial Friday: Lab, 16/17 Wing Homework 02: due Friday, 01 March (5:00 PM) Office Hours: Wing 210 Monday: 9:00 AM 10:30 AM Tuesday: 3:00 PM 4:00 PM Wednesday: 9:00 AM 10:30 AM Thursday: 2:00 PM 3:00 PM Friday: 9:00 AM 10:30 AM Tuesday, 19 Feb. 2019 Software Design III (CS 340) 17 5