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 Q & A for the latter.) If you have a Java language question not easily answered by a Java reference, please look here! As with the Assignment Q & A section, you may also want to refer to this page occasionally to be warned about potentially confusing issues in advance.
Contents:
staticMeth()
:
SuperFoo myFoo = new Foo(); myFoo.staticMeth();Because static method calls are resolved by compile-time type, in this case,
SuperFoo
's implementation of staticMeth()
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〉.
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:
sicp-19>rhlee~/cse331% 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 ----cb() ----return \ / my code ----returnBut it is more customary to draw it like this:
my code ----foo(x) ----return ----> \ / \ / library code ----cb() ----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 &mdash it invokes hashCode()
and equals()
in my code — returning.
new
keyword and with specifying the array size in brackets:
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, I suppose, any non-final class if you're okay 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 (I believe, I don't have access to my copy of The Pragmatic Programmer at the moment). 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 compareTo(T other). In the case of getBallsFromSmallest(), you would make a new class called something like BallSorter that implements Comparator<T>, and just use a regular compareTo() method like you would 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 compareTo() method.
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 basically throwaway class that contains only a single method, use Comparable<T>. If you can't or shouldn't edit the class (such as with Ball), use a Comparator<T> and pass it to your data structure when you construct it.
Back to the CSE 331 handouts home page.