290 likes | 499 Views
ARRAYS. Why Use Arrays Syntax Multi-Dimensional Arrays Vectors Adaptor Pattern. Why Use Arrays?. Until now, we have used variables that hold references only to single objects
E N D
ARRAYS • Why Use Arrays • Syntax • Multi-Dimensional Arrays • Vectors • Adaptor Pattern
Why Use Arrays? • Until now, we have used variables that hold references only to single objects • But what if we want to hold lots of data? Many programs need to keep track of hundreds, or thousands of pieces of information • We want to hold arbitrary number of objects with single reference • represents collection of elements • can then send messages to multiple elements much more easily • Arrays are oldest form of composite data structure, first found in FORTRAN (FORmula TRANslator, 1955), the first high-level programming language, designed by IBM for number-crunching and still in use today: “FORTRAN is a hardy weed…”
Fibonacci Series • Suppose we want to keep track of first 20 numbers in Fibonacci series • sequence begins with zero and one • successive numbers are determined by adding previous two numbers • third number: add first and second numbers (0+1) • fourth number: add second and third numbers (1+1); • and so on... • Beginning of sequence looks like this: 0 1 1 2 3 5 8 13 21 34 55 89 • We could do it with instance variables... public class FibSequence { private int _firstNum, _secondNum, _thirdNum, ... _twentiethNum; } • This gets tiresome and is not very flexible • try making one with forty numbers • now try it with a thousand!
Arrays • Arrays store a specified, constant number of homogeneous data elements • simplest homogeneous collection • each element must be same type or subclass of same type • Arrays are special in Java • Java provides special syntax to access array elements • use new to instantiate an array • cannot subclass off an array • arrays don’t have any methods • neither base type nor class, but Java construct • Arrays hold only elements of specified type • when declaring array, declare type that array stores (base type, class, or interface) • if class, can only put references to instances of that class (or subclasses) into array • could declare java.lang.Object if you wanted to be so general that you could store any instance, but highly unlikely you’d do that
Arrays (cont.) • Every array element is object reference or base type • floors of building • streets in Manhattan • strings representing names of people in a course • Elements are ordered sequentially by numerical index • in mathematics, we refer to related variables by using subscript notation, i.e., A1, A2, A3, ... An • with Java, represent subscript inside brackets, i.e., array[0], array[1], ... array[n-1] • Arrays store objects in numbered slots • for array of size n, first index is always 0, last index is always n-1 • Common graphical representations of arrays: [0] [1] [2] [3] [18] [19] [0] [1] [2] [3] [4] [5] [17] [18] [19]
Java’s Syntax for Arrays • Declaration: <type>[] <array-name>; • <type> denotes type that data array is to hold in each slot • can be class, base type, interface, or even another array (for nested arrays) • Colorable[] myColorables; declares array that holds instances of classes that implement Colorable interface • Note: unlike some other programming languages, in Java, size of array is not specified in declaration, but in initialization • Initialization <array-name> = new <type>[<size>]; • <size> must be an integer value greater than 0 // here we initialize array declared elsewhere myColorables = new Colorable[10]; • note only array is initialized, not elements of array; all elements are set to null // alternatively we can declare and initialize // in one statement Colorable[] otherColorables = new Colorable[5];
Java’s Syntax for Arrays (cont.) • Accessing individual elements: <array-name>[<index>] • index must be an integer between 0 and (array size - 1) • result is variable stored at that index • if index is greater than or equal to size, or less than 0, throws an ArrayIndexOutOfBoundsException • any place a constant or variable can occur, you can have an array element // initialize first element of the array to be // an Ellipse myColorables[0] = new gfx.Ellipse(this); // send a message to 3rd element of the array myColorables[2].setColor(java.awt.Color.red); // assign fourth element of the array to // another variable Colorable myOneColorable = myColorables[3]; // pass 5th element of the array as parameter _myPaintShop.paintRandomColor(myColorables[4]); • Note: in many other languages, index can run between any two integers (m,n), where m<n
Arrays as Parameters • Can declare an entire array as parameter by adding bracket to type of formal parameter public int sum(int[] numbers) { // code to compute sum of numbers } • But how do we determine size of array? • could pass a second parameter, specifying size • arrays have their length as a public property • we use special syntax to find out the length of the array int arrayLength = <array-name>.length; public int sum(int[] numbers) { int total = 0; for (int i = 0; i < numbers.length; i++) { total += numbers[i]; } return total; } • this kind of “looping through array” with a definite for loop is a very common pattern
Example: Making Cookies • Here is specification Design and implement a Java program with ten factories that generate cookies in a row at the top of the frame. When “Create Cookies” button is pressed all factories should make a cookie just below the factory’s position and drop it so it falls down and then out of the frame.
Quick Look at Design • Finding the nouns Design and implement a Java program with ten factories that generate cookies in a row at the top of the panel. When “Create Cookies” button is pressed all factories should make a cookie just below the factory’s position and drop it so it falls down and then out of the panel. • Some things we’ve seen before: • Java program – uses a javax.swing.JFrame • panel - JPanelcookies are graphically contained in a panel • cookie – java.awt.Image that has behavior to move down panel • factories that generate cookies - clearly the factory pattern. Use a java.awt.Image that has a makeCookie() method which makes new cookie at own position. • Note: you will learn about how to use java.awt.Image in section! • row - javax.swing.JPanel to layout cookie factories • Things that aren’t as apparent • how do we make button do something for all factories in sequence • how do we deal with ten cookie factories usefully?
‘Create Cookies’ Button • NEW button operation • extends javax.swing.JButton, add a java.awt.event.ActionListener that does something useful. public class DropButton extends javax.swing.JButton { // CookieFactory is defined elsewhere // (actual definition is not important for us) private CookieFactory[] _cookieFactoryArray; public DropButton(CookieFactory[] array) { super(container, "Create Cookies”); _cookieFactoryArray = array; this.addActionListener(new DropListener()); } private class DropListener implements java.awt.event.ActionListener { public void actionPerformed(java.awt.event.ActionEvent e) { /* when button pressed, use loop to tell every Factory in array to makeCookie */ int size = _cookieFactoryArray.length; for (int i = 0; i < size; i++) { _cookieFactoryArray[i].makeCookie(); } } } // end of inner class DropListener } // end of class DropButton
Out-of-Bounds Problems • Be careful about bounds of loops that access arrays: • Java will throw ArrayIndexOutOfBoundsException if index is negative since sequence starts at 0 • Java will throw ArrayIndexOutOfBoundsException if index is greater than or equal to array size; remember that the array goes from 0 to n-1 • exceptions usually lead to crashes so be careful • Java has a catch keyword which can be used to “catch” and handle exceptions… but you don’t need to worry about this right now • Prevent out-of-bounds problems by explicitly checking with conditionals before accessing public boolean indexInBounds(int index) { return ((index >= 0) && (index < _factoryArray.length)); } • don’t need to do this in for loop, but could be useful in indefinite loop • In general, important to check values of parameters yourself to prevent problems
Multi-Dimensional Arrays • Say we wanted to model a chess board • not a linear group of squares • more like a grid of squares • Can declare an array to be 2 (or more) dimensions, by adding more brackets • one pair per dimension • 2D: int[][] grid = new int[a][b]; • 3D: int[][][] cube = new int[x][y][z]; • Think of a 2D array as an array of arrays • array [i][j] • element at i+1th row, j+1th column MAX_COLS - 1 0 0 . . . MAX_ROWS - 1
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Row Major Ways to Think About Array Storage • Java stores arrays in “row major" format • E.g., int[][] grid = new int[5][3]; looks like this (where the numbers represent ordering of elements by subscript, not by their data): • Rows come first, so you think of grid[1][2] as the element in row 1, col 2. • This should look familiar to those who’ve worked with matrices in math grid[1][2]
0 3 6 9 12 1 4 7 10 13 2 5 8 11 14 Column Major x 0 1 2 3 4 0 1 2 (1, 0) y (3, 2) Thinking About Arrays for Graphics • When working with computer graphics you might find it easier to think of your array in column major format • that way you can think of it the same way you do pixels on the screen: first index is x, second y • Java doesn’t let you store arrays in column major format but you can use a trick… grid[3][2] is element in column 3, row 2
0 1 2 0 3 6 9 1 3 4 5 1 4 7 1 3 6 7 8 2 5 8 1 1 9 1 1 1 3 1 How to use arrays as Column Major • You can transpose the row and column indices and think of the array as stored in column major order. • Then grid [3][1] to you is element at column 3, row 1, even though it is actually stored in Java’s internal row major form at row 3, column 1. • As long as you are consistent in storing and accessing elements as if they were in a column major matrix, the transposition trick will work You think of [3][1] as being here. In actuality, it’s here. The cool thing is, you can still create your array normally, think of [3][1] as being here, and it will all work out fine. Column Major Row Major
0 1 2 0 3 6 9 1 3 4 5 1 4 7 1 3 6 7 8 9 1 1 2 5 8 1 1 1 3 1 Accessing 2D Arrays int[][] grid = new int[5][3]; • To access next element: • next = grid[i][j+1]; • for row major this is next element across, for column major it’s next element down • To get the number of rows and columns in a row major 2D array • int numRows = grid.length; • numRows would be equal to 5 • int numCols = grid[0].length; • grid[0] is short for 0th row, and therefore its length is equal to the number of columns • numCols would be equal to 3 • To get them for a column major 2D array • mentally flip rows and cols • also flip the lengths, to get Java to give you the new “view” • int numRows = grid[0].length; • numRows would be equal to 3 • int numCols = grid.length; • numCols would be equal to 5 Column Major Row Major
What would this output? Example: Size of 2D Arrays • In this example, we will think of our array as being stored “Row Major”, so no flipping needed public class ArraySize { private final static int NUM_ROWS = 10; private final static int NUM_COLS = 5; public ArraySize() { // java.awt.Image is just an arbitrary // choice! java.awt.Image[][] graphics = new java.awt.Image[NUM_ROWS][NUM_COLS]; System.out.println( “Number of rows = ” + NUM_ROWS); System.out.println( “Number of columns = ” + NUM_COLS); System.out.println( “Elements in array = ” + this.find2DArraySize(graphics)); } public int find2DArraySize(Object[][] array){ int numRows = array.length; int numCols = array[0].length; return (numRows * numCols); } }
Common Array Errors • Assigning a scalar to array int[] myArray = 5; • 5 is not an array, it is an element • Assign an array to a scalar int[] myArray = new int[1000]; int myInt = myArray; • Assigning arrays of different dimension to each other int[] myIntArray = new int[23]; int[][] my2DIntArray = new int[2][34]; myIntArray = my2DIntArray; • Never try to assign arrays of different dimensions or you will become best friends with something similar to “Incompatible type for =. Can’t convert int[] to int[][]” • similar message for assigning arrays of the wrong type
java.util.Vectors • java.util.Vectors, like arrays, hold many references to objects • Another kind of collection • Differences: • don’t need to be initialized with size • can hold unlimited number of references • are Java classes, so have methods • Why use them instead of arrays? • when number of elements to be held is unknown • making array too small leads to bugs or crashes • making array too large is inefficient, takes up more memory than necessary • Why use arrays instead of vectors? • you want something simple • concerned about taking up less memory • concerned about faster operations
java.util.VectorMethods // note: only most important methods are shown // see documentation for full interface public Vector() // returns the object at index public ElementType elementAt(int index) // inserts object at index public void add(int index, ElementType element) // adds object to end of vector public void addElement(ElementType element) // remove object at index public ElementType remove(int index) // remove first occurrence of object public boolean removeElement(Object obj) // replaces the object at index with element public ElementType set(int index, ElementType element) public int indexOf(Object elem) //finds first one public boolean contains(Object elem) //at least 1 public int size() public boolean isEmpty() • Some notes • can add object at particular slot or at end • adding element displaces following objects by one, i.e., increments their index by 1 • setting element does not displace other elements • removing element causes all following objects to be shifted down one index • removeElement returns false if the object is not in the vector • since ordered, can use for loop to access objects Question #1: What are all thoseElementTypes?
How to Use Vectors • How can Vector hold any object? • Every class implicitly extends Object • every object “is an” Object • methods of Object you can usefully redefine: • booleanequals(Object obj): check for equality • String toString(): returns object’s “state” as string; perhaps print all instance variables’ values • void finalize(): used in garbage collection • Upside: Vectors store things as Object, so maximum polymorphic flexibility • since everything is an Object, Vectors can hold instances of any and every class • adding/removing anything from Vector is easy • Downside: Vectors only store Objects • can only use methods of class Object on references accessed from Vector • cannot do much useful with only methods like equals, toString, and finalize • lost most of functionality we were modeling • Question #2: How can we access objects in a Vector in a useful way?
Answer(s): Generics! • Generics allow us to write a class to hold instances of another class, without regard for what that class happens to be • Allows for maximum generality while still being able to have the compiler check types for us • This feature is new in Java 1.5 • Had to do some work before the introduction of generics… • Let’s take a look at how a Vector would use generics…
The Vector’s Methods Revisited • Java 1.5 requires the use of generics whenever we declare a variable of type Vector • Let’s make a Vector that can hold CookieFactorys private java.util.Vector<CookieFactory> _vector; // returns an object of type CookieFactory public ElementType elementAt(int index) // will only insert CookieFactorys public void add(int index, ElementType element) // we can add only CookieFactorys to this // vector public void addElement(ElementType element) // remove and return the CookieFactory at // index public ElementType remove(int index) // replaces the CookieFactory at index with // the CookieFactory element public ElementType set(int index, ElementType element) • Let’s see an example...
A Contrived Vector Example public class CookieFactoryFarm { private java.util.Vector<CookieFactory> _vector; public CookieFactoryFarm() { //initialize vector _vector = new Vector<CookieFactory>(); //add 5 CookieFactorys for(int i = 0; i < 5; i++){ _vector.addElement(new CookieFactory()); } } //returns a CookieFactory at a specific index public CookieFactory getFactory(int index){ return _vector.elementAt(index); } } _vector.addElement(new CookieFactory()) • Will work, but... _vector.addElement(new Integer()) • Won’t work. Parameter needs to be of type CookieFactory
Before Generics… • What did we do before Java had Generics? • The world was dark and cold • Had to explicitly cast everything we put in, or took out, of a Vector or other data structure • Led to easy mistakes • Impossible to write a generic container data structure that was type safe • Had existed in other programming languages for decades. Java was lagging behind…
Quick Mainline Example package SlideExamples.Mainline public class App { public App() { } public static void main(String[] argv) { System.out.println(argv[0]); System.out.println(argv[1]); } } • If we type this in a shell: java Demos.Mainline.App Hello World • We get output: Hello World • In this example, if we did not pass two or more parameters to the mainline, we’d get an ArrayIndexOutOfBoundsException! • Why? Because argv’s size is exactly equal to the number of parameters passed to the mainline! • You won’t need to use mainline parameters right now, but we wanted you to know they existed!