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 Problem Set 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 Problem Set Q & A section, you may also want to refer to this page occasionally to be warned about potentially confusing issues in advance.
Contents:
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.
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.
cannot resolve symbol symbol: constructor Route () location: class ps2.Route public ElementaryRoute(GeoSegment gs) { ^
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 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 Languge Spec has to say about arrays, and speak with a TA if you're still confused.
java.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
runtime type is allocated for this purpose. Because we pass in the
array with that was created with the correct runtime 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);
(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 trys to prevent collisions, mapping different keys to different hash codes whenever possible.
The basic tenets of hash tables:
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 nuiance 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 precusory primer to hash tables. If you would like to know more about them, please speak with your TA.