CS61B: Frequently Asked Questions (FAQ)

Questions

Administrative Questions

  1. How are labs and homeworks graded? How do they contribute to the overall grade?
  2. Are there lab and homework solutions?
  3. How do I change my password, or the name listed in emails for my account?

Input/Output

  1. What are the "standard output" and the "standard error"?
  2. What is the "standard input", and what exactly does it mean to reach an "end-of-file" on it?
  3. I have some compiled Java code in a JAR file. How do I get Java to load it?
  4. What are nested classes all about?

Java Language Issues

  1. Can nested classes use "this"? If so, what does it refer to?
  2. Can an enclosing class access the private methods/variables of its nested classes?
  3. When several methods have the same name, how does Java select which is called?
  4. When I compare two strings with "==", I get unexpected results. Why?
  5. What are these unchecked/unsafe operations that the compiler warns me about? Should I worry about them?

Patterns

  1. 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.


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:
  1. Analogous to what happens with standard output, all Unix programs are supplied with a standard stream of text input called the standard input.
  2. 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.
  3. One can obtain the standard input from sources other than the keyboard in Unix by using input redirection or pipes:
    1. 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'.
    2. 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.
  4. 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)
    
  5. 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!