Sie sind auf Seite 1von 33

Intro.

to Computer Science, Fall 2012 Notes, Part 1


Madeleine Thompson <mbt@cs.nyu.edu> https://sites.google.com/site/nyucsciua0101 Sept. 4: Course objectives, VC with Subversion Introduction Objectives Grades i5 accounts Version control Subversion demo Readings for Sept. 4 Sept. 6: Integer representation and twos complement Integer representation Twos complement arithmetic Exercises, all answers unsigned 4-bit binary Representations of other data types Java integer types Abacus.java Readings for Sept. 6 Sept. 11: Boolean and floating point variables Boolean variables Exercises Demo Floating point variables Exercise Exact and inexact Readings for Sept. 11 Sept. 13: Floating point relations, hexadecimal, and Unicode Floating point relations Exponential notation Exercise Hexadecimal notation Exercise Unicode Strings Readings Sept. 18: Control structures (if, while, do-while, for, switch) if, if-else while loops do-while loop break continue for switch Another example Readings Sept. 20: Nested loops and formatted printing Bestiary of operators Preincrement and postincrement Nested loops String formatting Decompose.java Sept. 25: Methods, call stack, and variable scope Methods (a.k.a. functions) Example Variable scope Call stack Readings Sept. 27: Arrays What is an array? Creating arrays in Java Working with arrays Arrays are references Exercise Readings Oct. 2: Classes Classes: aggregation and abstraction Aggregation Abstraction Readings Oct. 4: Classes, continued Note Example from last time "this" Constructors packages, public, private, and "default" previous example, now with access modifiers Garbage collection and finalizers Oct. 11: Inheritance and the object hierarchy Inheritance instanceof operator java.lang.Object Readings

Oct. 18: Static and dynamic types, dispatch, toString, and equals static types and dynamic types Method dispatch Example toString equals Oct. 23: Parametric types and ArrayList Bonus warning: hashCode and hashtables Background: boxed types Introduction ArrayList Efficiency Example: withoutEvens For-each loop Oct. 25: Interfaces and abstract classes Interfaces Interface example Sorting example: Abstract classes Some context for abstract classes Readings Nov. 6 (part 1): Comparable<T> and TreeMap Comparable<T> Exercise Sorting addendum Comparator is not just for sorting: TreeMap<K,V> Example: counting messages sent Exercise: writing compare Addendum on Set

Sept. 4: Course objectives, VC with Subversion


Introduction


Objectives

Main purpose: to gain experience in a variety of aspects of computer programming Learn Javaits widely used, scales up well, and forces you to think about what youre really doing more than Python or PHP. Preparation for study in abstract computer science, so you can turn ideas into reality Prerequisites: Must already know some programming language. Anti-prerequisites: If youve done a substantial amount of programming in Java, C++, or another statically-typed language, you will probably be bored. Madeleine Thompson, mbt@cs.nyu.edu o office hours Thursday 10:4511:45 WWH 328 o let me know if you're coming Grader TBD


Grades

Gain a shallow understanding of a wide variety of CS topics so that when you encounter concepts in more depth in later courses, you have context for how they might apply. Understand how data is represented in a computer. Understand how types can be used to describe data and ways of processing it. Write Java programs that take advantage of its type system. Use version control. Understand data and functional abstraction. Understand event-driven programming and use it to construct basic GUIs.

Grades: 35% homework, 20% midterm, 45% final. Midterm is in class on Oct. 9.

Date of final will be announced. Re-grading of homework: Ill do it, but I wont look at your previous grade. It may go down.

i5 accounts

You can use any computer you want for this course. We can't support every possible type of computer you might have. i5.nyu.edu is a baseline. Log into it with:

o o

MacOS/Linux: open Terminal and type ssh yournetid@i5.nyu.edu Windows: use PuTTY to connect to i5.nyu.edu with your netid as the username

Version control

Keeps around every version of your codedata loss is rare. Remotely accessible Share code (with me, not each other) Version Control with Subversion: http://svnbook.red-bean.com/ Version Control by Example: http://www.ericsink.com/vcbe/

Subversion demo
ssh netid@i5.nyu.edu chmod 700 $HOME # Make it so others can't read your files. svn checkout https://netid@subversive.cims.nyu.edu/csci0101/u/netid cd netid ; mkdir hw1 # create a local directory, hw1 svn add hw1 # mark hw1 directory to be added to repository cd hw1 vi Hello.java # Or emacs, or nano. # Add this text: # public class Hello { # public static final void main(final String[] args) { # System.out.println("Hello, World!"); # } # } # } # checkstyle checks for common mistakes that javac might miss. # It finds things that are technically valid code, but might indicate # a bug. java -classpath /opt/checkstyle/checkstyle-5.5-all.jar com.puppycrawl.tools.checkstyle.Main -c /opt/checkstyle/sun_checks.xml Hello.java # 3 lines are one command javac Hello.java # build Hello.class java Hello # run the program svn add Hello.java # mark Hello.java to be added to repository svn commit -m "commit message" # add files to repository svn propedit svn:ignore . # Add "*.class" so svn stops bugging us svn commit cd .. # At this point, if you run 'pwd', it should print something like: # /home/y/yournetid123/yournetid123 # (the top level directory of your personal Subversion directory) svn mkdir submit # create your submit directory svn cp hw1 submit/ # copy hw1 directory to your submit directory svn commit # ...and it's turned in

Readings for Sept. 4

Chapters 13 of Version Control by Example Liang 7th ed. 1.79 or 9th ed. 1.68 and 1.10

Sept. 6: Integer representation and twos complement


Integer representation

Computers only store bits. Bits are grouped into machine words, the units the computer deals with most easily Most computers these days have 32 or 64 bits in a machine word. Pretend a machine word is 4 bits. Then, we can represent 2 + 3 = 5 by 0010 + 0011 = 0101. Signed integers (5, 0, -8, etc.) are represented in binary (base 2) in twos complement.

o o

Not, plus a carry -2 in four bits is (not 0010 + 0001) = (1101 + 0001) = 1110

Twos complement arithmetic

Negative numbers wrap around. So for 3 bit words:

o o o

Unsigned: Signed: Binary: 0

0 1

1 2

2 3

3 -4

4 -3

5 -2

6 -1

000 001 010 011 100 101 110 111

Addition ignores the twos complement rule. So 2u + 4u = 6u. +2 + -4 = -2. 6u and -2 have the same representation. Same for subtraction: 7u - 2u = 5u, -1 - +2 = -3. 5u and -3 have the same representation. Some numbers cant be represented. On overflow, the answers wrap around. o +1 + +3 = -4. o -4 - +3 = +1. Multiplication, division, and remainder (mod, %) work similarly. Dont depend on the rounding behavior of division or remainder for negative numbers.

Exercises, all answers unsigned 4-bit binary

(base 2) (base 2) (base 10) (base 10) (base 10)

0101 - 0010 = 0010 - 0110 = 10 - 15 = 5 * 4 = 10 / 4 =

Representations of other data types

Does the byte 00101100 mean 44? Comma? Add 12 to accumulator? Depends on the context! Java lets us say which with its type system. Well talk about fractions next lecture.

Java integer types

byte: 8 bits short: 16 bits int: 32 bits long: 64 bits

rarely used mathematically, just for opaque data storage rarely used at all most common integer type used when int is too small (e.g. ms since 19700101)

operations on byte and short generate ints:

o o o

byte a = 100; The expression a * a has the type int and the value 10000. byte a2 = a * a; // error!

Abacus.java

In demo/Abacus.java in the Subversion repository. (Use your svn password.) simple examples leading zeros overflow on sum/difference

Readings for Sept. 6

Liang 7th ed. 2.18 and 2.1315 or 9th ed. 2.111 and 2.15. If you're interested in or confused by two's complement arithmetic, check out the Two's Complement Wikipedia page.

Sept. 11: Boolean and floating point variables


Boolean variables

take the value true or false syntax: boolean b = true; can be the result of comparisons operations:

o o o o o o o o o o

== (equal-to), != (not equal to) <, >, <= (less than or equal to), >= (greater than or equal to) boolean b = 3 > 4; ! (not) && (and) || (or) boolean b = 3 <= 2 || !(1 > 1); // b is now true // b is now false.

boolean operations:

&& and || are short circuit operators If the left hand side of && is false or the left hand side of || is true, theres no need to evaluate the right hand side. boolean b = 3 > 2 || 5 / 0 > 0; // b == true // runtime error! boolean b = 5 / 0 > 0 || 3 > 2;

Exercises

What are the values of these expressions? 1. 2. 3 <= 3 && (1 < 0 || !false) (true == true) == (0 < -1)

(Answers: true, false)

Demo
A demo given at lecture is in the Subversion demo directory as AndNot.java.

Floating point variables

Floating point variables represent fractional values Called floating point because they have a constant number of significant digits and a decimal point that could go anywhere. In base 10 with 3 digits of precision, we could have: o 1.25, 0.0000125, 125000 Two types in Java: float (32-bit) and double (64-bit). float is mostly a historical artifact like short. double is stored like this:

(Wikipedia)


Exercise

Takes the value (-1)s1.f2e-1023 Syntax: double x = 1.5; Similar operators to integers, +, -, etc. as well as common utility functions in the Math class: Math.pow, Math.acos, etc. Relational operators like != to be discussed next time.

What is this floating-point double value? 0100000000011100000000000000000000000000000000000000000000000000 Broken up: s = 0, f = 1100000000000000000000000000000000000000000000000000, and e = 10000000001 (1025 base 10). (Answer: 7.0)

Exact and inexact

Some magic values of the exponent give infinities, not-a-number (NAN), and denormalized numbers (which we will not talk about). Some (actually, almost all) fractions cant be represented exactly since fraction has a finite number of bits. Only exact fractions in base ten have denominators of the form 10y. o example: 1.25 = 125/102 Only exact fractions in base two have denominators of the form 2y. o example: 1.25 = 9 / 22 = (-1)01.010000...21023-1023 o example: 1/3 = (-1)01.01010101...21021-1023

Readings for Sept. 11

The Wikipedia page for the double precision floating point format is a useful reference; Liang does not cover it well. Also, finish chapter 2 and read 3.12 of Liang 7th ed. or 9th ed. The ambitious among you can read "What Every Computer Scientist Should Know About Floating-Point Arithmetic," by David Goldberg (94 pp.).

Sept. 13: Floating point relations, hexadecimal, and Unicode


Floating point relations

Floating point numbers have similar relational operators as integers.

o o o

0.3 < 0.4

// true! // true // false!

But, theres a catch: 0.5 * 0.5 == 0.25 0.1 * 0.1 == 0.01

Inexact representation makes 0.1 * 0.1 equal to 0.010000000000000002. Use == or != with floating point numbers with extreme caution. Comparisons may not behave as you expect for non-finite numbers: // false, NaN != NaN 0.0 / 0.0 == 0.0 / 0.0 // true, POSITIVE_INFINITY == POSITIVE_INFINITY 1.0 / 0.0 == 2.0 / 0.0

Exponential notation
You will sometimes see floating point numbers written in the form 4.13e+6 or 3e-2. This means 4.1310+6=4130000or 310-2=0.03. The Java type of a number in this form is double, even if there is no decimal point.

Exercise

1. 2.

4e+12 - 3e-9 = ? 1.0 / 3.0 has the representation e = 1023 and f = 0101010101...01. What is 1.0 / 3.0 + 1.0 / 3.0? Is this the same as 2.0 / 3.0?

Hexadecimal notation


Exercise

Hexadecimal notation is base 16, with the extra digits A=10, B=11, ..., F=15. Case is a matter of style; lowercase is more common in Java. Usually marked by writing 0x before the digits (thats zero, lowercase x) The number 0x2a is 216+10=42. We usually write hexadecimal numbers with leading zeros. A single byte is always two hex digits, a single int is always eight.

o o

int x = 0x000000e3; byte y = 0xe3;

Easy to pick out individual bits, but more compact than binary. ex.: What is bit 20 in 1496407792? Hard question. ex.: What is bit 20 in 0x59315ef0? Most significant bit in the fifth place, which is a one, which is less than 8, so bit 20 is zero.

1. 2.

0xA3 - 0x52 0xFE + 0x03

Unicode

Last week I said 44 might be a comma if you store a single character in a byte (ASCII). There are more than 28symbols in the world's languages. Java has the "char" data type, a 16-bit unsigned integer (which takes values 0 to 65535). comma is 44, is 26412, etc. There is a standard; it is 1472 pages long. Syntax: char char char char char char c1 c2 c3 c4 c5 c6 = = = = = = 44; ','; // same as c1 '\n'; ''; // platform-dependent '\u672c'; // portable c4 using four hex digits 26412; // same as c5


Strings

There are not only more than 256 symbols, there are more than 65536. o Mostly variations on Chinese-derived ideographs. o Handling the ones that don't fit in a char is awkward in Java. o We won't be talking about it in this class. For more information, check out "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)," by Joel Spolsky at http://www.joelonsoftware.com/articles/Unicode.html. For some useful functions like isUppercase, check out the Character class documentation.

We've danced around java String a bunch so far, and will continue to do so for a while. In the meantime, note that a String is a sequence of char Unicode escapes are valid in String literals: String s = "\u65e5\u672c"; //

Readings
There's nothing required for this lecture, but I recommend "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)". And, make sure you're caught up with the readings mentioned in the Sept. 11 notes.

Sept. 18: Control structures (if, while, do-while, for, switch)


if, if-else

Lots of content this lecture All easytrivially different than Python

int x =3 if (x > 0) { x = -1; } // now x is -1

int y = -3; if (y > 0) { y = 1; } else { y = -1; } // now y is -1

Omitting the braces is sometimes legal but always confusing.

int z = 0; if (z > 0) if (z > 2) z = 1; else z = -1; // What is z?

while loops
while (condition) { statements to repeat while condition is true } int x = 0; int y = 0; while (x < 10) { x = x + 1; y = y + x; } // x is now 10, y is now 1 + 2 + ... + 9 + 10 = 55

do-while loop
do { statements to repeat while condition is true } while (condition);

Like a while loop, but checks condition at the end instead of the beginning. So, loop body always runs at least once.

int x = 0; int y = 0; do { x = x + 1; y = y + x; } while (x > 10); // x and y are now both 1

int x = 0; int y = 0; while (x > 10) { x = x + 1; y = y + x; } // x and y are now both 0


break

Sounds like it might be useful, but rarely is. I have started writing them many times, but I don't think I've kept one in ten years.


continue

Exits current loop. Often used when the loop statements are of the form "Read input, then do something with input," so that the loop can terminate if the input ends. See SumSqBreak.java.


for

Doesn't end the loop, just skips to the condition test. See SumSqContinue.java. When looping over inputs, can be used to ignore invalid or inappropriate data without wrapping the entire body with "if (valid) { }". Be careful! break and continue jump end statement blocks without a close-brace, so they can confuse people reading your code.

Syntax: for (initializer; condition; iteration) { statements to repeat while condition is true ; }

Example: int x = 0; for (int i = 0; i < 3; i = i + 1) { x = x + i; } // x is now 0 + 1 + 2 = 3

Almost the same as: int x = 0; int i = 0; while (i < 3) { x = x + i; i = i + 1; }

Would only be different if there were a continue inside the body.

o o

The iteration statement runs every time. Historically, they predated all other loops.

for loops are a common pattern, so they're provided for brevity. There is also a "for-each" loop, which we will discuss later. It looks like: for (int x : someSequenceOfInts) { }

switch

Jumps to a different place depending on the value of an integer. Just like if-else executes different statements for the two values of a boolean, switch executes different statements for different values of an integer. int x = 2; int y = 0; switch (x) { case 0: y = 1; // Control goes here if x is 0. break; case 2: case 3:

y = 2; // Control goes here if x is 2 or 3. break; default: y = 3; // Control goes here if x does not match a label. break; } // Now y is 2.

Without the breaks, the line "y = 3;" would run after "y = 2;". Weird syntax is a historical artifact relating to goto in C. Never leave out break statements and fall through unless you have a good reason and document that it wasn't accidental.

Another example

Readings

See PowerForLoop.java

If you have Liang 7th ed., read 3.35, 3.7, and 4.19. If you have Liang 9th ed., read 3.315, 3.17, and 4.110.

Sept. 20: Nested loops and formatted printing


Bestiary of operators

bitwise and, or, xor, and not: &, |, ^, ~ bitwise left shift, right shift, unsigned right shift: <<, >>, >>> We won't use bitwise operators in this class. Rarely useful in Java You should recognize them if you see them, though. i += j is the same as i = i + j Similar for -=, *=, /=, &&=

Preincrement and postincrement

++i (preincrement) and i++ (postincrement) are both like i += 1 (or i = i + 1) and mean the same thing in a statement on their own. As an expression, though, the value ++i is the value of i after adding one,while the value of i++ is the value of i after one is added.

int j = 0; int k = j++; // Now j==1 and k==0. int j = 0; int k = ++j; // Now j==1 and k==1.

int j = 0; j = (j++); // What is j now?

++i and i++ are convenient shorthand for i = i + 1 on its own. In an expression, you have to think about its consequences so much it's not worth the trouble.

Nested loops

Loops can go inside other loops. Each time though the outer loop, the inner loop starts over again.

for (int i = 0; i < 3; i++) { for (int k = 0; k < 2; k++) { System.out.println(String.format("(%d,%d)", i, k)); } } (0,0) (0,1) (1,0) (1,1) (2,0) (2,1)

Inner loop conditions can depend on outer loop variable:

for (int i = 1; i <= 5; i++) { int factorial = 1; for (int k = 1; k <= i; k++) { factorial = factorial * k; } System.out.println(String.format("%d! = %d", i, factorial)); } 1! 2! 3! 4! 5! = = = = = 1 2 6 24 120

break and continue apply to the innermost loop. See NestedBreak.java. Output:

10! 11! 12! 13! 14! 15!

= 3628800 = 39916800 = 479001600 is big. is big. is big.

Same goes for switch. o a break in a switch inside a for or while loop aborts the switch o a break in a loop inside a switch aborts the loop

String formatting

Weve used the String.format function a bunch, but never explained it. Based on the C function printf. Also appears in Python as the % string operator. Examples:

String.format("A string without percent signs.") // Returns "A string without percent signs." String.format("%d cookies", 7) // Returns "7 cookies" String.format("...%3d cookies", 6) // Returns "... 6 cookies" String.format("...%03d cookies", 5) // Returns "...005 cookies" String.format("...%4.2f cookies", 4.12345) // Returns "...4.12 cookies" System.out.println( String.format("%20s %5.2f%%", "vertically", 1.23)); System.out.println( String.format("%20s %5.2f%%", "aligned", 0.032)); // Prints: // vertically 1.23% // aligned 0.03%

Many more options. Check out the java.util.Formatter documentation for details.

Decompose.java
Here's the source code for Decompose.java, the demo on Sept. 20.

Sept. 25: Methods, call stack, and variable scope


Methods (a.k.a. functions)

Methods serve two main purposes: o Abstraction o Avoid code duplication Abstraction:

o o o o

Replace code that does something with a name for what is being done. Change how a value is computed or an action is performed without knowing why it is computed/performed. Keep the code for performing conceptually different things separate.

Avoiding duplication: o Frequently, the same action needs to be repeated in more than one context, with different data. Methods let you write the code in terms of parameters instead of repeating the same statements with minor variations.

Example
// Does the product of x and y overflow? private static boolean canMultiply(int x, int y) { return y == 0 || (x * y) / x == y; }

private and static are modifiers. We'll talk about these two later. For now, private is not important, and every method you define must be static.

If you know Python, static means something similar to @staticmethod.

boolean is the return type. This means that the function always returns a boolean. "int x, int y" specifies the parameters that canMultiply has two parameters, both int. Call the method like this: boolean b = canMultiply(5, 0); // b is now true

Or maybe: int x = 2000000000; if (canMultiply(4, x)) { ... }

This x is a different x than the one in canMultiply! In the calling code, x is 2000000000, but in canMultiply, it is 4. See FactorialMethod.java.

Variable scope


Call stack

Variables are only meaningful until the close-brace that ends its block of statements.

See Scope.java.

For methods, this is the brace at the end of the method. o See ChangeParam.java. For for loops, this is the brace at the end of the for loop.

See FactorialScope.java.

In the previous example, main calls factorial, which calls canMultiply. We call the sequence of methods that were called to get to the current state of the program the call stack. If there is an error, it is printed out so you can see how you got to where you are. Suppose we forgot to pass the second number to String.format in FactorialScope.java: System.out.println( String.format("%d! is defined, but %d! overflows.", m - 1));

Then, when we run FactorialScope, we get the error: Exception in thread "main" java.util.MissingFormatArgumentException: Format specifier 'd' at java.util.Formatter.format(Formatter.java:2432) at java.util.Formatter.format(Formatter.java:2367) at java.lang.String.format(String.java:2769) at FactorialScope.main(FactorialScope.java:33)

This says that the actual error was detected in Formatter.java at line 2432 in the method format. We can look for our own error by reading down until we see a method we wrote ourself.


Readings

We see this at the last line, so we can look for a bug at FactorialScope.java line 33, in the function main.

Please read chapter 5 of Liang, either 7th ed. or 9th ed.

Sept. 27: Arrays


What is an array?

Arrays are a sequence of Java values. Can be any single type: int, String, whatever. Arrays let you operate on a collection of values as a whole without putting each of them into its own variable. For example, arrays let you write a method that: o sorts a collection of items of any length o adds a sequence of numbers o stores and displays the pixels of an arbitrary-size image o in any way operates on a data set whose size is not small and fixed Size is fixed on creation. We've already talked about String a bit. A String is very similar to an array of char that can't be modified.

Creating arrays in Java

An array of int is declared like this when you want to initialize it to a specific list of values: int[] x = { 21, 15, 9 };

You can also say: int[] x = new int[3]; to create an array of three elements with default values (0 for integer types).

Use this syntax to make arrays of size you don't know when you're writing the program: void myMethod(int n) { int[] x = new int[n]; // and then do stuff with x }

If you don't initialize a numeric variable, it defaults to zero. If you don't initialize an array, it defaults to the special value null

Working with arrays

The length of an array x is stored in x.length. Element i of array x is stored in x[i]. You can assign to x[i] but not x.length. Add the first two values of an array x: int sum = x[0] + x[1];

Add all of the elements of an array x: int sum = 0; for (int i = 0; i < x.length; i++) { sum += x[i]; }

Change each element of x to the cumulative sum of all elements up to and including that element: // x[0] starts correct for (int i = 1 ; i < x.length; i++) { x[i] = x[i - 1] + x[i]; }

Arrays are references

If an int is four bytes, does that mean that an int[3] is twelve? What happens if you do this: int[] x = { 0, 1, 2 }; int[] y = x; System.out.println(Integer.toString(x[1])); y[1] = 17; System.out.println(Integer.toString(x[1]));

This code will print: 1 17


Exercise

An array is a reference type. One way to think about it is that every array (of any type) is a single integer pointing to a location in memory where the array elements are stored. Assign one array to another, and you copy the reference. Change the underlying data through one reference, and you'll see the changes if you access them through the original array reference.

Write a method with the signature: bool containsElement(int[] a, x); that returns true if a contains the element x and false otherwise. It is allowed (encouraged!) to cause the computer to catch fire of a is null.

Readings

Please read chapter 6 of Liang, either 7th ed. or 9th ed.

midterm covers up to here

Oct. 2: Classes
Classes: aggregation and abstraction

Arrays let you store an arbitrary-sized sequence of elements of the same type. What if you have fixed collection of data, possibly not of the same type? o Classes let you aggregate the data into a single object. What if you want to provide an abstract interface to an object without its users knowing how exactly it's stored? o Classes let you hide the implementation details, sharing only a documentable interface.

Aggregation

Example: class WebPage { String url; String html; }

This represents a web page as a URL and some HTML text. This pair of data can be returned from a method as a single object, like an array: static WebPage makeWebPage() { WebPage page = new Webpage(); page.url = "http://www.nyu.edu" page.html = "<html>...</html>"; return page; }

It can also be passed to a method as a single object: static void savePageToCache(WebPage page) { ... }

Abstraction

in addition to grouping data together, classes can be used to abstract away the underlying implementation instance methods let an author hide implementation details from the users of the class

In the previous example, suppose a lot of web pages are identical, and we want to save space by storing each unique page once.

Instead of accessing html directly, we can declare that it be accessed through a getHtml method. class WebPage { String url; String html; String getHtml() { return html; } }


Readings

Notice how a method that is not declared static can access members not declared static directly (without "object." before them). This way, we can change how the class stores the HTML at our leisure without affecting the callers' code.

Read chapter 7 in Liang 7th ed. or chapter 8 in Liang 9th ed.

Oct. 4: Classes, continued


Note
These are the notes I planned to use. I decided I didn't like them much, and did a Towers of Hanoi example in class instead, covering mostly of the same material. The source code is in Towers.java. Madeleine

Example from last time


class WebPage { String url; String html; String getHtml() { return html; } }

"this"

In the previous example, we're going to need a setHtml method, too. It'll look something like: void setHtml(String newHtml) { html = newHtml; }

This can get a bit confusing. Which variables are parameters, and which are instance variables? Inside non-static methods, the this object refers to the current object, so you can write: void setHtml(String html) { this.html = html; }

this is also useful when a method wants to return a reference to its own object, or pass itself to another object:

class Installer { String packageName;

void installProgram(String packageName) { this.packageName = packageName; // save for later String installLocation = askUserForInstallLocation(); PackageManager.installInBackground( packageName, installLocation, this); } // Called by PackageManager when installation is done. void doneInstalling() { System.out.println("Done installing " + packageName + "."); } }

Constructors

Constructors are functions that initialize an object. They have the same name as the class and no return type: class WebPage { final String url; final String html; WebPage(String url, String html) { this.url = url; this.html = html; } ...

Now, instead of creating a WebPage with: WebPage page = new WebPage(); page.setHtml(...); ... We do: WebPage page = new WebPage("http://...", "<html>...");

This way, it's not possible to create a WebPage that is not properly initialized. It also means that we can get rid of setHtml, etc. if we don't want the object to be changed after it's created. The final modifiers on the instance variables make it impossible to change them, just like final on arguments to methods. final instance variables must be set in the constructor or directly where they are defined, and can't be changed in other methods. What if we want to be able to change instance variables with functions like setHtml, but don't want any random caller to be able to sneak past our abstraction?

For this, there are access modifiers: public, private, etc.

packages, public, private, and "default"

A package is declared at the top of the source file with: package packagename;

The package name is usually the same as the directory the source is in. Conventionally, the package is an URL, backwards, like "edu.nyu.programname". As we've already seen, you access classes from other packages with import.

not necessary for classes in the java.lang package like Integer.

Classes marked public can be used by name by other classes. Classes marked private cannot be used by name by other classes.

Classes marked neither public nor private can be used by classes in the same package.

o o

Called "default" access.

Methods and fields marked public can be read and written by other classes. Methods and fields marked private cannot be used by other classes, only methods of their own class. But maybe a different object! Methods and fields marked neither public nor private can be used only by classes in the same package. Another access specifier, protected, we will discuss later.

previous example, now with access modifiers

public class WebPage { private final String url; private final String html; public WebPage(String url, String html) { this.url = url; this.html = html; } public String getHtml() { return html; } public String getUrl() { return url; } }

String objects can't be changed, so if you use this class and call getHtml multiple times, there is no way for different objects to be returned different times. This would not be true if html were stored as a char[].

Array reference could stay the same, while elements of the underlying array could be changed.

Garbage collection and finalizers

Java automatically frees the memory used by objects when they're no longer used. Subsystem called the "garbage collector." When an object is freed, the garbage collector calls its finalize method. Never use this feature. o GC is fickle. Finalizer may never be called. o See Effective Java 2nd Ed. (Item 7) for more details.

Oct. 11: Inheritance and the object hierarchy


Inheritance

Inheritance is a way to build a class that extends the functionality of another. If class A extends class B, A is called a subclass and B is called a superclass. A can be considered to be a kind of B. Historically, comes from the GUI world, from Smalltalk:

o o o

A DialogBox could extend a Window, inheriting all the functionality of a Window and adding new behavior specific to modal dialog boxes. Want a button that does something when clicked? Extend the regular button and replace the onClick method. We'll do this later in the course.

In my opinion, almost never a good idea, but often you don't have a choice.

Utility class shared by both classes is preferable. Inheritance is pervasive in Java APIs, especially old ones.

instanceof operator
If we have: class class ... A x = B y = A z = B w = Then: x instanceof A // true y instanceof A // true z instanceof A // true x instanceof B // false y instanceof B // true z instanceof B // true It's safe to pass objects which may be null to instanceof; it always returns false. A a = null; a instanceof A // false It is usually a bad idea to use instanceof, though. A { ... } B extends A { ... } new new new new A(); B(); B(); A();

// legal, since B is a kind of A // error! A is not a kind of B

java.lang.Object


Readings

Unless you define a class with extends, there is an implicit "extends java.lang.Object". Object has a bunch of methods, mostly bad ideas relating to threading. equals, toString, and hashCode are the ones we care about most.

Read chapters 9 and 10 of Liang 7th ed. or 10 and 11 of Liang 9th ed. ("Thinking in Objects" and "Inheritance and Polymorphism").

Oct. 18: Static and dynamic types, dispatch, toString, and equals
static types and dynamic types

An object's static type (or compile-time type) is the type it is declared as locally. An object's dynamic type (or run-time type) is the type of the constructor that created it. An object's dynamic type is always a subtype of its static type. You can always store a specific type in a more general variable:

class class ... A a = B b =

A { ... } B extends A { ... } new B(); // legal, B is a subtype of A new A(); // illegal, A is not a subtype of A

A aa = new B(); B bb = aa; // illegal, aa's static type is A, and not all A are B B b3 = (B) aa; // legal...tell the compiler we know what we're doing; // works because the runtime type of aa is B ... A a4 = new A(); B b4 = (B) a4; // same as with aa, but generates ClassCastException // because a4 does not have the dynamic type B.

Method dispatch

An object's static type determines which methods may be called.

o o

If you have a variable a of type A, and A has a method foo, you can call A.foo(...). If A has a method foo, and B extends A, then both of these do the same thing: A x = new B(); x.foo(); and: B x = new B(); x.foo();

An object's dynamic type determines which implementation is run.


Example

If foo is defined in B, then the foo in B overrides the one in A, and the one in B is called. Otherwise, the one in A is called.


toString

TextWindow.java Note call to super() in constructor. paintComponent is overridden

Object.toString returns something like "Test@eb42cbf", which is often useful for debugging. (At least it tells us what kind of object it is.)

We can do better by overriding it. For example: public class EmailAddress { private String username; private String host; ... @Override public String toString() { return username + "@" + host; } }

Users of your class may depend on the behavior of toString. Good practice:

o o o o o o

Don't rely on a single toString method with no arguments for a class like Date. Provide a separate formatting method. A class like DatabaseConnection has live state you can't turn into a String no matter how hard you try. Its toString should be for debugging. A class like URL or Boolean has a single, obvious interpretation as a String. Go ahead and rely on it. Often, you insert System.out.println(obj) into code to see what obj was when the program passed by that point. String.format uses toString to convert anything you pass it to a String when it sees a %s format specifier. (String.toString is just return this.) Code that reports error conditions often call toString on the problematic object when building an error message, particularly if it's a type of object it can't handle.

When I say debugging, what do I mean?

equals

So, override toString liberally!

Unless they are primitive types like int, a == b is true if a and b are the same object. == is unpredictable for immutable objects like String and nearly useless for your own classes. new String("foo") == new String("foo") is false. An alternative is the equals method. Object.equals is the same as ==, which is probably not what you want.

a.equals(b) and a == b are the same by default.

You can override equals. public class EmailAddress { private String username; private String host; ... @Override public boolean equals(Object obj) { if (!(obj instanceof EmailAddress)) { return false; } EmailAddress address = (EmailAddress) obj; return username.equals(address.username) && host.equals(address.host); } }

The @Override is important.

o o

Doesn't change the meaning of the code. But, suppose you did the sensible appearing thing: boolean public equals(EmailAddress address) { ... } Then, which equals gets called would depend on what type of variable the argument is stored in, not what type it is.

@Override protects you from accidentally creating a new method that won't get called at the right time when you meant to replace a method.

See EqualsDispatch.java for an example.

Oct. 23: Parametric types and ArrayList


Bonus warning: hashCode and hashtables

Remember Python dict? Java has something like them, HashMap. Just like a Python dict, HashMap maintains a mapping from keys to values. There is another method of Object, hashCode, that is used by HashMap. Others might put your objects into a HashMap without telling you about it. If you override equals and do not override hashCode, bad things will happen. CSCI-UA.0102 covers HashMap.

Background: boxed types

int, char, etc.types with lowercase namesare primitive. No methods, value only, can't be null. Variations: Integer, Character, etc. are reference types. We need these because some places in Java, you need to use a proper object. o Widely regarded as a mistake in language design, but can't be fixed now. An Integer holds a single int: Integer x = new Integer(17); int xx = x.intValue(); // xx is now 17.

Integer, etc. can be null. Autoboxing: Integer x = 10; is shorthand almost, but not entirely, equivalent to: Integer x = new Integer(10);

Never use == to compare boxed types. Can't be sure a new one will be created unless you specifically say new. Same ideas apply to String! Who knows what this will do? Integer x = 10; Integer y = 10; if (x == y) { System.out.println("x == y"); }

Conversion rules are complicated.

o o

Easy way: always use intValue, booleanValue, etc. Hard way: Grok JLS 5.1.78.

Introduction


ArrayList

Python has lists and dicts. What does Java have? You can't resize arrays, so they don't count. Parametric types let you create classes that depend on other classes. For example, you could define a Matrix class that depends on a number-type class so that you could define a matrix of integers, a matrix of complex numbers, etc. without changing the Matrix class. We'll skip past most of the interesting things you can do with parametric types and just talk about containers, mainly ArrayList and TreeMap.

ArrayList<Integer> is a lot like int[], but can change size. Can't have an ArrayList<int> because int is not a class.

// Create list of size 0. ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.set(0, 3); // list now has elements: // 3, 2 int s = list.size(); // s is now 2. int x = list.get(1); // x is now 2.

// Create list of size 10. static final int N = 10; int[] a = new int[N]; a[0] = 1; a[1] = 2; a[0] = 3; // a now has elements: // 3, 2, 0, 0, ..., 0 int s = a.length; // s is now 10. int x = a[1]; // x is now 2.


Read ArrayList documentation for a full list of all the operations you can do. Note the auto-boxing used when adding and extracting elements.

o o

We added an int to a container of Integer. More concise than: list.add(new Integer(1));

Efficiency

ArrayList uses an array underneath the hood (name gives it away). Some operations are cheap, on average: o adding an element to the end

o o o

resizing removing the last element accessing any element

Some are expensive, since they may require copying other elements: o adding an element in the middle o removing an element from the middle Other collection classes have different properties. CSCI-UA.0102 has it all! For now, we ignore these details.

Example: withoutEvens
public static ArrayList<Integer> withoutEvens( ArrayList<Integer> list) { ArrayList<Integer> returnList = new ArrayList<Integer>(); for (int i = 0; i < list.size(); i++) { Integer elem = list.get(i); if (elem.intValue() % 2 != 0) { returnList.add(elem); } } return returnList; }

For-each loop
That for loop is boilerplate. Here's a more concise form: public static ArrayList<Integer> withoutEvens( ArrayList<Integer> list) { ArrayList<Integer> returnList = new ArrayList<Integer>(); for (Integer elem : list) { if (elem.intValue() % 2 != 0) { returnList.add(elem); } } return returnList; }

elem takes on every element of list. You can use this to perform some operation the elements of any object with an iterator method. Also works with arrays:

public static ArrayList<Integer> withoutEvens(int[] array) { ArrayList<Integer> returnList = new ArrayList<Integer>(); for (int elem : array) { // <-- LOOK HERE: for loop over an array if (elem % 2 != 0) { returnList.add(elem); // autoboxing: int converted to Integer } } return returnList; }

Oct. 25: Interfaces and abstract classes


Interfaces

Last time, I showed how to iterate over the elements of anything with an iterator method. e.g.: for (Integer elem : listOfIntegers) { ... }

You can write methods that have arguments like this using an interface. An interface is like a class, but does not specify an implementation, only public methods. For example: public interface Iterable { Object iterator(); }

This says that an Iterable must have a public method named iterator that returns an Object. All methods specified in an interface are public, so we don't need the public keyword.

Interface example

Here's an interface for objects that have a natural order: public interface Comparable { // return negative if this < obj, 0 if this == obj,

// positive if this > obj. int compareTo(Object obj); }

Suppose we want to be able to sort email addresses with the EmailAddress class we talked about earlier. Here's a reminder of what it looked like: public class EmailAddress { private String username; private String host; // define constructor, getXXX, equals, toString, etc. }

Modify to this: public class EmailAddress implements Comparable { private String username; private String host; // define constructor, getXXX, equals, toString, etc.

// sorts case-insensitively first by host, then by // username @Override public int compareTo(Object obj) { // Causes an error if we compare to something not an // EmailAddress. EmailAddress addr = (EmailAddress) obj; int hostOrder = host.compareToIgnoreCase(addr.host); int userOrder = user.compareToIgnoreCase(addr.user); if (hostOrder != 0) { return hostOrder; } else { return userOrder; } } }

Results in the order "foo@a.com", "bar@b.com", "BAZ@B.COM".

Sorting example:

We can get this now with: EmailAddress[] addresses = ...; Arrays.sort(addresses);

Arrays.sort uses the compareTo method in the Comparable interface to sort the array we give it.

Abstract classes

An abstract class is halfway between a regular class and an interface. Like a regular class, some or all of its methods are defined and it can have fields.

Like an interface, it can't be directly created with new and it may have declared but undefined methods. "Abstract," as opposed to concrete, because you can't create them directly. Syntax:

public abstract class AbstractList<E> implements List<E> { public int indexOf(E elem) { ... } // implemented method public abstract E get(int index); // unimplemented method ... }

To obtain an object that is an AbstractList, you need to extend it and implement all the unimplemented methods.

Just like an interface, except some methods have a default implementation you can use.

Some context for abstract classes

Commonly used when you want to give users of your code lots of features with a big interface like List<E>, but a lot of the code is common to most implementations. o Implementing it in every implementation would be tedious.


Readings

Either implement List from scratch, or extend AbstractList.

Abstract classes predate interfaces in the Java language. o Even though both abstract classes and interfaces can't be directly instantiated, abstract classes are called "abstract" and interfaces aren't since in the beginning, there were no interfaces. You will occasionally see abstract classes like java.util.Dictionary that have weird definitions because they predate the addition of interfaces to the language.

Read chapter 11 in Liang 7th ed., chapter 15 in Liang 9th ed., or the chapter called "Abstract Classes and Interfaces" in other editions.

Nov. 6 (part 1): Comparable<T> and TreeMap


Comparable<T>

Last time, we used Comparable to compare a bunch of EmailAddress objects: class EmailAddress implements Comparable { ... }

It was messy, though, since we had to do: @Override public int compareTo(Object obj) { ... }

If obj was not an EmailAddress, the method would break at runtime. Wouldn't it be nice if we got a compile time error and didn't need to cast obj to an EmailAddress first?

Instead of implementing Comparable, we can implement Comparable<T>. Comparable<T> looks like this: So we can implement it like this: class EmailAddress implements Comparable<EmailAddress> { ... @Override public int compareTo(EmailAddress addr) { ... } }

Exercise

Read ... implements Comparable<EmailAddress> as "is an object that can be compared to an EmailAddress.

Define a class IntWrapper with a single public field "int x" that considers itself less than another IntWrapper if the absolute value of x is less than the absolute value of the x of the other IntWrapper.

Sorting addendum

You could sort a bunch of IntWrapper objects by: List<IntWrapper> someInts = new ArrayList<IntWrapper>(); // Add elements to someInts. Collections.sort(someInts);

Here, I use List instead of ArrayList. List is an interface with all the interesting methods of ArrayList, but does not imply an implementation. Any method that takes a List can take an ArrayList, but not vice versa. Using List lets us call any method that accepts any kind of List, not just an ArrayList. Good style to do this, but it doesn't make much of a difference in this example.

Comparator is not just for sorting: TreeMap<K,V>

Python has dict. What does Java have?

o o o o o o o o

More than you have any use for. All of them implement the Map interface. Got a bunch of V objects labeled with K objects? Are they comparable? Stick them in a TreeMap<K,V>! Details in CSCI-UA.0102 If the key were an Integer, a TreeMap<Integer,V> would be sort of like an ArrayList<V>. But, List objects have to have indices from zero to one less than the size. Map objects can have any collection of keys.

One possibility is TreeMap<K,V>.

TreeMap holds objects in a sorted binary search tree. Just like ArrayList lets you look up objects by their index, TreeMap lets you look up objects by a key.

Since a TreeMap keeps the objects sorted, it is fast to fetch the value for a particular key. Also fast to insert and delete key-value pairs, even from the middle of the collection.

Example: counting messages sent

import java.util.Map; import java.util.TreeMap; public class MailSender { private final Map<EmailAddress, Integer> messagesSent; public MailSender() { messagesSent = new TreeMap<EmailAddress, Integer>(); ... } public int numMessagesSent(EmailAddress recipient) { return messagesSent.containsKey(recipient) ? messagesSent.get(recipient) : 0; } public void sendMessage(EmailAddress recipient, String message) { ... messagesSent.put(recipient, numMessagesSent(recipient) + 1); } }

Exercise: writing compare


Suppose we have a class that looks like this: public class EmailAddress { private String username; private String host; ... } We can't change it, though. TreeMap lets us pass an explicit Comparator<T> object that overrides any compareTo in the objects in the map itself. It has a single method: interface Comparator<T> { int compare(T t1, T t2); } Write the code for a Comparator<EmailAddress> so that the MailSender class would count messages by host, ignoring username.

Addendum on Set

Just like Python has dict and set, Java has Map and Set. TreeSet implements Set like TreeMap implements Map. Keeps track of a collection of objects. "Is this element in the set?" and "Add this to the set," is faster than with arrays since it doesn't need to operate on every element in the array to perform the requested operation.

continued...

Das könnte Ihnen auch gefallen