1. Literals
    1. Char
      1. char a = 'a'; char letterN = '\u004E'; // The letter 'N' char c = (char)70000; // The cast is required; 70000 is // out of char range char e = -29; // Possible loss of precision; needs a cast char f = 70000 // Possible loss of precision; needs a cast char c = '\"'; // A double quote char d = '\n'; // A newline
    2. Boolean
      1. boolean t = true; // Legal boolean f = 0; // Compiler error! int x = 1; if (x) { } // Compiler error!
    3. Int
      1. Decimal (10)
        1. int length = 343;
      2. Hex(16)
        1. int y = 0x7fffffff;
      3. Octal(8)
        1. int eight = 010;
    4. Double
      1. double d = 11301874.9881024;
      2. double g = 987.897; // ok as literal is a double by default
      3. float f = 23.467890; // Complier error (possible loss of precision)
      4. float g = 49837849.029847F; // OK; has the suffix "F"
  2. Memory Allocs
    1. Stack
      1. Local Vars
    2. Heap
      1. Inst Vars
      2. Objects
    3. Memory Allocation
      1. Topic
  3. Assignment Operators
    1. Primitive Assignments
      1. int x = 7; // literal assignment int y = x + 2; // assignment with an expression // (including a literal) int z = x * y; // assignment with an expression
      2. byte b = 27; equivalent to byte b = (byte) 27; // Explicitly cast the int literal to a byte
      3. byte a = 3; // No problem, 3 fits in a byte byte b = 8; // No problem, 8 fits in a byte byte c = b + c; // Should be no problem, sum of the two bytes // fits in a byte
      4. The compiler knows the rule about int-or-smaller expressions always resulting in an int. It would have compiled if we'd done the explicit cast: byte c = (byte) (a + b);
      5. Primitive Casting
        1. int a = 100; long b = a; // Implicit cast, an int value always fits in a long
        2. float a = 100.001f; int b = (int)a; // Explicit cast, the float could lose info
        3. float f = 32.3; // won't compile - must either cast the value or append an f to the end of the literal
        4. float f = (float) 32.3; //all 3 compile fine float g = 32.3f; float h = 32.3F;
        5. Also get compile error if attempt to assign value to variable that is too big byte a = 128; // byte can only hold up to 127 Fix this with a cast : byte a = (byte) 128;
    2. Compound Assignment Operators
      1. byte b = 3; b += 7; // No problem - adds 7 to b (result is 10)
      2. byte b = 3; b = (byte) (b + 7); // Won't compile without the cast, since b + 7 results in an int
    3. Assigning one primitive variable to another
      1. int a = 6; int b = a; Changing the value of b does not affect a
    4. Ref var assignments
      1. Button b = new Button(); Makes a reference variable named b, of type Button Creates a new Button object on the heap Assigns the newly created Button object to the reference variable b
      2. can also use a reference variable to refer to any object that is a subclass of the declared reference variable type public class Foo { public void doFooStuff() { } } public class Bar extends Foo { public void doBarStuff() { } } class Test { public static void main (String [] args) { Foo reallyABar = new Bar(); // Legal because Bar is a subclass of Foo Bar reallyAFoo = new Foo(); // Illegal! Foo is not a subclass of Bar } } The rule is that you can assign a subclass of the declared type, but not a superclass of the declared type!
    5. Variable Scope
      1. 4 basic scopes
        1. Static vars - have longest scope Survive as long as the class
        2. Instance - next longest lived Live as long as instance
        3. Local - survive as long as the method
        4. Block - survive as long as block is executing
    6. Topic
    7. Local Obj Refs
      1. null reference is not the same as an uninitialized reference Locally declared references can't get away with checking for null before use, unless you explicitly initialize the local variable to null import java.util.Date; public class TimeTravel { public static void main(String [] args) { Date date; if (date == null) // does not compile System.out.println("date is null"); } }
    8. Assigning one obj ref to another
      1. Obj refs point to the same obj so changes in one affect the other (exception is with Strings)
  4. Passing variables into methods
    1. Objs
      1. When pass obj ref to method pass (1)COPY OF ref & (2)NOT the obj itself Therefore way to get to obj on heap.
      2. BUT - the method DOES have a ref to the EXACT obj on the heap!
    2. Primitives
      1. Pass by COPY - therefore changing the value in the method does not change the original var whose value was copied and passed in.
  5. Arrays
    1. Declaring Array
      1. Primitives
        1. int[] key; // brackets before name (recommended) int key []; // brackets after name (legal but less readable) spaces between the name and [] legal, but bad
      2. Obj Refs
        1. Thread[] threads; // Recommended Thread threads[]; // Legal but less readable
        2. Multi-Dimentional
          1. String[][][] occupantName; // recommended (2D) String[] ManagerName []; // yucky, but legal (3D)
      3. It is never legal to include the size of the array in your declaration int[5] scores; // will not compile!
        1. Floating Topic
    2. Constructing Array
      1. Create on the heap Must specify size
      2. int[] testScores; // Declares the array of ints testScores = new int[4]; // constructs an array and assigns it to the testScores variable Could also do this : int[] testScores = new int[4];
      3. Thread[] threads = new Thread[5]; This statement produces only 1 object - the array associated to the ref variable threads. This single object holds 5 Thread reference vars - BUT no Thread objects have yet been created and assigned to them.
      4. Remember - ALWAYS need a size when creating! int[] carList = new int[]; // Will not compile; needs a size
      5. NEW - will cause Super Constructors and Constructor to run.
    3. Initialising Array
      1. Animal [] pets = new Animal[3]; This creates 1 object on heap - with 3 null refs to Animal. To create the Animal objects: pets[0] = new Animal(); pets[1] = new Animal(); pets[2] = new Animal(); This puts 3 new Animal objects on heap and assigns them to 3 index positions in the pets array.
      2. Don't need to specify size for anonymous array (pg 230)
    4. Initialsation Blocks
      1. Run when class first loaded (STATIC Initialisation block)
      2. Run when class instance created (INSTANCE Initialisation block)
    5. class SmallInit { static int x; int y; static { x = 7 ; } // static init block { y = 8; } // instance init block }
    6. rules: ■ Init blocks execute in the order they appear. ■ Static init blocks run once, when the class is first loaded. ■ Instance init blocks run every time a class instance is created. ■ Instance init blocks run after the constructor's call to super().
      1. class Init { Init(int x) { System.out.println("1-arg const"); } Init() { System.out.println("no-arg const"); } static { System.out.println("1st static init"); } { System.out.println("1st instance init"); } { System.out.println("2nd instance init"); } static { System.out.println("2nd static init"); } public static void main(String [] args) { new Init(); new Init(7); } } produces: 1st static init 2nd static init 1st instance init 2nd instance init no-arg const 1st instance init 2nd instance init 1-arg const
      2. if you make a mistake in your static init block, the JVM can throw an ExceptionInInitializationError. Let's look at an example, class InitError { static int [] x = new int[4]; static { x[4] = 5; } // bad array index! public static void main(String [] args) { } }
  6. Wrapper classes & Boxing
    1. Provide a mechanism to "wrap" primitive values in an object so that the primitives can be included in activities reserved for objects, like being added to Collections,
    2. Provide an assortment of utility functions for primitives. Most of these functions are related to various conversions
    3. Subtopic 3
    4. Creating Wrapper classes
      1. All of the wrapper classes except Character provide two constructors: one that takes a primitive of the type being constructed, and one that takes a String representation of the type being constructed
        1. Integer i1 = new Integer(42); Integer i2 = new Integer("42"); or Float f1 = new Float(3.14f); Float f2 = new Float("3.14f");
      2. Character class has 1 constructor
        1. Character c1 = new Character('c');
    5. ValueOf() methods
      1. Two (well, usually two) static valueOf() methods provided in most of the wrapper classes give you another approach to creating wrapper objects
        1. Integer i2 = Integer.valueOf("101011", 2); // converts 101011 to 43 and assigns the value 43 to the Integer object i2 or Float f2 = Float.valueOf("3.14f"); // assigns 3.14 to the Float object f2
    6. Wrapper conversion utilities
      1. xxxValue()
        1. Use when you need to convert the value of a wrapped numeric to a primitive
        2. All no arg methods!
        3. Integer i2 = new Integer(42); // make a new wrapper object byte b = i2.byteValue(); // convert i2's value to a byte primitive short s = i2.shortValue(); // another of Integer's xxxValue methods double d = i2.doubleValue(); // yet another of Integer's xxxValue methods or Float f2 = new Float(3.14f); // make a new wrapper object short s = f2.shortValue(); // convert f2's value to a short primitive System.out.println(s); // result is 3 (truncated, not rounded)
      2. parseXxx() and valueOf()
        1. Both take a String as an argument
        2. Both throw a NumberFormatException (a.k.a. NFE) if the String argument is not properly formed
        3. Both can convert String objects from different bases (radix), when the underlying primitive type is any of the four integer types.
          1. ■ parseXxx() returns the named primitive.
          2. valueOf() returns a newly created wrapped object of the type that invoked the method.
          3. Examples: double d4 = Double.parseDouble("3.14"); // convert a String to a primitive System.out.println("d4 = " + d4); // result is d4 = 3.14 Double d5 = Double.valueOf("3.14"); // create a Double obj System.out.println(d5 instanceof Double); // result is "true" The next examples involve using the radix argument (in this case binary): long L2 = Long.parseLong("101010", 2); // binary String to a primitive System.out.println("L2 = " + L2); // result is: L2 = 42 Long L3 = Long.valueOf("101010", 2); // binary String to Long object System.out.println("L3 value = " + L3); // result is: L3 value = 42
      3. toString()
        1. All of the wrapper classes have a no-arg, nonstatic, instance version of toString(). This method returns a String with the value of the primitive wrapped in the object
        2. Double d = new Double("3.14"); System.out.println("d = "+ d.toString() ); // result is d = 3.14
        3. All of the numeric wrapper classes provide an overloaded, static toString() method that takes a primitive numeric of the appropriate type (Double. toString() takes a double, Long.toString() takes a long, and so on) and, of course, returns a String: String d = Double.toString(3.14); // d = "3.14"
        4. Integer and Long provide a third toString() method. It's static, its first argument is the primitive, and its second argument is a radix: String s = "hex = "+ Long.toString(254,16); // s = "hex = fe"
      4. toXxxString() (Binary, Hexadecimal, Octal)
        1. Take an int or long, and return a String representation of the converted number: String s3 = Integer.toHexString(254); // convert 254 to hex System.out.println("254 is " + s3); // result: "254 is fe" String s4 = Long.toOctalString(254); // convert 254 to octal System.out.print("254(oct) ="+ s4); // result: "254(oct) =376"
    7. AutoBoxing
      1. Previous to Java 5: Integer y = new Integer(567); // make it int x = y.intValue(); // unwrap it x++; // use it y = new Integer(x); // re-wrap it System.out.println("y = " + y); // print it Now, with new and improved Java 5 you can say Integer y = new Integer(567); // make it y++; // unwrap it, increment it, rewrap it System.out.println("y = " + y); // print it Both examples produce the output: y = 568
      2. Boxing, ==, and equals()
        1. equals() method is to determine whether two instances of a given class are "meaningfully equivalent
        2. In order to save memory, two instances of the following wrapper objects (created through boxing), will always be == when their primitive values are the same: ■ Boolean ■ Byte ■ Character from \u0000 to \u007f (7f is 127 in decimal) ■ Short and Integer from -128 to 127
      3. Where Boxing Can Be Used
        1. class UseBoxing { public static void main(String [] args) { UseBoxing u = new UseBoxing(); u.go(5); } boolean go(Integer i) { // boxes the int it was passed Boolean ifSo = true; // boxes the literal Short s = 300; // boxes the primitive if(ifSo) { // unboxing System.out.println(++s); // unboxes, increments, reboxes } return !ifSo; // unboxes, returns the inverse } }
    8. Overloading - made hard
      1. Be aware of widening: when an exact match isn't found, the JVM uses the method with the smallest argument that is wider than the parameter
      2. Boxing and Var-Args class AddBoxing { static void go(Integer x) { System.out.println("Integer"); } static void go(long x) { System.out.println("long"); } public static void main(String [] args) { int i = 5; go(i); // which go() will be invoked? } } The compiler will choose widening over boxing - therefore answer = long
      3. class AddVarargs { static void go(int x, int y) { System.out.println("int,int");} static void go(byte... x) { System.out.println("byte... "); } public static void main(String[] args) { byte b = 5; go(b,b); // which go() will be invoked? } } Compiler again chooses widening - therefore answer = int, int
      4. Boxing beats Var-Args - so Var-Args always loses
      5. NOT LEGAL to widen one wrapper to another (eg Integer to Long)
      6. class WidenAndBox { static void go(Long x) { System.out.println("Long"); } public static void main(String [] args) { byte b = 5; go(b); // must widen then box - illegal } }
      7. class BoxAndWiden { static void go(Object o) { Byte b2 = (Byte) o; // ok - it's a Byte object System.out.println(b2); } public static void main(String [] args) { byte b = 5; go(b); // can this byte turn into an Object ? Yes! } }
  7. Garbage Collection
    1. ■ For any given object, finalize() will be called only once (at most) by the garbage collector. ■ Calling finalize() can actually result in saving an object from deletion.