Week 2 Primitive types, operators, colors, random numbers, and conditionals TYPES All data in Java has either - REFERENCE type: all objects, and NULL - PRIMITIVE type: everything else (not objects, can't send them messages) PRIMITIVE TYPES Primitive numeric types: byte, char, short, int, float, long, double These are 8, 16, 16, 32, 32, 64, and 64 bits long, respectively. Use primarily int and double. float and double both called "floating point". All the other numeric primitive types are "integer types" One other primitive type: boolean OPERATOR PRECEDENCE AND ASSOCIATIVITY What does 2 + 4 / 2 mean? Ans: 2 + (4 / 2), not (2 + 4) / 2. How about 8 / 4 / 2? Ans: (8 / 4) / 2, since / associates left to right (L to R) Operator precedence and associativity (Big Java: appendix A3 lists all operators in decreasing order of precedence, with all those in the same associativity group of equal precedence). Here are the ones we've seen so far: unary + and -, cast, R to L * / % (remainder) L to R (binary) + - L to R = assignment R to L Associativity: Doesn't matter for associative operations like +. (Floating point + isn't exactly associative.) arithmetic operators overloaded on integers and floating points. double diameter = 2.0; is an example of a VARIABLE DECLARATION. In general, they are of the form = ; or ; In the latter case, without an INITIALIZER, the variable gets a default value determined by its type if it is a field. If it is a local variable, the type checker uses a somewhat crude algorithms to confirm that it is assigned before it is used. Generally, the type of the expression must be the same as the declared type, but there are some IMPLICIT CONVERSIONS. E.g. we could have written double diameter = 2; instead of using 2.0, because there is an implicit WIDENING CONVERSION from integer to double in an assignment (including declarations, as here, and parameter passing, as we shall see). Widening and narrowing conversions. - implicit: assignment conversion and (arithmetic) promotion (coercion), e.g. double twoPi = 2 * 3.14159; // promotion double zero = 1 / 2; // yikes! double half = 1.0 / 2; - explicit: casting int intArea = (int)(diameter * twoPi); Conversions between primitive types (other than boolean) that do not loose any information are allowed and implicit. Conversions that loose information are never implicit, but are allowed (other than those involving boolean). Exercise: what is the type and value (if well typed) of the expression (int)-1.0/2*55.0 ? Increment and decrement operators ++ and --, either postfix or prefix. Good style: use only as statements. There are also assignment operators: +=, etc. COLORS The (ADDITIVE) PRIMARY COLORS are red, green, and blue, corresponding to the three types of cones in our eyes and the three types of phosphors in color monitors. This is often called the RGB COLOR SYSTEM. RGB colors are represented in Java as three bytes, representing red, green, and blue, with values from 0 to 255 (2^8 - 1). new Color(int red, int green, int blue) (0, 0, 0) is black, (255, 255, 255) is white. How many possible Java colors are there? RANDOM NUMBERS objectdraw.RandomIntGenerator randGen = new RandomIntGenerator(int first, int last) returns a new generator of random numbers in the range [first, last]. ****** SpiroGraph.java import objectdraw.*; import java.awt.*; // mouse drags draw lines radiation from central points mouse down point public class SpiroGraph extends FrameWindowController { // generator for RGB color values private static final RandomIntGenerator COLOR_GEN = new RandomIntGenerator(0, 255); private Location lineStart; // point from which lines radiate private Color lineColor; // randomly generated color // create the random number generator public void begin() { canvas.setBackground(Color.BLACK); canvas.clear(); // necessary for the background color } // save the starting point public void onMousePress(Location point) { lineStart = point; lineColor = new Color(COLOR_GEN.nextValue(), COLOR_GEN.nextValue(), COLOR_GEN.nextValue()); System.out.println(lineColor); } // draw lines as the user drags the mouse about public void onMouseDrag(Location point) { new Line(lineStart, point, canvas).setColor(lineColor); } } ****** CONDITIONALS Dragging diagram with lastPoint and point for onMousePress, onMouseDrag start, and onMouseDrag end. ****** WhatADrag1.java import objectdraw.*; import java.awt.*; // croc.gif resized from Microsoft Design Galary wmf image // http://dgl.microsoft.com/mgo1en/preview.asp?bInSelBasket=false // &nMedia=1&tName=j0215228&tExtension=wmf&nSize=21&nDuration=0&tCaption=CGL%20Preview public class WhatADrag1 extends FrameWindowController { // starting position for image private static final int IMAGE_LEFT = 200; private static final int IMAGE_TOP = 100; private VisibleImage image; // visible image to be dragged private Location lastPoint; // point where mouse was last seen // make the iamge public void begin() { image = new VisibleImage(this.getImage("croc.gif"), IMAGE_LEFT, IMAGE_TOP, canvas); } // save starting point and whether point was in image public void onMousePress(Location point) { lastPoint = point; } // if mouse is in image, then drag the image public void onMouseDrag(Location point) { if (image.contains(lastPoint)) { double dx = point.getX() - lastPoint.getX(); double dy = point.getY() - lastPoint.getY(); image.move(dx, dy); lastPoint = point; } } } ****** The getImage method is sent to the CURRENT INSTANCE, the one executing the current method, indicated by the keyword THIS. As a shorthand, if the object of a method call is the current instance, "this." can be omitted, so the call could be getImage("croc.gif") instead of this.getImage("croc.gif"). getImage returns an object of type java.awt.Image, but such images are not visible by themselves. For this we create an instance of objectdraw.VisibleImage. In onMouseDrag, there are LOCAL VARIABLE DECLARATIONS of dx and dy. Local variable declarations are syntactically like field declarations, except that they cannot have static or visibility (e.g. public, private) modifiers. The SCOPE of local declarations is the block in which they are enclosed (in this case the method body): they are not visible elsewhere. They are created when the block is entered and their storage is reclaimed when control leaves the block. contains(point) => contains(lastPoint) introduces a bug! contains check is a bit time consuming: use grabbed boolean variable, set in onMousePress, tested in onMouseDrag ****** WhatADrag.java import objectdraw.*; import java.awt.*; // croc.gif resized from Microsoft Design Galary wmf image // http://dgl.microsoft.com/mgo1en/preview.asp?bInSelBasket=false // &nMedia=1&tName=j0215228&tExtension=wmf&nSize=21&nDuration=0&tCaption=CGL%20Preview public class WhatADrag extends FrameWindowController { // starting position for image private static final Location IMAGE_LOCATION = new Location(200, 100); private VisibleImage image; // visible image to be dragged private Location lastPoint; // point where mouse was last seen private boolean grabbed = false; // whether the image has been dragged by the mouse // make the iamge public void begin() { image = new VisibleImage(getImage("croc.gif"), IMAGE_LOCATION, canvas); } // save starting point and whether point was in image public void onMousePress(Location point) { lastPoint = point; grabbed = image.contains(point); } // if mouse is in image, then drag the image public void onMouseDrag(Location point) { if (grabbed) { double dx = point.getX() - lastPoint.getX(); double dy = point.getY() - lastPoint.getY(); image.move(dx, dy); lastPoint = point; } } } ****** Next we add a wall on the right. Want to stop if image runs into it. add COULD USE image.getWidth() INSTEAD: private static final int IMAGE_WIDTH = 70; private static final int WALL_X = 350; private static final int WALL_Y = 0; private static final int WALL_WIDTH = 20; private static final int WALL_HEIGHT = 400; in begin() new FilledRect(WALL_X, WALL_Y, WALL_WIDTH, WALL_HEIGHT, canvas); in onMouseDrag double dx = point.getX() - lastPoint.getX(); double dy = point.getY() - lastPoint.getY(); image.move(dx, dy); if (image.getX() + IMAGE_WIDTH > WALL_X) image.move(-dx, -dy); Numeric comparison operators. ==, not = Limits == for floats and strings. Use Math.abs(x - y) < epsilon and string1.equals(string2) If mouse is moved fast, stops short of wall. Move it back just the right amount. double distancePastWall = image.getX() + IMAGE_WIDTH - WALL_X; // if image has collided with the wall, move it back if (distancePastWall > 0) image.move(-distancePastWall, -dy); Strange behavior if moved fast past wall. Ungrabb it if it hits the wall. if (distancePastWall > 0) { image.move(-distancePastWall, -dy); grabbed = false; } Add OUCH! message. private Text ouch; // hurting text in begin ouch = new Text("OUCH!", 0, 0, canvas); // initial position is ignored ouch.hide(); in onMousePress ouch.hide(); in onMouseDrag if (distancePastWall > 0) { image.move(-distancePastWall, -dy); grabbed = false; ouch.moveTo(image.getX(), image.getY() + OUCH_Y_OFFSET); ouch.show(); } Add a second wall. Use boolean || operator and nested if. double distancePastRightWall = image.getX() + IMAGE_WIDTH - RIGHT_WALL_X; double distancePastLeftWall = image.getX() - (LEFT_WALL_X + LEFT_WALL_WIDTH); // if image has collided with the wall, move it back if (distancePastRightWall > 0 || distancePastLeftWall < 0) { if (distancePastRightWall > 0) image.move(-distancePastRightWall, -dy); else image.move(-distancePastLeftWall, -dy); // distancePastLeftWall < 0 ****** WhatADragWalls.java import objectdraw.*; import java.awt.*; // croc.gif resized from Microsoft Design Galary wmf image // http://dgl.microsoft.com/mgo1en/preview.asp?bInSelBasket=false // &nMedia=1&tName=j0215228&tExtension=wmf&nSize=21&nDuration=0&tCaption=CGL%20Preview public class WhatADragWalls extends FrameWindowController { private static final int IMAGE_LEFT = 200; private static final int IMAGE_TOP = 100; private static final int IMAGE_WIDTH = 70; private static final int LEFT_WALL_X = 0; private static final int LEFT_WALL_Y = 0; private static final int LEFT_WALL_WIDTH = 20; private static final int LEFT_WALL_HEIGHT = 400; private static final int RIGHT_WALL_X = 350; private static final int RIGHT_WALL_Y = 0; private static final int RIGHT_WALL_WIDTH = 20; private static final int RIGHT_WALL_HEIGHT = 400; private static final int OUCH_Y_OFFSET = -20; private VisibleImage image; // visible image to be dragged private Text ouch; // hurting text private Location lastPoint; // point where mouse was last seen private boolean grabbed = false; // whether the image has been grabbed by the mouse // make the image and walls public void begin() { new FilledRect(LEFT_WALL_X, LEFT_WALL_Y, LEFT_WALL_WIDTH, LEFT_WALL_HEIGHT, canvas); new FilledRect(RIGHT_WALL_X, RIGHT_WALL_Y, RIGHT_WALL_WIDTH, RIGHT_WALL_HEIGHT, canvas); image = new VisibleImage(getImage("croc.gif"), IMAGE_LEFT, IMAGE_TOP, canvas); ouch = new Text("OUCH!", 0, 0, canvas); // initial position is ignored ouch.hide(); } // save starting point and whether point was in image public void onMousePress(Location point) { lastPoint = point; grabbed = image.contains(point); ouch.hide(); } // if mouse is in image, then drag the image public void onMouseDrag(Location point) { if (grabbed) { double dx = point.getX() - lastPoint.getX(); double dy = point.getY() - lastPoint.getY(); image.move(dx, dy); double distancePastRightWall = image.getX() + IMAGE_WIDTH - RIGHT_WALL_X; double distancePastLeftWall = image.getX() - (LEFT_WALL_X + LEFT_WALL_WIDTH); // if image has collided with the wall, move it back if (distancePastRightWall > 0 || distancePastLeftWall < 0) { if (distancePastRightWall > 0) image.move(-distancePastRightWall, -dy); else image.move(-distancePastLeftWall, -dy); // distancePastLeftWall < 0 grabbed = false; ouch.moveTo(image.getX(), image.getY() + OUCH_Y_OFFSET); ouch.show(); } else lastPoint = point; } } } ****** If statement - Syntax. - Test expression must have boolean type. - Then and else statements are often blocks of statements. - Flow charts with and w/o else clause. - Indent then and else parts. - Exception: else if doesn't introduce new nesting level. - Flow chart of else if. There is also a conditional operator - example: min of x and y: x < Y ? x : y same as Math.min(x,y) SWITCH STATEMENT Use only the following restricted form: switch (EXPRESSION) { case CONSTANT_EXPRESSION : STATEMENT ... break; ... default : STATEMENT ... } - Can only switch on ints or types that can be widened to int (e.g. chars). - End every clause (except maybe the last: a DEFAULT clause) with a break statement. - End every switch statement with a default clause. - It is easy to forget the break statements. On the other hand, switch is faster for many-way branches. BOOLEAN OPERATORS Boolean expressions comparison operators: ==, !=, <, >, <=, >= - logical operators: !, &&, and || (in decreasing precedence order) - && and || operators associate to the left and don't evaluate right-hand arguments if result is known. - usually used in control constructs, but can appear as arguments, return values (boolean valued methods), etc. Common mistake, things like: i < j < k Instead use: i < j && j < k || (or) is inclusive: it means one or the other or both. Be careful about the difference between == and =. > boolean a = false; > a == true false > a = true true > a == true true & and | are bitwise operations on integer values as well as strict boolean operator. XOR is the name of the exclusive-or operation: one or the other but not both. EXERCISE: write boolean xor(boolean a, boolean b) [same as a ^ b] ~~~~ Text omitted from pre-lecture notes ~~~~ EXERCISE: write boolean inOrder(double x, double y, double z), where the order may be ascending or descending. ~~~~ Text omitted from pre-lecture notes ~~~~