CS61B: Frequently Asked Questions (FAQ)
Questions
Administrative Questions
-
How are labs and homeworks graded? How do they contribute to the overall
grade?
-
Are there lab and homework solutions?
-
How do I change my password, or the name listed in
emails for my account?
Submission Issues
-
When I try to submit, I get an error that "the current directory does not appear to be an assignment directory."
-
When I try to compile project 0, I'm getting a cannot find symbol error that has to do with the CommandArgs class.
Input/Output
-
What are the "standard output" and the "standard error"?
-
What is the "standard input", and what exactly does it mean to reach an "end-of-file" on it?
-
I have some compiled Java code in a JAR file. How do I get Java to
load it?
-
What are nested classes all about?
Java Language Issues
-
Can nested classes use "this"? If so, what does it refer to?
-
Can an enclosing class access the private methods/variables of its
nested classes?
-
When several methods have the same name, how does Java select which
is called?
-
When I compare two strings with "==", I get unexpected results. Why?
-
What are these unchecked/unsafe operations that the compiler warns me
about? Should I worry about them?
Patterns
-
When I read the input \\(hello\\)
from the terminal into a String variable
and then use it as a Pattern, it does not match the String
"(hello)"
.
Why not?
Answers
Administrative Questions
Q: How are labs and homeworks graded? How do they contribute to the overall
grade?
A:
Please see the first-day informational handout, which is also available on
web page.
Q: Are there lab and homework solutions?
A:
Yes, we will post them sometime after the due date.
Q: How do I change my password, or the name listed in
emails for my account?
A:
From your Unix account, log in to update server on an xterm window using
ssh update
. The name officially listed for your account is
under the "Change your Cecos" entry.
Submission Issues
Q: When I try to submit, I get an error that "the current directory does not appear to be an assignment directory."
A:
This means that the directory that you're working in a directory that was not created by the hw init or hw checkout commands. You should use hw checkout to get a new folder that
was created by these commands, and then copy your files into this new directory.
Q: When I try to compile project 0, I'm getting a cannot find symbol error that has to do with the CommandArgs class.
A:
You have an out of date copy of the cs61b-software folder. Use the
rsync -a LOGIN@torus.cs.berkeley.edu:~cs61b/cs61b-software $HOME command to update your software.
Input/Output
Q: What are the "standard output" and the "standard error"?
A:
Unix supplies programs with two
streams of
output to which they can write text. These are called the
standard
output, which is intended for normal output,
and the
standard error, which is intended for error,
warning, or logging messages. You should observe this convention in your
own programs, writing error messages to
System.err.
From the point of view of a program, these streams
look like ordinary output files. Various programming languages provide
different notations and library calls to refer to them. In Java programs, the
standard output appears as the variable System.out and the standard
error as System.err. Anything written to these (by, say, the
printf method) comes out on the respective stream.
By default, both streams
go to the terminal (or "console"). Unix shells provide
various ways of directing
them instead into separate files. Unfortunately, the various
shells are inconsistent in how to do this. To run a command FOO (e.g.,
java solve test1.in), and send the output and error to various
destinations:
Desired effect | csh-like shell | bash-like shell |
Std. output -> blah
Std. error -> terminal
|
FOO > blah | FOO > blah |
Std. output -> blah
Std. error -> blah
|
FOO >& blah | FOO > blah 2>&1 |
Std. output -> blah1
Std. error -> blah2
|
(FOO > blah1) >& blah2 |
FOO > blah1 2> blah2 |
You can also redirect the output of FOO to be the input of another command,
BAR:
Desired effect | csh-like shell | bash-like shell |
Std. output -> BAR
Std. error -> terminal
|
FOO | BAR | FOO | BAR |
Std. output -> BAR
Std. error -> BAR
|
FOO |& BAR | FOO 2>&1 | BAR |
Std. output -> BAR1
Std. error -> BAR2
|
(FOO | BAR1) |& BAR2 |
(FOO | BAR1) 2&>1 | BAR2 |
We use all this in the autograder to separate or combine the output and error
streams, as needed.
Q: What is the "standard input", and what exactly does it mean to reach an "end-of-file" on it?
A:
There seems to be vast confusion about end-of-file in general.
The confusion
arises from the fact that people have formed an inseparable link in their
minds between keyboard input, the "standard input", and System.in (and are
unfamiliar with how to make keyboard input "end"). So here's a brief
tutorial:
- Analogous to what happens with standard output, all Unix programs are
supplied with a standard stream of text input called the standard input.
- There are no necessary connections between keyboard input,
the standard input, and System.in except that by default,
the standard
input comes from the keyboard and System.in is by default
the Java
"handle" by which programs access the standard input.
- One can obtain the standard input from sources other than the keyboard
in Unix by using input redirection or pipes:
- The command line
java foo < SOMEFILE
runs foo but takes the standard input from SOMEFILE (a file name) rather
than the keyboard. This works for any command, not just 'java'.
- The command line
SOMECOMMAND | java foo
runs SOMECOMMAND (any command) and java foo, taking the standard output
from SOMECOMMAND and using it as the standard input for java foo.
- Although System.in by default gives a program access to the standard input
to the program, you can change this with
System.setIn (SOMEINPUTSTREAM)
where SOMEINPUTSTREAM can be any Java expression that yields
an InputStream, such as
new FileInputStream (SOMEFILENAME)
or
new StringBufferInputStream (SOMESTRING)
- You can, in fact, get end-of-file on keyboard input. On our system by
default, the character ^D (Control-D) signals the shell that it should
send end-of-file to whatever program is reading from the terminal (the
^D is never transmitted). However, you almost never want to do this.
In general, your test input really ought to come from files, so that you
aren't constantly retyping it.
Q: I have some compiled Java code in a JAR file. How do I get Java to
load it?
A:
All classes loaded by a running Java program come from one of the locations
indicated by the
class path, which is a list of directories and
JAR (Jave ARchive) files. JAR files, in effect, are directories full of files
all collected into a single ordinary file in such a way that the original
constituent files are easily found and extracted.
The Java runtime system looks for a class
bar in package foo by looking at each item in the class path in turn. If
the classpath item is a directory,
D, then Java looks for a
file
D/foo/bar.class
(reverse the slashes on Windows). If the item is a JAR file, Java treats it
as a directory and again finds the desired class file (foo/bar.class) in it.
Typically, the current directory will be part of the classpath, although it
need not be.
Eclipse provides a "Java build path" window under Project->Properties. The
Libraries tab on that window will give you an "Add External Jar" selection.
In plain UNIX, you add the Jar file to the CLASSPATH environment variable,
which is a list of files separated by colons.
Q: What are nested classes all about?
A:
Nested classes are "members" of the enclosing class, just as are
instance variables, constructors, and methods. They may be public,
private, protected, or package private (default). The meaning of
public, protected, etc., is exactly the same for classes as it is for
instance variables and methods: it determines where else in the program
you may mention the name of the member.
Static nested classes are just plain classes, like non-nested ones. The
only thing that distinguishes them is where their names can be mentioned,
and how they are referred to (class Nested inside class Enclosing is called
Enclosing.Nested).
Non-static (inner) nested classes are plain classes with one extra implicit
field.
For inner class Inner in enclosing class Enclosing, if E is an Enclosing,
then new E.Inner (...) is a pointer to a new object of type Enclosing.Inner
that has a private instance variable field called Enclosing.this, whose
value is E. So, given
class Enclosing {
String myName;
Enclosing (String name) { myName = name; }
public String toString () {
return "Enclosing named " + myName;
}
Inner makeInner (String id) {
return this.new Inner (id);
// OR return new Inner (id) for short ('this.' implied)
}
class Inner {
String innerName;
Inner (String name) { innerName = name; }
public String toString () {
return "Inner named " + innerName + " connected to "
+ Enclosing.this;
}
}
}
we could write (in some method somewhere):
Enclosing e = new Enclosing ("Tom");
Enclosing.Inner i1 = e.makeInner ("Dick");
Enclosing.Inner i2 = e.new Inner ("Harry");
System.out.printf ("e = %s%ni1 = %s%ni2 = %s%n", e, i1, i2);
and see printed
Enclosing named Tom
Inner named Dick connected to Enclosing named Tom
Inner named Harry connected to Enclosing named Tom
Java Language Issues
Q: Can nested classes use "this"? If so, what does it refer to?
A:
Nested classes are just classes, and
this means the same thing in them
as it does in other classes: it applies in instance methods and refers
to the "thing to the left of the dot" in the call. That's why we have
the odd syntax "Enclosing.this" for use in inner classes to distinguish
the "this's". To make life confusing, Java will "helpfully" figure out
places where you "must have meant Enclosing.this" and supply it for you.
So if in an instance method of Inner, above, you had written
makeInner ("Jack")
the Java compiler would assume that you must have meant to write
Enclosing.this.makeInner ("Jack");
Q: Can an enclosing class access the private methods/variables of its
nested classes?
A:
Yes. The rule on private is "can only be used within the top-level
class containing its declaration," which must be (or include) the
enclosing class.
Q: When several methods have the same name, how does Java select which
is called?
A:
In general, Java uses lexical scoping, just like Scheme. That is, a
use of an unqualified simple name (i.e., an identifier that is not
preceded by '.') may refer to any declaration that's in a
declarative
region (a class or interface declaration, a {...} block, a method,
a
for statement, a
catch clause, the source file, the package) that
contains that use. In addition, package names in the anonymous package,
classes and interfaces in the package
java.lang,
and imported classes and
interfaces can sort of be thought of as being in declarative regions
that contain the use.
For qualified names, SOMETHING.x, we look for 'x' only within SOMETHING
(which may be a package, class, or instance).
For this purpose, we count inherited declarations as being in the class or
interface that inherits them.
So far, these rules will in general pick out several possible declarations,
as in the following completely legal declarations:
class A {
// a
A A;
// 1 b
A A (A A) { return A; }
// 2 c 3 d 4
A () { }
// e
}
class B extends A {
// f
void A () {
// g
A A = A (new A ().A);
// 7 h 8 9 10
}
}
Here, I have marked each use of A with a numeral and each definition with a
lower-case letter.
Initially, use #8 might refer to the declarations a (same file); b, c,
or e (inherited by class B), g, or h. First, however, we apply
syntactic context: use #8 must refer to a method, because it is part
of a method call. Therefore, it refers either to declaration c or g.
Overloaded methods are disambiguated by means of the argument list, so
#8 must refer to c.
Or consider #9. By context, it must refer to a class, which means
declaration a, and a constructor within that class, which can only be
e.
Since the thing to the left of the dot preceding #10 is an A, #10 must
refer to either declaration b, c, or e. Since it is not a method call
or constructor invocation, it must refer to b.
Sometimes, these considerations of context or argument lists are not
sufficient, as in use #4, which might refer to either b or d. In this
case, we defer to the INNERMOST declarative region, which in this case
is the method containing use #4. That is #4 refers to d.
Staticness has nothing whatever to do with any of this analysis. Neither
does access level (public, private, etc.), with the exception that
private declarations are not visible outside their package, which may
cut down on the set of possible candidate declarations. (Other access
levels, such as default (package private) don't hide declarations;
instead you get errors about trying to access non-public things from
outside the package. I consider this a small but annoying
inconsistency in Java).
Therefore, runtime selection of instance methods by dynamic type is a
separate mechanism, and does not participate in determining which
declaration the compiler applies to some use. It is only when the
program is run that the system actually selects which method to call.
It will always be one that has the same signature as the one the
compiler selected.
Q: When I compare two strings with "==", I get unexpected results. Why?
A:
The == operator always compares
values for equality.
Since the value of
a String expression is a
pointer to a String object,
this means that ==
compares
pointers, not the contents (character sequences)
contained in the
objects pointed to. You can construct the same contents two different ways,
and get two different objects with the same contents. E.g.,
x = "Hello, ";
"Hello, world" != x + "world"
This is semantically consistent, but admittedly confusing. Use the
.equals method instead:
"Hello, world".equals (x + "world")
Q: What are these unchecked/unsafe operations that the compiler warns me
about? Should I worry about them?
A:
Yes, you should worry. As a general rule, you should treat almost all
compiler warnings as if they were errors, because they
might
be errors. Warnings such as
Note: foo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
in particular mean that you have a construct that cannot be checked until
execution time, whereas it is usually checkable at compilation time if the
program is written correctly. If you do this:
ArrayList foo = ...
instead of
ArrayList<String> foo =
for example, you'll get a warning. You should correct all of these (our
pretests often require it, for example).
In almost all cases, you can correct them
without a problem. For this project, you are likely to find a couple of
instances in which you run into a limitation of Java and will have to
use the
@SuppressWarnings ("unchecked")
annotation before a method or constructor. In my project #2, I had two
on small methods. If you
have any more than that, or if you have to attach it to an entire class,
you are probably doing something wrong.
The messages ask you to run javac like this:
javac -Xlint:unchecked foo.java
as our Makefiles are set up to do. This will give you more details.
In Eclipse, you should eliminate all the
little yellow warning flags.
Patterns
Q: When I read the input \\(hello\\)
from the terminal into a String variable
and then use it as a Pattern, it does not match the String
"(hello)"
.
Why not?
A:
[Kyle Wecker]
The problem here is the difference between the way characters are represented
inside a .java file and the way they are recognized through streams (e.g.,
stdin). When you are typing into a string in a .java file, in order to show
that you mean '\', you must type "\\". The reason for this is that backslash is
an escape character that isalso used to signal a few other characters
(like '\n').
Characters in a stream or reader, on the other hand, are read
verbatim, without escape sequences. So backslash is just backslash, and
two backslashes are just two backslashes. So, your example is really
equivalent to the Java test "(hello)".matches ("\\\\(hello\\\\)")
,
which is indeed false. The argument to .matches
here, coming
from a String literal, contains the characters backslash, backslash,
left parenthesis, etc.—each pair of backslashes in the literal encodes a
single backslash in the resulting String.
To make the confusion worse, backslashes have special significance in
Patterns, too. So the Pattern consisting of two backslashes could
be input from
a file as two backslashes or else written as a String literal with four
backslashes, and is interpreted by the Pattern class as matching ONE
backslash!