Computer Science 15-100 (APEA Section E), Summer 2008
Class Notes: Ch 3: Using Classes and Objects (1 of 2)
Logistics
Topic Outline:
Ch 3:
Using Classes and Objects
Polygon p1 = new Polygon(); p1.addPoint(10,10); p1.addPoint(40,80); p1.addPoint(70,10); Polygon p2 = new Polygon(); p2.addPoint(10,110); p2.addPoint(40,180); p2.addPoint(70,110); page.setColor(Color.blue); page.fillPolygon(p1); page.setColor(Color.red); page.fillPolygon(p2);
Polygon p1 = new Polygon();
p1.addPoint(10,10);
p1.addPoint(40,80);
p1.addPoint(70,10);
Polygon p2 = new Polygon();
p2.addPoint(10,110);
p2.addPoint(40,180);
p2.addPoint(70,110);
Polygon p = p1;
p.addPoint(40,30);
page.setColor(Color.blue);
page.fillPolygon(p1);
page.setColor(Color.red);
page.fillPolygon(p2);
Polygon p1 = new Polygon();
p1.addPoint(10,10);
p1.addPoint(40,80);
p1.addPoint(70,10);
Polygon p2 = new Polygon();
p2.addPoint(10,110);
p2.addPoint(40,180);
p2.addPoint(70,110);
Polygon p = p1;
p.addPoint(40,30);
p = p2;
p.addPoint(40,30);
page.setColor(Color.blue);
page.fillPolygon(p1);
page.setColor(Color.red);
page.fillPolygon(p2);
a) For integer values
class MyCode { public static void main(String[] args) { int a = 2; int b = 2; System.out.println(a == b); // true } }
b) For floating point values
We have already seen the dangers in using "==" with floating point
values. They are approximate, and "==" will not work right with them. So:
do not use "==" with floating point values (that is, floats and doubles).
c) For Objects
import java.io.File; class MyCode { public static void main(String[] args) { File a = new File("foo.txt"); File b = new File("foo.txt"); System.out.println(a == b); // false System.out.println(a.equals(b)); // true } }
Q: Why not use the equals method on integer values (or other
primitive data types)?
A: Because you cannot call ANY methods on primitive data types!
Try this:
class MyCode {
public static void main(String[] args) {
int a = 2;
int b = 2;
System.out.println(a == b);
System.out.println(a.equals(b));
}
}
Error: int cannot be
dereferenced.
d) For Weird Cases (Objects that are sometimes cached by the compiler)
d.1.) String literals are cached (because Strings are immutable):
class MyCode {
public static void main(String[] args) {
String a = "foo";
String b = "foo";
System.out.println(a == b); // true <-- caching!
System.out.println(a.equals(b)); // true
}
}
d.2.) Strings resulting from string operations are not cached
class MyCode {
public static void main(String[] args) {
String a = "foo";
String b = "" + a;
System.out.println(a == b); // false <-- no caching for String b
System.out.println(a.equals(b)); // true
}
}
Another example -- the "new" operator:
class MyCode {
public static void main(String[] args) {
String a = "foo";
String b = new String("foo");
System.out.println(a == b); // false <-- no caching for String b
System.out.println(a.equals(b)); // true
}
}
d.3.) ... unless the string operation is performed at compile-time
class MyCode {
public static void main(String[] args) {
String a = "foo";
String b = "f" + "o" + "o";
System.out.println(a == b); // true <-- still caching!
System.out.println(a.equals(b)); // true
}
}
d.4.) Though we won't study them until next lecture.... Integers (the wrapper class, as opposed to primitive integer types) are sometimes cached, too (for values in [-128, +127] that are autowrapped)
e) The Moral of the Story
* Use "==" without worries for integers and booleans.
* Do not use "==" with other types (unless you are certain it is
appropriate, and then Be Careful!).
* For doubles, use your own static "approximatelyEquals" method:
approximatelyEquals(d1,d2)
* For objects, use the "equals" method: obj1.equals(obj2)
Polygon p1; p1 = new Polygon(); p1 = new Polygon(); // What happened to our first polygon?
See Figure 3.1 (p. 119), along with some additional methods:
Method Description charAt Returns the character at the given index of this string, where the first index is 0 and the last index is at (length()-1). For example:
String s = "abcd";
System.out.println(s.charAt(0)); // prints: a
System.out.println(s.charAt(1)); // prints: b
System.out.println(s.charAt(s.length()-1)); // prints: d
A common mistake is to use length() rather than (length()-1) as the last index. This is one type of off-by-one error. For example:
String s = "abcd";
System.out.println(s.charAt(s.length())); // DOES NOT WORK -- off-by-one error!
Compile and run this. Read the error carefully. It says StringIndexOutOfBoundsException, and even tells us that the offending index is 4 (whereas the largest legal index is 3 for the string "abcd").compareTo Note: In Java, we would like to compare two strings the way we compare to numbers. That is, something like this:
Unfortunately, you cannot use relational operators (<, <=, >=, >) with strings, and while you can use equality operators (==, !=) with strings, you generally should not do so as they often do not work as expected. Instead of these operators, you should use the compareTo method described here and the equals method described below.
This method compares "this" string to a second string (which we will call "that" string). The comparison is lexicographic, which basically means that it works the way words are sorted in the dictionary. Returns a negative number if "this < that" -- that is, if "this" string would occur in a dictionary prior to "that" string. Returns 0 if "this" equals "that". And returns a positive number if "this > that". For example:
System.out.println("abc".compareTo("def")); // prints -3, so "abc" < "def"
System.out.println("abc".compareTo("abc")); // prints 0 , so "abc" equals "def"
System.out.println("def".compareTo("abc")); // prints 3 , so "def" > "abc"
The comparison uses Unicode values. As Unicode 'Z' is less than Unicode 'a', we see that all uppercase letters occur before the lowercase letters:
System.out.println("ABC".compareTo("abc")); // prints -32, so "ABC" < "abc"
System.out.println("Z".compareTo("a")); // prints -7 , so "Z" < "a"
Also, as Unicode '9' is less than Unicode 'A', we see that all digits occur before the uppercase or lowercase letters:
System.out.println("123".compareTo("ABC")); // prints -16, so "123" < "ABC"
To continue, we see that all whitespace characters occur before digits and uppercase or lowercase letters:
System.out.println(" ".compareTo("123")); // prints -17, so " " < "123"
Finally, we see that punctuation and other characters occur somewhat unpredictably:
System.out.println("%".compareTo("123")); // prints -12, so "%" < "123"
System.out.println("~".compareTo("xyz")); // prints +6 , so "~" > "xyz"
Again, it is important to remember this rule:Do not use relational or equality operators with strings. Instead, use the compareTo and equals methods.
compareToIgnoreCase This method works the same as compareTo, except that it ignores case (as its name implies), so that uppercase letters are considered equal to lowercase letters. For example:
System.out.println("ABC".compareToIgnoreCase("abc")); // prints 0, so "ABC" equals "abc"concat Returns a new string -- the result of concatenating the argument to the end of "this" string:
System.out.println("ABC".concat("def")); // prints ABCdef
This method is not often used, as we can achieve the same result using string concatenation:
System.out.println("ABC" + "def"); // prints ABCdefcontains Returns the boolean true if "this" string contains the argument, and false otherwise:
System.out.println("ABC".contains("BC")); // prints true
System.out.println("ABC".contains("CB")); // prints false
System.out.println("ABC".contains("AC")); // prints false
In the last example, we see that "ABC" does not contain "AC" -- even though "A" and "C" are contained, they are not adjacent, so "AC" is not contained in "ABC".endsWith Returns the boolean true if "this" string ends with the argument, and false otherwise:
System.out.println("ABC".endsWith("BC")); // prints true
System.out.println("ABC".endsWith("C")); // prints true
System.out.println("ABC".endsWith("")); // prints true
System.out.println("ABC".endsWith("B")); // prints falseequals Returns the boolean true if "this" string equals the argument, and false otherwise:
System.out.println("ABC".equals("ABC")); // prints true
System.out.println("ABC".equals("AB")); // prints false
System.out.println("ABC".equals("abc")); // prints falseequalsIgnoreCase This method works the same as equals, except that it ignores case (as its name implies), so that uppercase letters are considered equal to lowercase letters. For example:
System.out.println("ABC".equalsIgnoreCase("abc")); // prints trueindexOf Returns the starting index where the argument first occurs in "this" string, or -1 if it does not occur. Note that the argument can be either a char or a string. For example, here we find where chars occur:
System.out.println("ABC".indexOf('A')); // prints 0
System.out.println("ABC".indexOf('B')); // prints 1
System.out.println("ABC".indexOf('D')); // prints -1
And here we find where strings occur:
System.out.println("ABC".indexOf("BC")); // prints 1
System.out.println("ABC".indexOf("CD")); // prints -1
Note that indexOf can take a second parameter, the fromIndex -- in this case, the method looks for the argument starting from that index (and so the method will not find the argument if it only occurs to the left of the index). For example:
System.out.println("ABCDBC".indexOf("BC",1)); // prints 1
System.out.println("ABCDBC".indexOf("BC",2)); // prints 4
System.out.println("ABCDBC".indexOf("BC",5)); // prints -1lastIndexOf Returns the starting index where the argument last occurs in "this" string, or -1 if it does not occur. Note that is argument can be either a char or a string. For example, here we find where chars last occur:
System.out.println("ABCAB".lastIndexOf('A')); // prints 3
System.out.println("ABCAB".lastIndexOf('B')); // prints 4
System.out.println("ABCAB".lastIndexOf('D')); // prints -1
And here we find where strings last occur:
System.out.println("ABCAB".lastIndexOf("AB")); // prints 3
System.out.println("ABCAB".lastIndexOf("CD")); // prints -1
Note that lastIndexOf can take a second parameter, the fromIndex -- in this case, the method looks for the argument starting from that index (and so the method will not find the argument if it only occurs to the right of the index). For example:
System.out.println("ABCDBC".lastIndexOf("BC",4)); // prints 4
System.out.println("ABCDBC".lastIndexOf("BC",3)); // prints 1
System.out.println("ABCDBC".lastIndexOf("BC",0)); // prints -1length Returns the length of the string -- that is, the number of characters in the string:
System.out.println("abcdef".length()); // prints 6
System.out.println("g h".length()); // prints 6
System.out.println("".length()); // prints 0replace Returns a new string resulting from replacing all occurrences of its first argument with its second argument. Note that the arguments can be either strings or chars. For example, here we will replace one char with another:
System.out.println("abcabc".replace('a','d')); // prints dbcdbc
And here we replace one string with another:
System.out.println("abcabc".replace("bc","e")); // prints aeae
You cannot replace a string with a char, or a char with a string:
System.out.println("abcabc".replace("bc",'e')); // will not compile!
Note that you can use this method to remove all occurrences of a string by replacing them with the empty string ("").
System.out.println("abcabc".replace("bc","")); // prints aa
Finally, note that you cannot remove all occurrences of a char by replacing them with the empty char (''), because there is no such thing!
System.out.println("abcabc".replace('c','')); // will not compile!
So, again: Even though there is an empty string (""), there is no empty char ('').startsWith Returns the boolean true if "this" string starts with the argument, and false otherwise:
System.out.println("ABC".startsWith("")); // prints true
System.out.println("ABC".startsWith("A")); // prints true
System.out.println("ABC".startsWith("AB")); // prints true
System.out.println("ABC".startsWith("BC")); // prints falsesubstring Returns a new string composed of characters from its first argument (the beginIndex) up to, but not including, its second argument (the endIndex). For example:
System.out.println("ABCD".substring(0,1)); // prints A
System.out.println("ABCD".substring(0,2)); // prints AB
System.out.println("ABCD".substring(1,2)); // prints B
System.out.println("ABCD".substring(1,3)); // prints BC
A common use of substring is to find a suffix -- that is, a substring from some beginIndex until the end of the string. Because the endIndex is not included in the string, we can use string.length() as the endIndex, as such:
System.out.println("ABCD".substring(2,4)); // prints CD
System.out.println("ABCD".substring(2,"ABCD".length())); // prints CD
Actually, suffixes are so commonly used that they have their own form of substring -- if you only include one argument, the beginIndex, then the method returns the suffix starting from this beginIndex:
System.out.println("ABCD".substring(2)); // prints CDtoLowerCase Returns a new string where all uppercase characters are converted to lowercase, and all other characters are unchanged. For example:
System.out.println("ABcd123".toLowerCase()); // prints abcd123toUpperCase Returns a new string where all uppercase characters are converted to lowercase, and all other characters are unchanged. For example:
System.out.println("ABcd123".toUpperCase()); // prints ABCD123trim Returns a new string which is the same as "this" string with leading and trailing whitespace omitted (but with all other whitespace included). For example:
String s = " ab cd ";
System.out.println("[" + s.trim() + "]"); // prints [ab cd]
See Figure 3.2 (p. 123)
import java.util.Random; class MyCode { public static void main(String[] args) { Random random = new Random(); int a = random.nextInt(); // in range [Integer.MIN_VALUE, Integer.MAX_VALUE] int b = random.nextInt(100); // in range [0,100) <-- exclusive! double d = random.nextFloat(); // in range [0,1) <-- exclusive! System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("d = " + d); System.out.println("Coin flip: " + (random.nextFloat() < 0.5)); System.out.println("Coin flip: " + (random.nextFloat() < 0.5)); } }
Note: The Math class is static. You do not create instances. You call the methods by prefacing them with "Math.". For example:
class MyCode { public static void main(String[] args) { int a = (int)(10 * Math.random()); // in range [0,10) <-- exclusive! int b = (int)(10 * Math.random()); // ditto System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("Math.max(a,b) = " + Math.max(a,b)); System.out.println("Math.min(a,b) = " + Math.min(a,b)); System.out.println("Math.pow(a,b) = " + Math.pow(a,b)); System.out.println("Math.sqrt(a) = " + Math.sqrt(a)); System.out.println("Math.random() = " + Math.random()); System.out.println("Math.random() = " + Math.random()); } }
See Figure 3.4 (p. 128), , along with some additional methods:
Method | Description |
Math.sqrt | Returns the square root of its argument. For example: System.out.println(Math.sqrt(5)); // prints 2.23606797749979 |
Math.random | Returns a random number between 0 (inclusive) and 1
(exclusive). For example: System.out.println(Math.random()); This prints a different random number every time you run it. |
Math.min | Returns the minimum of its two arguments. For example: System.out.println(Math.min(3,4)); // prints 3 System.out.println(Math.min(4,3)); // also prints 3 Note that the minimum of two ints is also an int, whereas the minimum of two doubles is a double. So we have: System.out.println(Math.min(3,4)); // prints 3 System.out.println(Math.min(3.0,4.0)); // prints 3.0 (not 3) |
Math.max | Returns the maximum of its two arguments. For example: System.out.println(Math.max(3,4)); // prints 4 System.out.println(Math.max(4,3)); // also prints 4 Note that the maximum of two ints is also an int, whereas the maximum of two doubles is a double. So we have: System.out.println(Math.max(3,4)); // prints 4 System.out.println(Math.max(3.0,4.0)); // prints 4.0 (not 4) |
Math.abs | Returns the absolute value of its argument. For example: System.out.println(Math.abs(5)); // prints 5 System.out.println(Math.abs(-5)); // also prints 5 Note that the absolute value of an int is also an int, whereas the absolute value of a double is a double. So we have: System.out.println(Math.abs(5)); // prints 5 System.out.println(Math.abs(-5.0)); // prints 5.0 (not 5) |
Math.ceil | Returns the "ceiling", or the smallest (closest to negative
infinity) integer that is greater than or equal to its argument.
For example: System.out.println(Math.ceil(2.01)); // prints 3.0 System.out.println(Math.ceil(2.00)); // prints 2.0 System.out.println(Math.ceil(1.99)); // prints 2.0
Note that the value computed by Math.ceil cannot be assigned
directly into an integer variable, because the value is actually a
double value that happens to be an integer. So: |
Math.floor | Returns the "floor", or the largest (closest to positive
infinity) integer that is less than or equal to its argument. For
example: System.out.println(Math.floor(2.01)); // prints 2.0 System.out.println(Math.floor(2.00)); // prints 2.0 System.out.println(Math.floor(1.99)); // prints 1.0
Note that the value computed by Math.floor cannot be assigned
directly into an integer variable, because the value is actually a
double value that happens to be an integer. So: |
(int) Math.round |
Returns the rounded integer, or the closest integer value to its
argument. For example: System.out.println(Math.round(2.50)); // prints 3 System.out.println(Math.round(2.49)); // prints 2 System.out.println(Math.round(2.01)); // prints 2 System.out.println(Math.round(2.00)); // prints 2 System.out.println(Math.round(1.99)); // prints 2 Note that, unlike Math.ceil and Math.floor, the value computed by Math.round is not a double. Curiously, it also it not an "int". Instead, it is a "long", which is a special kind of integer. This is a type of variable that we generally do not use. As such, it is recommended that you always convert the result of Math.round from a long to an int, by preceding the call with "(int)", as such: System.out.println((int)Math.round(2.50)); // prints 3 System.out.println((int)Math.round(2.49)); // prints 2 System.out.println((int)Math.round(2.01)); // prints 2 System.out.println((int)Math.round(2.00)); // prints 2 System.out.println((int)Math.round(1.99)); // prints 2
Note that the value computed by Math.round cannot be assigned
directly into an integer variable unless you convert it as just
described. So: |
Math.pow | Returns the value of the first argument raised to the power of
the second argument. For example: System.out.println(Math.pow(2,0)); // prints 1.0 (which is 2^0) System.out.println(Math.pow(2,1)); // prints 2.0 (which is 2^1) System.out.println(Math.pow(2,2)); // prints 4.0 (which is 2^2) System.out.println(Math.pow(2,3)); // prints 8.0 (which is 2^3) Note that we can use Math.pow to compute the square
root of a number: Note that the value computed by Math.pow cannot be assigned
directly into an integer variable, even when raising an integer to
an integer power, because the value is actually a double
value that happens to be an integer. So: |
Math.exp | Returns e (Euler's number, the base of the natural logarithms)
raised to the power of its argument. For example: System.out.println(Math.exp(1)); // prints 2.7182818284590455 (which is E^1) System.out.println(Math.exp(2)); // prints 7.38905609893065 (which is E^2) Note that we can use Math.pow with the
constant Math.E in place of Math.exp: Note however that double math is approximate, and so
computing Math.exp with Math.pow produces very close but
not identical results: |
Math.log | Returns the natural logarithm (base e) of its argument. That
is, the number x such that ex equals its argument. For
example: System.out.println(Math.log(Math.E)); // prints 1.0 (since e1.0 == e) System.out.println(Math.log(1)); // prints 0.0 (since e0.0 == 1) System.out.println(Math.log(0)); // prints -Infinity (since e-infinity == 0) System.out.println(Math.log(-1)); // prints NaN (since ex is never negative) You can use this method to compute the logab for any base a by applying this rule: logab = logeb / logea For example, the following line prints out the log381, which is the value x such that 3x == 81 (which is 4): System.out.println(Math.log(81)/Math.log(3)); // prints 4.0 (since 34.0 == 81) Actually, due to the approximate nature of double math, this prints out 4.000000000000001 rather than 4.0. Close enough! |
Math.log10 | Returns the base-10 logarithm of its argument. That is, the
number x such that 10x equals its argument. For example: System.out.println(Math.log10(100)); // prints 2.0 (since 102.0 == 100) System.out.println(Math.log10(0.01)); // prints -2.0 (since 10-2.0 == 0.01) As noted above, you can use Math.log to compute Math.log10, so this method is provided merely as a convenience. |
Note: in general, you do not need to know much trigonometry for this course. However, we will make simple use of some trig functions in our graphics programs, so these methods are included here mostly for reference purposes. | |
Math.sin Math.cos Math.tan |
These methods return the trigonometric
functions of their argument, which is an angle in radians. For
example: System.out.println(Math.sin(0)); // prints 0.0 System.out.println(Math.cos(Math.PI/3)); // prints (about) 0.5 System.out.println(Math.tan(-Math.PI/4)); // prints (about) -1.0 |
Math.asin Math.acos Math.atan |
These methods return the inverses of the
trigonometric functions -- that is, the "arcsine", "arccosine", and
"arctangent". They return an angle in radians. For example, we see
how the previous examples are inverted: System.out.println(Math.asin(0.0)); // prints 0.0 System.out.println(Math.acos(0.5)); // prints (about) π/3 System.out.println(Math.atan(-1.0)); // prints (about) -π/4 |
Math.toDegrees Math.toRadians |
These methods convert between degrees and
radians, where 180 degrees equals π
radians.. They are especially useful because many students are more
comfortable dealing with degrees than radians. For example: System.out.println(Math.toDegrees(Math.PI/3)); // prints (about) 60 System.out.println(Math.toRadians(-30)); // prints (about) -π/6 Naturally, these are often used in conjunction with the trigonometric functions. For example: System.out.println(Math.cos(Math.toRadians(60))); // prints (about) 0.5 System.out.println(Math.toDegrees(Math.acos(0.5))); // prints (about) 60 |
carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem - carpe diem