Contents:
6.170 is a class where you will learn to design and implement software systems. In this recitation we will review Java syntax and object oriented programming concepts. By the end of this recitation you should be familiar with Java syntax and writing specifications. The material covered in this recitation should help you with the first two problem sets.
In lecture we got a glimpse of object oriented programming. Now we need to introduce more Java syntax which you will be using for the rest of the term.
Take a look at the provided code: ComplexNumber.java and ComplexNumberMain.java. This is the code we will be dissecting in this recitation.
A Java program is made up of 1 or more classes. The complex number example has two. One is used to interface to the command line, and the other defines the complex number class. Each class has its own .java file, with the same name. For example, ComplexNumber.java contains the definition for the class ComplexNumber.
Each Java file has one class declaration. This includes the visibility of the class, the keyword class, the name of the class, possibly the classes and interfaces it extends or implements (none in this case), and the body of the class enclosed in curly braces. The class ComplexNumber is defined like this:
public class ComplexNumber {
// Fields go here
// Constructors go here
// Methods go here
}
At the top of the class's body are field declarations followed by constructors, then methods.
There are some Java keywords in ComplexNumber.java:
In this course we will also use the following notations when we talk about program structures:
Fields are where data is stored for each class. Fields may be public or private. Generally, it is good practice to make all of your fields private, except in special cases. In ComplexNumber there are two private fields, real and img. Fields can also be either static or not (non-static is the default). Just like static methods, static fields can be accessed without creating an instance of the class.
private double real; private double img;
ComplexNumber a = new ComplexNumber(1,1); ComplexNumber b = new ComplexNumber(2,2); double absValue = ComplexNumber.abs(); ComplexNumber sum = ComplexNumber.add(a, b);
A method body is made up of statements. These include method calls, assignments, and flow control. HelloWorld (the full text of which is shown below) has an example of a statement which is a method call. Many statements end in a semicolon. Assignments look like id = expr;. Here expr may be any expression. An expression may be a method call, a variable, or any combination of these with the operators.
A constructor is the piece of code which is executed to create a new instance of a class. In the ComplexNumber example there is one constructor:
public ComplexNumber(double realPart, double imgPart) {
this.real = realPart;
this.img = imgPart;
}
A constructor looks very much like a method declaration, except that the function name is the name of the class, and does not have a return type. It is worth noting here the use of the java keyword this. this is simply used to make explicit that we want to modify something in the instance that is currently executing.
A method declaration defines a new method for a class. In Java all methods are associated with a class. A method takes zero or more arguments and returns a single result. The abs method in the ComplexNumber class is an example:
public double abs() {
return Math.sqrt(real*real + img*img);
}
In this example, the first identifier is the visibility. In this case, abs() is a public method. The second identifier is the return type. This is the type of the value returned by the method. In this case, abs() returns a value of type double. A method can return only one type of value. However, it is also possible for a method to return no value at all. In this case, the keyword void is used in place of the return type. Next is the method name, in this case abs. Then, inside the parenthesis, are the input parameters with their types. In this case, there are no inputs to the method (for a better example, look at the static method add(...) in ComplexNumber). Finally is and open curly brace followed by the method body. In functions which have a non-void return type, there must be a return statement in the body. There may be many return statements, and they may be anywhere in the body, even in deeply nested loop structures.
The method body here is just one line. The expression following return is to be evaluated as the return value of the method. Math is the name of a class in java.lang; it is followed by a dot. This operator is used to select a method or a field from the object on its left. Math.sqrt refers to the square root method of the Math class (which is a static method).
This is the first thing everyone learns in a new language, and it covers some important constructs in Java.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Note: instead of public static void main(String[] args), it is also legal to use public static void main(String args[]). If you don't understand this distinction, don't worry about it for right now. Just use it as a black box.
You are already familiar with class and method declarations, but there are a few new things here too. You will notice that there are three identifiers before the method name here. The keywords public and static are prepended to the method declaration. Their meanings we mentioned earlier. This particular method declaration is the method which is always called when this class is invoked. System is the name of a class, and System.out refers to the out field of the System class. System.out.println refers to the println method of that field. This method is then passed the parameter "Hello, World!".
It is likely that you will encounter some bugs in your code. Java uses exceptions to handle any abnormal condition, including errors, generated during the program's execution. Here are some frequently encountered exceptions.
Literals are non-object values in Java; it can be literally specified in the code as a character sequence that conforms to specific syntax based on the value's type. The eight java literals are:
In every class there should be an equals method, for comparing the current instance to its input. Most objects in java simply inherit this method from the base class Object. Two objects are .equals() if they cannot be distinguished using any sequence of calls to the objects' methods. For further details refer to page 94 of the textbook.
.equals to each other, are they
indistinguishable? Is your answer the same for both mutable and immutable
objects?
String aStringLiteral = "abc";
String aStringObject = new String("abc");
String anotherStringObject = new String("abc");
What should be the output of the following statements?
1. aStringLiteral == "abc";
2. aStringLiteral.equals("abc");
3. aStringObject == "abc";
4. aStringObject.equals("abc");
5. aStringLiteral == aStringObject;
6. aStringLiteral.equals("abc"));
7. aStringObject == anotherStringObject;
8. aStringObject.equals(anotherStringObject);
1. true 2. true 3. false 4. true 5. false 6. true 7. false 8. true
Immutable objects should not be compared to its literal counterparts or
another object of the same type using ==,
if what you want is to check whether they have the same value. == checks whether two literals are the
same, or whether two statements evaluate to point to the same object.
The default equals function an object has is inherited from the java Object class. When you are implementing immutable class, you should define your own equals method.
In closing, use == exclusively for literals. Use .equals() for objects if you are testing observable similarity (are all the fields the same?) and use == on objects if you want to know if two reference are in fact the same object.
All java classes have a toString method that is either inherited from the Object class or implemented by the class. The method returns a string that represents the current state of the object. In the ComplexNumber class, toString returns the string a + bi, in which a is the real part and b is the imaginary part.
public String toString() {
if (img >= 0)
return real + " + " + img + "i";
else
return real + "-" + (-img) + "i";
}
When you define a new class, you should implement your own toString method. It makes outputing easier, and is good for debugging as well. Trust us, this is a really good idea. Your code will generally need to be debugged, at which point you will end up writing a toString() method anyway, and you'll wish you just had one instead of having to side-track your mind to write one.
Consider the following simple Java method:
/**
* This takes an integer array, a begin index into the array, and an
* end index into the array, and returns the sum of the array elements
* from the begin index, up to, but not including, the end index.
*/
public int computeSum(int[] elementArray, int beginIndex, int endIndex) {
int result;
result = 0;
for (int i=beginIndex; i<endIndex; ++i)
result += elementArray[i];
return result;
}
This seemingly innocent program is fraught with peril! The following must be true in order for the program to work correctly:
To ensure program correctness, either this method must check these conditions, or every method that calls this one must ensure that it passes in arguments that meet these requirements. This is by no means the end of the world for this program. In fact, this isn't even a problem with the code. It's only a matter of specification.
// comments one line /* ...comments a region... */ /* comment /* comment */ not comment */ (These may not be nested.) /** * This is a JavaDoc comment block. Note that * it begins with two stars after the slash. * The vertical stars are ignored, and just make * it clearer that it is a comment. **/ // You can also make block comments // like this. This is not a JavaDoc // comment and is harder to read.
Comments may be used to temporarily remove code from a program. The most effective comment for this is // placed at the beginning of every line you intend to remove. (/* ... */ comments are worse because they do not nest and because it is hard to tell what code is commented out, especially in printouts or when syntax highlighting is not used). In general, you should use the first method shown above for javadoc comments, and the second method above for comments in your code that explain what is going on. Code removed with comments should never be left in a final version of your program.
Comments may be used to explain tricky parts of your program in English. It is also good to put a comment before every function describing what it does (using the javadoc format mentioned above, along with the keywords requires, effects, and modifies. Look in ComplexNumber for an example of how to do this). If you have any trouble reading the comments in the ComplexNumber example, or in the problem set 1 code, feel free to ask a TA or LA to explain any of the comments.
Consider the code:
Integer i = new Integer(3); Number n = i; List<Integer> intlist = new ArrayList<Integer>(); List<Number> numlist = new ArrayList<Number>(); intlist.add(i); intlist.add(n); numlist.add(i); numlist.add(n); int x = i.intValue(); int y = n.intValue();
n (which is Number) is not a subtype
of Integer.n is Integer, even though the
compile-time type is Number.ArrayList<Integer> and
ArrayList<Number>?
Integer is a subtype of
Number, ArrayList<Integer> is not a
subtype of ArrayList<Number> — and neither is
ArrayList<Number> a subtype of
ArrayList<Integer>. However,
ArrayList<Integer> is a subtype of
List<Integer>.
(For advanced students: there are wildcard types, ArrayList<?
extends Number> and ArrayList<? super Number>,
which have subtyping relations with
ArrayList<Number> — but there are
restrictions on how values of these compile time types may be used.)