This handout will list frequently encountered questions about the Java language. This page will focus on issues that fall between purely syntactic issues and deep conceptual issues. (Please see a Java reference for the former and your TA or the Assignment specification for the latter.) If you have a Java language question not easily answered by a Java reference, please look here! As with the Assignment specification, you may also want to refer to this page occasionally to be warned about potentially confusing issues in advance.
Contents:
staticMethod()
:
SuperFoo myFoo = new Foo(); myFoo.staticMethod();Because static method calls are resolved by compile-time type, in this case,
SuperFoo
's
implementation of staticMethod()
will be invoked. This is because the compile-time
type of myFoo
is SuperFoo
. The lesson to be learned here is to always
invoke static methods by 〈Classname〉.〈method-name〉:
either calling SuperFoo.staticMethod()
or Foo.staticMethod()
, depending
on the desired behavior.
public class Test { public static int _myInt = 1; public static int foo() { return _myInt; } } public class Test2 extends Test { public static int foo() { _myInt++; return _myInt; } } public class TestDriver { public static void main(String args[]) { System.out.println(Test.foo()); System.out.println(Test2.foo()); System.out.println(Test.foo()); } }produces the following behavior:
> java TestDriver 1 2 2This is because the superclass and all of its subclasses share the same copy of all static members.
private
, public
,
etc.)A brief description of the different keywords:
public
- all classes are able to view this constructor/method/field.
protected
- only subclasses and other classes in the package are able to view
this constructor/method/field
private
- this constructor/method/field is not visible outside of this class.
The default access in java is "package visible (default-access)". This access level grants package-only access to the constructor/method/field.
You should always be careful to not expose more of your implementation than necessary, and you should always keep in mind the design trade-offs involved in using each level of visibility.
If you're still not sure about when each type of visibility is appropriate, please ask your TA.
super(...)
when instantiating a subclass.ElementaryRoute
(which is a subclass
of Route
). What does it mean? cannot resolve symbol symbol: constructor Route() location: class hw2.Route public ElementaryRoute(GeoSegment gs) { ^
super(...)
constructor (with or without arguments), or Java will implicitly call the zero-argument
constructor of your superclass. If no such constructor of the superclass exists, you will get a
compile-time error.
Keep in mind that if you do invoke super(...)
, it must be the first statement in
your subclass's constructor. Also, if you define a class but declare no constructors, an
implicit zero-argument constructor (which does nothing) is created for you. However, if you
declare any constructors, there is no implicit zero-argument constructor.
Foo()
constructor, why doesn't the statement
Foo(0);
work?
new
keyword. It's often useful to call another constructor to augment your current constructor, so
Java provides a special syntax: this(params);
. In the above example, you
would use the statement this(0);
. Note that calling of other constructors is also
restricted to the first line of your constructor.
import java.lang.Math
. Why is it that I still have to
type Math.random();
? Why doesn't using just random();
work?
import
statement merely makes it so you don't have to type out the full package path of a class. Indeed,
in this case, all java.lang.*
classes are imported by default, so the statement is
extraneous.
Suppose that my code calls a library routine, foo()
. Usually, the library code
executes until a return statement, and then control returns to my program.
Here is ASCII art of the flow of execution (time flows to the right). Where there is a line, code is executing. Where there is blank space, code is not executing.
my code -------foo(x) -------------> \ / library code -------returnThe library might call some other library, too:
my code ----foo(x) ----> \ / library code ---bar() ----return \ / other library ----returnA callback is when the library calls a function in *my* code, before finishing its work. We could draw it like this:
my code ----foo(x) ----> \ / library code ----bar() ----return \ / my code ----returnBut it is more customary to draw it like this:
my code ----foo(x) ----return ----> \ / \ / library code ----bar() ----returnTwo examples of callbacks are
hashCode()
and equals()
. When I define a
class, I define these methods, so they are my code. When I call HashMap.put
, the
implementation makes a callback — it invokes hashCode()
and
equals()
in my code — before returning.
new
keyword and with specifying the array size in brackets:
// These are equivalent declarations. Either placement of the '[]' works. Foo f[] = new Foo[20]; Foo[] f = new Foo[20];
The length of an array is stored in a public final
(read-only) field:
int size = f.length;
You cannot directly resize an array. In order to grow an array, you must create a new one of
the desired size and copy the old elements over. You can copy the elements with System.arraycopy()
.
An example:
Foo temp[] = f; // 'temp' now points to the old array. f = new Foo[f.length*2]; // Make f a new array that's twice as large. System.arraycopy(temp,0,f,0,temp.length); // Copy old values back over.
Please see what the Java Language Specification has to say about arrays, and speak with a TA if you're still confused.
toArray()
to populate a typed arrayjava.util.List
(Vector
, ArrayList
,
LinkedList
, etc.) that I know is populated by a bunch of Foo
objects. Is
there an easy way to get a Foo[]
array without stepping through the whole array and
casting?
java.util.List
interface defines a toArray(Object[])
method which takes as an argument, the array into which the elements of this list are to be
stored, if it is big enough; otherwise, a new array of the same run-time type is allocated for
this purpose. Because we pass in the array with that was created with the correct run-time type,
it is safe to cast the return value directly to the typed array.
For example:
//Vector fooVect is populated with Foo objects Foo[] fooList = new Foo[fooVect.size()]; fooList = (Foo[])fooVect.toArray(fooList);
String
class when working with strings.
(In Java, the hash code you generate can be any integer, but, based on the capacity of the hash table (which is maintained automatically), Java will take the modulo of your hash code to map it to an entry in the hash table.)
However, there is a many-to-one mapping from keys to hash codes, so knowing a hash code does not necessarily give you a single entry. Also, if many keys map to the same hash code, we'd have to search through all the keys associated with that hash code to find our desired entry; this would deny us our constant time search. (In the worst case, all keys might map to the same hash code, resulting in a simple list.) Thus, we want to try to write a hash function which tries to prevent collisions, mapping different keys to different hash codes whenever possible.
The basic tenets of hash tables:
.equals()
method to compare keys must
never change while that key is in use in a hash table. Otherwise, you will no longer be
able to find your entry. (For instance, if you use a Date
object as a key,
you must be sure not to modify it, or it will no longer correspond to the hash code under
which it's stored.)
.equals()
to each other) return the same hash code. This is so you
can always find your entry.
About good vs. bad hash functions: Let's say your key is an ordered pair, (x,y). A worst case hash function would always return, say, 1. A better hash function might return x+y. In that case, (1,4) and (2,3) would still hash to the same code. An even better hash function would be x+1123*y, which would reduce the number of probable collisions even more. (We multiply by a prime number so our efforts aren't negated when Java takes a modulo. There's a lot more nuance regarding hash functions that are beyond the scope of this Q & A.)
Hash tables are implemented via the HashMap
class. The older Hashtable
class is still around, but is slower, and you should use HashMap
for most
purposes.
Please see the spec for Object.hashCode()
,
which explains the restrictions for your implementation of hashCode()
. While
you're at it, please see the spec for Object.equals(Object)
,
which explains the restrictions for your implementation of equals()
. You must be
sure to implement equals()
correctly or your class will not work properly as a
hash table key.
This is a very precursory primer to hash tables. If you would like to know more about them, please speak with your TA.
A: In Java, we frequently come across situations where two Objects must be compared to each other, such as when needing to implement sorted data structures (just like in getBallsFromSmallest()). The Java standard library has two methods for automatically comparing Objects together in these data structures: Comparable<T> and Comparator<T> (in each case, T is the class that you want to compare). While these both achieve the same thing, they go about it different ways.
Comparable<T> is an interface that you can add to any class you have edit access to (or, more accurately, any non-final class if you're ok with inheritance). The Comparable<T> interface adds a single method, compareTo(), which each of your instantiations of T gets. Whenever one of your Ts gets added to a sorted collection<T>, its compareTo() method is called against all other Ts it is compared against.
Good times to use Comparable<T> are when your class must always compare against itself the same way, or you don't want to define an entirely new class just to run comparisons. However, it does require editing the original T class, which is not always possible (or, with the case of Ball, recommended). In those cases, a Comparator<T> must be used.
The Comparator<T> interface is an interface designed to create a type of class called a function object. Function objects are a trick of using interfaces to basically gain some degree of first order functions (a function that can be passed as an argument).
So that's what a Comparator<T> is. How do you implement it? Unlike Comparable<T>,
when you use Comparator<T> you make an entirely new class, containing only the method
compare(T first, T second)
, which works just like compareTo
works.
In the case of getBallsFromSmallest()
, you would make a new class called
something like BallSorter
that implements Comparator<T>, and just use a
regular compare()
method like you would use compareTo
if you were
using Comparable<T>. Then, when you construct a sorted data structure, you can simply
pass the Comparator<T>
in the constructor and the data structure will use that class's compare()
method
to perform comparisons.
Of these two ways of comparing objects, which is the best? If you have edit access to the class and don't want to go through the hassle of creating a one-time-use class that contains only a single method, use Comparable<T>. If you can't or shouldn't edit the class (such as with Ball), or there are multiple meanings of "comparison" that are all valid and applicable at different times, use a Comparator<T> and pass it to your data structure when you construct it.