====== Objects in Methods, Objects as Class Fields, Arrays of Objects ====== ---- ===== Objects in Methods ===== * We will examine the topic of methods that return objects, and also objects passed to methods as input parameters. * We will design and implement a //Fraction// class, ... * ... and then we will write methods to add & subtract two //Fraction// objects. * This is the way we want to be able to work with //Fraction// class objects: // Construct one fraction and print it Fraction f1; f1 = new Fraction(2, 3); System.out.println(f1); // Add two Fraction objects to get a sum Fraction object Fraction f2; f2 = new Fraction(1, 6); Fraction f3; f3 = addFraction(f1, f2); System.out.println(f1 + " + " + f2 + " = " + f3); * In the code above, we use an //addFraction// method that takes two //Fraction// objects (f1, f2) as input and returns a //Fraction// object that we can assign to another //Fraction// object (f3). * The output of the above //System.out.println()// is: 2/3 + 1/6 = 5/6 * Notice that 5/6 is a reduced fraction, meaning that somewhere in the //Fraction// class, there needs to be some kind of //reduce()// method, so the reduced form of a fraction is stored in the class. * The //addFraction// method is shown below. * In order to return a //Fraction// object, the //addFraction// method needs to call the //Fraction// constructor with the numerator and denominator of the //Fraction// that is the sum of //Fractions// one and two (last few lines of the code below): public static Fraction addFraction( Fraction one, Fraction two ) { // Compute common denominator: int dd = one.getDenominator() * two.getDenominator(); // Cross multiply and add: int nn = one.getNumerator() * two.getDenominator() + two.getNumerator() * one.getDenominator(); Fraction sum = new Fraction( nn, dd ); return sum; // // or skip using a sum variable by doing this: //return new Fraction( nn, dd ); } * The //subtractFraction// method is not substantially different from //addFraction//. ---- ===== Objects as Class Fields ===== * We will examine the topic of using an object of one class as a field in a different, but related class. * Objects in the real world are often composed of smaller related objects, for example, an account holder object within a bank account object... * We will design and implement an //AccountHolder// class, ... * ... and then we will use an //AccountHolder// class object as a field in a //BankAccount// class. * ... and then we will test the //BankAccount// class in a program. * Here are the relevant sections of the //AccountHolder// class. public class AccountHolder { private String firstName; private String lastName; private int age; // Constructors: /** * Constructor #1 * @param first name * @param last name * @param age */ public AccountHolder( String fn, String ln, int ag ) { firstName = fn; lastName = ln; age = ag; } /* * Constructor #2 (default) */ public AccountHolder() { } // Methods: // Write get and set methods for firstName, lastName, age below. ... } // end class * The //BankAccount// class will use an //AccountHolder// object to represent an account holder: public class BankAccount { private int acctnum; private double balance; private AccountHolder customer; ... ... } // end class * The //BankAccount// constructor will look like this: /** * Constructor#1 for objects of class BankAccount * @param acct * @param bal * @param firstname of customer * @param lastname of customer * @param age of customer */ public BankAccount( int acct, double bal, String firstname, String lastname, int age ) { // Write code to set account number, balance and customer name and age: acctNum = acct; balance = bal; // Since customer is an object, initializing it requires calling a constructor; // Use last 3 input parameters to construct the customer object. customer = new AccountHolder( firstname, lastname, age ); } * When a BankAccount object is constructed using the above constructor, a customer object will also be constructed. (Code in main() method of TestBankAccount.java) BankAccount myAccount; myAccount = new BankAccount( 1, 8000.00, "Joe", "Chung", 56 ); // The last 3 constructor arguments, "Joe", "Chung", and 56 will // be passed to the AccountHolder constructor to construct a // customer object within the myAccount object. ==== Working with objects as instance variables ==== * If a class has an object instance variable, the accessor methods (get/set methods) may have to be written and used a bit differently. * A BankAccount method to return the customer object's information might look like this: /** * Get method for customer's information * @return info */ public String getCustomerInfo() { // Use get methods defined in the AccountHolder class: String info = "Name:\t" + customer.getFirstName() + " " + customer.getLastName() + "\n" + "Birthday:\t" + costomer.getBirthDay() + "\n" + "Age:\t" + customer.getAge() + "\n" +; return info; } * A BankAccount method can be written to return the actual customer object like this: /** * Get method for customer * @return customer, an AccountHolder object */ public AccountHolder getCustomer() { return customer; } * The getCustomer method can then be used to access customer information using customer get methods. * This requires an additional dot (.) to be used to access AccountHolder methods. (Code in main() method of TestBankAccount.java) // Get bankaccount holder's first name only: System.out.println("Account holder's first name: " + myAccount.getCustomer().getFirstName()); // myAccount.getCustomer() returns the customer object that's in the myAccount object, and then // .getFirstName() gets the customer object's firstname. ---- ===== Arrays of Objects ===== * We will examine the topic of arrays that contain objects. * The arrays we have looked at before were arrays of simple, primitive types, such as //int// or //double//. * We have used an array of Strings in the //MagicEightBall// class example. * While Strings are objects in Java, they are "special," i.e., don't require constructors to create Strings. * We will design and implement a //Cat// class, ... * ... and then we will use an array of //Cat// class objects as a field in a //PetStore// class. * A //PetStore// represents a collection of //Cats// (and other animals). * Here is the simple //Cat// class. public class Cat { // instance variable private String _name; /** * constructor #1 * @param name */ public Cat(String name) { _name = name; } // methods /** * Get method for _name * @return _name */ public String getName() { return _name; } } // end class * The //PetStore// class will have an array of Cats as an instance variable, public class PetStore { // instance variables // array of Cats private Cat [] cats; private final int MAXCATS = 15; ... * The //PetStore// class constructor will need to "dimension" (set the length of) the array with the //MAXCATS// constant, public PetStore() { // construct array of cats cats = new Cat[MAXCATS]; } * Every element of the //cats// array currently contains //null// as a value, by default. * Every element of an int (or double) array would contain 0 (or 0.0) by default. * Every element of a boolean array would contain //false// by default. * Every element of an array of objects contains //null// by default. * To add //Cat// objects to the //cats// array, we need to construct //Cat// objects and then assign the objects to the array elements. * We can do this in a //addCats// method, public void addCats() { // Add a new Cat using a Cat variable, c1 Cat c1 = new Cat("Miu"); cats[0] = c1; ... // Add a new Cat without using a Cat variable cats[3] = new Cat("Skitty"); ... } * If we added //Cat// objects to the first 4 elements of the //cat// array, the remaining elements of the array would still contain the value //null//. * As with any array, the //cats// array is restricted to only //Cat// type objects. * We would not be able to add //Dog// class objects to the //cats// array. * To access a //Cat// object as an array element, we need to use normal array syntax, i.e., array[index]. * For example, to print the name of the 4th //Cat// object in the //cats// array, we would need to write, // Must call Cat object's getName method System.out.println(cats[3].getName()); ---- ===== The ArrayList Class ===== * We will examine the //ArrayList// Class and its advantages over standard Arrays. ==== java.util.ArrayList ==== * allows for "expandable" arrays * An ArrayList has these characteristics: * An ArrayList automatically expands as data is added. * An ArrayList has methods for inserting, deleting, and searching. * An ArrayList can be traversed using a foreach loop, iterators, or indexes. ==== Arrays or ArrayList? ==== * Programmers are frequently faced with the choice of using a simple array or an ArrayList. * If the data has a known number of elements or small fixed size upper bound, or where efficiency in using **primitive types** is important, arrays are often the best choice. * However, many data storage problems are not that simple, and ArrayList (or one of the other [[http://download.oracle.com/javase/6/docs/technotes/guides/collections/index.html|Java Collections]] classes) might be the right choice. ==== Automatic expansion ==== * Use ArrayList when there will be a large variation in the amount of data that you would put into an array. * Arrays should ideally be used only when there is a constant amount of data. * For example, storing information about the days of the week should use an array because the number of days in a week is constant. * Use an ArrayList for your email contact list because there is no upper bound on the number of contacts. ==== Objects only ==== * A possible disadvantage of ArrayList is that it holds only object types and not primitive types (e.g., int, double, character). * To use a primitive type in an ArrayList, put it inside an object or use of the wrapper classes (eg, Integer, Double, Character, ...). * The wrapper classes are immutable, so if you use, eg, Integer, you will not be able to change the integer value. ==== Common ArrayList methods and constructors ==== * Here are some of the most useful ArrayList methods. * Note that E is the notation for the type of an element in a collection such as in an ArrayList. * Constructors: new ArrayList() Creates ArrayList of Class E objects with initial default capacity of 10. new ArrayList(cap) Creates ArrayList with initial int capacity cap. * Adding elements: a.add(e) adds element e to the end of ArrayList a a.add(i, e) Inserts e at index i, shifting elements up as necessary. * Replacing an element: a.set(i,e) Sets the element at index i to e. * Getting the elements: a.get(i) Returns the object at index i. a.toArray() Returns elements in a as an array of objects. * Removing elements: a.clear() Removes all elements from ArrayList a a.remove(i) Removes the element at position i. a.removeRange(i, j) Removes the elements from positions i thru j. * Other: a.size() Returns the number of elements in ArrayList a. ==== Adding elements to the end of an ArrayList, getting them by index ==== ArrayList a = new ArrayList(); // Construct default size ArrayList a E s = new E(); // Construct s object of Class E. . . . a.add(s); // Add object s to the end of the ArrayList a . . . s = a.get(i); // Assigns i-th element from a to object s. ==== To get successive elements from an ArrayList ==== * 1. Use special "foreach" loop. * This is fast and works for all kinds of lists, but is not entirely flexible (can only go sequentially forward with no deletions, additions, or multiple references). * foreach loops should be the first choice for ArrayLists ArrayList a = new ArrayList(); . . . for ( String s : a ) { System.out.println( s ); } * 2. Use standard //for// loop with index. * This is fast. * It does allow orders other than sequentially forward by one. // Assume a is an ArrayList: for ( int i = 0; i < a.size(); i++ ) { System.out.println( a.get( i ) ); } ==== Sorting ==== * If the data in your ArrayList has a natural sorting order you can simply call the static //Collections.sort()// method. Collections.sort(yourArrayList); * Example: sort words in an ArrayList: // Purpose: An exercise using Scanner, ArrayList, and // Collections.sort. Read words, sort them, print // them. import java.util.Scanner; import java.util.ArrayList; import java.util.Collections; // for sorting method public class Alphabetize { public static void main(String[] args) { //... Declare variables. Scanner in = new Scanner(System.in); ArrayList words = new ArrayList(); //... Read input one word at a time. System.out.println("Enter words. End with EOF (ex. CTRL-Z then Enter, or CTRL-D)"); //... Read input one word at a time, adding it to an array list. while (in.hasNext()) { words.add(in.next()); } //... Sort the words. Collections.sort(words); //... Print the sorted list. System.out.println("\n\nSorted words\n"); // foreach loop: for (String word : words) { System.out.println(word); } } // end main } // end class ----