EECS2030 Sample Test 2


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * A utility class for Test 2.
 * 
 * @author EECS2030
 * 
 */
public class Test2D {

	private Test2D() {}
	
	/**
	 * Returns the string at the end of the list t
	 * 
	 * @param t
	 *            a list
	 * @pre. t.size() > 0
	 * @return the string at the end of t
	 */
	public static String last(List<String> t) {
		return t.get(t.size() - 1);
	}

	/**
	 * Returns the second last string in the list t
	 * 
	 * @param t
	 *            a list
	 * @return the second last string in t
	 * @throws IllegalArgumentException
	 *             if the length of the list is less than 2
	 */
	public static String secondLast(List<String> t) {
		if (t.size() < 2) {
			throw new IllegalArgumentException("list must have length of 2");
		}
		return t.get(t.size() - 2);
	}

	/**
	 * Returns the string formed by concatenating all of the strings contained
	 * in the list t. The strings are concatenated sequentially starting from
	 * the first string in the list and ending with the last string in the list.
	 * For example, if t is the list:
	 * 
	 * <p>
	 * ["he", "ll", "o"]
	 * 
	 * <p>
	 * then the resulting string is "hello"
	 * 
	 * @param t
	 *            a list of strings to concatenate
	 * @return the concatenation of the strings in t
	 */
	public static String concat(List<String> t) {
		StringBuilder b = new StringBuilder();
		for (String s : t) {
			b.append(s);
		}
		return b.toString();
	}


	/**
	 * Sorts a list of strings by their length (shortest first). Strings with
	 * the same length are sorted in dictionary order. For example, if the list
	 * t is:
	 * 
	 * ["abstract", "boolean", "char", "code", "for"]
	 * 
	 * then t is modified so that it becomes:
	 * 
	 * ["for", "char", "code", "boolean", "abstract"]
	 * 
	 * @param t
	 *            the list to sort
	 */
	public static void sortByLength(List<String> t) {
		Map<Integer, List<String>> lengths = new TreeMap<Integer, List<String>>();
		for (String s : t) {
			int sLen = s.length();
			List<String> u = lengths.get(sLen);
			if (u == null) {
				u = new ArrayList<String>();
				lengths.put(sLen, u);
			}
			u.add(s);
		}
		t.clear();
		for (List<String> u : lengths.values()) {
			Collections.sort(u);
			t.addAll(u);
		}
	}

}

Multiple choice question

Question 1

Inside of a constructor, the keyword this refers to what?

A. the class of the object being constructed
B. the fields of the object being constructed
C. the object being constructed
D. the memory location of the client's variable that refers to the new object

Question 2

Suppose that two Student objects are considered equal if their student numbers are equal; in the Student implementation, the student number is stored as a String, and student numbers are guaranteed to not be null.

The implementation of the Student class looks like:

public class Student {
  private String studentNumber;
  
  public Student(long number) {
    this.studentNumber = new String(Long.toString(number));
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (this.getClass() != obj.getClass()) {
      return false;
    }
    Student other = (Student) obj;
    return this.studentNumber == other.studentNumber;
  }
  
  // hashCode not shown, but guaranteed to be correct
}

What does the following client code output?

Student s = new Student(123);
Student t = new Student(123);
System.out.println(s.equals(t));

Type your answer here: false

Question 3

You were taught that if you override equals in a class, then you must also override hashCode. Is it also true that if you override hashCode then you must also override equals?

You must explain your answer; simply stating yes or no will not be considered as an answer.


No. The contract for hashCode states that objects that are equal must return the same hash code (i.e., hashCode depends on equals). The contract for equals has no dependency on the result of hashCode.