Chapter3

Un article de Sometimes Kitties Think Too.

SCJP


Sommaire

Chapter 3 - Operators & Assignments



Stack & Heap

       + instance (objects) variables live on heap
       + local variables live on stack


Literals

       + a source code representation for a value of a string object
       + arrays  are the only non-primitive type that have a literal representation
       + all integer literals may be proceeded by a 'L' at the end
       --decimal - base10
       --hexadecimal - base16, a preceeding '0x' is required
       --octal - contain only 0-7, begins with a '0' (up to 21 digits n.i. 0)
               e.g. int oct = 0231;
       --floating Point Literal
               + every floating point is implicitly a double(64 bit)
               + compiler won't allow a floating point number to be assigned to a "float" w/o explicit cast
               + no need for a explicit cast for doubles ('D') because it is the default behavior
       --character (unsigned 16 bit representation)
               + represented by a single character in quotes or the Unicode in quotes
                 or an integer with a cast

Assignment

       + e.g. of an implicit cast (widening conversion):    double d = 100D;
       + bytes, shorts, chars, when assigned a larger literal, will be implicitly cast down
       + 2 bytes, if added together will be int sized because of the implicit cast.  Therefore
    byte c = a + b;   <---- illegal (where a,b are bytes)
    int c = a + b;    <---- correct
       + can assign a subclass of the declared type (but not superclass)
    Bar b = new Foo();  // where Bar extends Foo    <---- illegal 
    Foo f = new Bar();  // where Bar extends Foo    <---- correct
               e.g.  Foo f = new Bar();  // where Bar extends Foo
               variable           - bit holder
               reference variable - bit of an address for how to get to the object
               primitive          - value is equivalent to a number
       + narrowing requires an explicit cast
               e.g. 
     float f = 100F;
     int i   = (int) 1222222;
       + when there is a loss of precision by casting, only the most significant left-most bits are used
               byte b = (byte) 128;
                       since 128 is a 32 bit int, the leftmost 24 bits are removed
                       and 10000000 is left.  2's complement notation means that
                       the bits are flipped and then 1 is added.
                       resulting in -128
       + need explicit casting when there is a loss of precision.
               e.g.
                byte b = 0x3;
                b =+ 1;   ----should be----> b = (byte) (b + 1)

Conversion of Primatives

+ an automatic conversion will happen in the following scenarios:

  • Assignment
    % A non-boolean may be converted to another non-boolean type, provided the conversion is a widening conversion.
    % A non-boolean MAY NOT be converted to another non-boolean type, if the conversion would be a narrowing conversion.
    % A boolean MAY NOT be converted to any other type.
 
  • Method call (Implicit casting)
     - a method will accept any argument that's narrower than the signature parameter
  • Arithmetic promotion
     % All arithmetic expressions are promoted to the wider of the operands.
     % The promotion is at least to int, even if no int operand appears.
     % these rules don't apply to "++" and "--"
  • Explicit casting
      - can widen or narrow (except for boolean)

Equality

  + .equals() 
         will return false even for Wrapper classes that look like they have the same value.  
         Why?
         Because the equals() method does a instanceof test
equals()?
ObjectA WrapperA primitive
ObjectB IS-A ?? false false
WrapperB false false maybe
primitive false maybe compiler error
  + ==
         this compares references.  Is the reference to the same object?
         Compiler error will result if the objects being compared are different
         
         However, if a primitive and wrapper class are being compared, autoboxing will allow
         the comparison to go forward
         
         == will return true when a wrapper object and a primitive have the same values
         (Boolean, Byte, Character, Short, Integer) because one will be unboxed
  + == special cases (See Below)
         When Wrapper classes wrap primitives that are not immutable, then equality doesn't hold true

Rounding

   + integer arithmetic operations are floored, so 9/10 is floored to 0
   + printf() rounds numbers in the normal way

Scope

       + static variables have longest scope and last as long as the class is loaded
       + instance variables last as long as instance lives

Unitialized Variables

       + local variables (stack) have no default initialization
       + instance variables get default initialization values
        variable type   |       default value
        ------------------------------------------------------
        object          |       null
        byte, short     |
          long, int     |       0
        float, double   |       0.0
        boolean         |       false
        char            |       '\u0000'
       + array elements are ALWAYS given default values

Automatic Variables

       + automatics are local variables
       + unitialized local primatives will result in a compiler error
       + local references are NOT default initialized (to null)
   + Java is pass-by-value (for all variables running within a single VM)
       - an object's reference is passed with copy of the reference bits
       - a primative is passed with the a copy of the value of the primative


Arrays

       + are objects that store multiple variables of the same type
       + arrays live on the heap
       + arrays can be declared, constructed and initialized
       + array constructors need to specify a size.
               however, this is legal:
                       int[][] example = new int[3][];
       + negative numbers not allowed in array indices and the numbering starts at '0'
       + ArrayIndexOutOfBoundsException is a >>runtime<< exception
       + single public variable, "length"
       + anonymous arrays --> int[][] anonArray = { {1,2,3}, {3,4,5}, {5,6,7} };
               because the middle arrays have no reference variables
       + primitive arrays can hold any type that can be implicitly promoted to the
               declared type of the array , e.g. a int[] can hold shorts, char, ints
       + arrays of object references can contain subclass or interface of array type
         arrays of interfaces can contain IS-A classes, or implementors of the interface
       + primitive arrays cannot be reassigned to other reference types other than what the array contains
               int[] this = new int[3];
               char[] that = this;  <--illegal


       + not so restrictive with arrays of objects.
       + interface reference can be assigned to an array of objects implementing that interface

Initialization Blocks

       + there exist static and instance initialization blocks
       + they run when a class or instance is initialized and after all super-constructors have run
       + don't take arguments and don't return anything
       + they run in the order they appear

Wrapper Classes & Boxing

       + there is a wrapper class for every Java primitive
       + most wrapper classes (except Character) take String as a constructor arg
               which throws NumberFormatException if there's a problem
       + Boolean wrapper will be false unless either a true (boolean value) 
         or "true" (String) are used in the constructor argument...
       wrapper classes:
             java.lang.Boolean
             java.lang.Character
             java.lang.Long
             java.lang.Float
             java.lang.Integer
             java.lang.Double
             java.lang.Byte
             java.lang.Short
       
       XXX valueOf(String s)
            STATIC
               + second method to constructing a wrapper class.  
                 Takes String argument and radix (base)
         
       xxx parseXXX(String s)
            STATIC
               + static method, throws NumberFormatException
               + returns named primative.  e.g. Double.parseDouble("3.12") --> double
       
       String toString(XXX)
           STATIC
               + returns string of the primative that's wrapped.  
                 Long and Integer have a static toString( base10, radix)
           
       xxx xxxValue()
           
               + converts wrapped numeric to primative e.g. short f = f2.shortValue();


       static    instance method

Autoboxing

       + compiler automatically unboxes and unwraps the object reference (in the process creating a new wrapper)
       + == and != do not act the same
    
         != works as expected
       +  == will return true when a wrapper object and a primitive have the same values
          (Boolean, Byte, Character, Short, Integer and Long)  and are of same type (no widening)
          because one will be unboxed
       + equals() returns false when comparing between differnt Wrappers (Even if the same primitive value)
       + BUT equals() will return true if comparing the same primitive value.
         e.g.
             int i = 10;
             Integer II = new Integer(10);
             II.equals(i);        ---> true


       + NullPointerExceptions can happen with wrapper objects

Overloading

       widening - for example expanding a byte to fit a int argument
       + JVM uses the method with the narrowest argument type that's wider than the parameter
       + widening takes precedence over boxing (because of pre-Java5 code)
       + widening takes precedence over var-args
       + auto-boxing takes precedence over var-args

Widening Reference Variables

       + is legal to widen the parameter supplied to a method, as long as it passes the IS-A test
         because the parameter will only be asked to do the superclass things within the method
       + cannot widen between wrappers, e.g. Integer cannot fit into a Long's place
       + can only box-then-widen  NOT widen-then-box


        Precedence
        -----------------------------
        (highest)       ^                widen
                        |                 ^
                        |               auto-box
                        |                 ^
        (lowest)        |               var-args

Garbage Collection

       + JVM decides when it is run
       + can request it by calling System.gc
       + GC run in low priority daemon thread
       + no guarantee on implementation, platform specific
       + all non-String objects are eligible for collection when no live thread can access it
       + garbage collecting is performed by Runtime class
             Runtime.getRuntime() ---> Singleton
             Runtime.getRuntime().gc()

Making objects Eligible for Garbage Collection

       + once a reference is assigned a null value it is eligible for collection
       + local variables can be GC once the method has completed
       + if a ref variable is reassigned, the old object is eligible for GC
       + Exceptions thrown in the finalize() method are ignored by the GC
       + finalize() can be used to free up other resources besides memory.  Like files, network connections
       + Object's finalize() throws an Exception


Special Behavior

Normally, when the primitive types are boxed into the wrapper types, the JVM allocates memory and creates a new object. But for some special cases, the JVM reuses the same object.

The following is the list of primitives stored as immutable objects:

  • boolean values true and false
  • All byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007F

so.........

  Integer small1 = 20;
  Integer small2 = 20;
  small1 == small2 ? -----> true

whereas.....

  Integer big1 = 200;
  Integer big2 = 200;
  big1 == big2 ? -----> false

Note: this special behavior only applies to Wrapper classes and '=='!

Question


1. When you initialize an object manually or by default to null, does that mean it's eligible for GC? 2. Does auto-boxing imply both directions 3. what's an example of box-then-widen that doesn't violate widening between wrappers