Primitive Types, Access & Use
Peter Komisar    ©     Conestoga College            v 5.8          2008


Recall the HelloPlanet class. So far we have dealt mostly
with issues that surround the class, putting classes into
packages, documenting them with Javadoc and passing
arguments in from the command line.

We did learn about legal identifiers and we can start using
them with the basic value types that Java supplies. Java
supplies a boolean, true false type, four integer types, two
floating point types and one character type. The 'char' type
was used, recall, to store escaped Unicode characters.


The scope of main( ) supplies an old-fashion test zone.


Let us preview one of these types, the 'int' type and show
it in an example. When Java is used, as in the HelloPlanet
example, simply with a main( ) method, (and no constructor.)
Java is in an 'old-fashioned', non-object-oriented mode.
This mode is great for displaying much about the inner
workings of the language.

Example

class Command
{
public static void main(String[] args)
{
      // all the area instead main can be
      // used as a black board to show
      // how the standard, non-object-oriented
      // features of Java work.
}
}


An Example With the 'int' Type


The primitives are basic Java values whose features
can be demonstrated inside the main( ) method. Let us
preview one of these types the 'int' type or integer type.

We create a couple of 'int' values in the code below
and add them, printing the result to console. Just as a
reminder, each of the int values have been given a legal
identifiers, in the following example it is  a , b  and  c .

Identifiers a  and  b have been declared to type  'int' and
each has been assigned a numeric value.  A third int,  c
has been declared and receives the results of an addition
operation performed on values stored in 'fields' a and b.


Example

class Command
{
public static void main(String[] args)
{
  int a = 1;
  int b = 2;
  int c = a + b;
  System.out.println("1 + 2  =  " + c );
}
}

In the following discussion many examples are shown
outside the context of a method in a program. We can
assume though,that they will behave as if in the same
context as the primitives shown above.



Signed, Twos Compliments Numbers    


When encountering the description of the integer
number types in Java, they are described
as 'signed,
twos compliments numbers'. A
signed type can store
positive and negative numbers. A signed type will have
it's possible range spread over a positive and negative
integer number range. For instance in a moment we
see a  byte may store any whole number between and
including -128 to 127.

The computer can store signed numbers by various
techniques. A common method used is called 'two's
compliment' . Imagine an older computer chip or perhaps
a simple embedded controller device that has a 4 bit
register or 4 'on-off' positions to store a number.

With 4 bits, the computer can count from 0 to 15. If we
had written a compact language for this chip, one number
type might be what is described as an 'unsigned 4 bit
number with a range of 24 or a total of 16 values. The
following example shows the binary representations of
the numbers from 0 to 15.


Example Showing Binary Numbers Using a 4 bit Register

0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111,
1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111     

What if instead we wanted to be able to create signed
numbers, both negative and positive? One approach
would be to designate the top bit of our 4-bit register to
represent the sign of the number represented. This would
cut approximately in half the range of positive numbers
we could represent however this would be compensated
for by the fact that now that limited range could be
extended in both the positive and negative directions.

Back to our 4-bit register, if the top bit was a 0 then
the remaining three bits could be used to represent the
numbers 0 to 7. 


Example

0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111 

// 0 to 7

A 4 bit Representation of Positive Numbers Using 2s Compliment

// counting down from 7 to 0  

 binary
 decimal
 0111
 7
 0110
 6
 0101
 5
 0100
 4
 0011
 3
 0010
 2
 0001
 1
 0000
 0


Setting the top bit to one would now be used to
represent the numbers from -8 to -1.

Example

1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111  

// - 8 to -1


4 bit Type Representation of Negative Numbers Using 2s Compliment

 

 binary
 decimal
 1111
 -1
 1110
 -2
 1101
 -3
 1100
 -4
 1011
 -5
 1010
 -6
 1001
 -7
 1000
 -8


Notice when overflow occurs and 1111 is reached this
number becomes -1.  For negative numbers to 'count'
you can
follow the zeros in the same way you followed
the ones for
positive numbers.  ( -2 adds a zero at the
first
digit column etc.)


Java Example of Overflow


The same thing happens with Java's twos compliment
numbers except the smallest type is the 8 bit byte.


Example

class Binary{
public static void main(String[] args){
    byte a=127;
    System.out.println(a); // 127, 01111111
    byte b=(byte)128;
    System.out.println(b); // -128 10000000
    // 255 is all ones and evaluates to -1
    byte c=(byte)255;
    System.out.println(c); // -1,  11111111
    }
}


The Offset

If there were no zero in our number systems, things
would be perfectly symmetrical. As it is the zero is the
first number on the positive side of system. In arrays
this first number is zero, the second one etc. The
presence of the zero is what leads to the index values
starting at zero and being called an 'offset'.

In the following example we start with the positive number
4. The binary value is 'inverted to generates a negative
three. Inversion is changing 1s to 0s and 0s to 1s.

// invert and add one

The value 1 is added to account for the offset introduced
by 0 we are left with the negative value of the original
positive number. This is how two's compliment works
and indeed how most computers today represent positive
and negative numbers.

Any twos compliment binary positive number can be
inverted and incremented by one to arrive at the negative
value for that number. We have been using a 4 bit register.

A Java 'byte' type has 8 bits. It will evaluate to 127  in
positive values. Attempting to evaluate to 128 changes
top most bit to a one making it a negative number. It
'overflows' to the value negative one.

The bigger the Java primitive type, the larger the range
of positive and negative numbers will be included


Example

0100   // binary 4
1011   // ~ inverted becomes binary for -5 in our 4 bit system.
   1   // to account for the offset introduced by 0, 1 binary is added
1100  // check the table above and now we have -4


An interesting aspect of the twos compliment system
is we get our original value back by following the same
process of inverting and incrementing by one the
negative number.

Example

1100     //  -4 in binary in our 4 bit type system
0011     // ~ inverted becomes binary for 3 in our 4 bit system.
   1    // to account for the offset introduced by 0, 1 binary is added
0100    // we are back to positive binary 4


If we steal ahead to introduce a few of Java's operators,
the 'inversion' and the 'increment' operators, we can
demonstrate how the computer uses twos compliment
to represent negative and positive numbers.


Example

class Twos
  {
  public static void main(String[] args)
    {
    int x=4;
    System.out.println("x is " + x);
    x= ~x;                 // inverting
    System.out.println("x inverted becomes " + x);
    x++;                 // incrementing
    System.out.println("Now x is incremented to become " +x);
    x= ~x;
    x++;
    System.out.println
    ("Inverting and incremented again returns x to the value " +x);
    }
 }

OUTPUT

C:\Documents and Settings\Peter.XP_STUDIO\My Documents\J1\Examples>java Twos
x is 4
x inverted becomes -5
Now x is incremented to become -4
Inverting and incremented again returns x to the value 4


Four of Java's primitive types types are signed, twos
compliment numbers.
 


The Primitive Types


The primitive types define the primary storage spaces
where numeric and character data are
held in a Java
program. The first thing to mention is there is nothing
primitive about
them in the sense of an Aztec harvest
ritual.

They are primitives in the sense that they 'prime' or
'atomic' elements of the language that cannot be broken
down to smaller
pieces. Practically, the primitives are
'prime' in the sense that memory cells in the computer
each have an address. Primitives, are stored directly in
memory in association with these addressed memory
cells.

// not primitive as in harvest rituals, rather as in prime number

In addition to numeric and character data, Java defines
the 'boolean' type for
storing true or false values. Four
integral number types are used to store different size

number ranges, or integral data. They are the 'byte',
'short', 'int' and 'long'. Java uses the
'char' type to store
single characters and the float and double types to store
floating
point numbers.

// Java defines a boolean, four integral types that are
// all signed two's
compliment numbers, an unsigned '
// char' type and two floating point
types, the float and
// the double.


Strong Typing, Types are the Same on All JVMs
Regardless of Platforms

Because Java source code is  compiled to run on the
Java Virtual Machine,
all Java primitive types will have
the same type definitions regardless of what operating
system and hardware they are running on. An 'int' type
will be always be 4 bytes long whether
it is run on an
Intel platform running Linux or Windows or on a 'Mac'

running Apple's latest operating system.

// JVM ensures all primitives have same properties

This fact is what allows Java to provide what is called
'strong typing', where all the types are mandated to
exact size specifications.
Strong typing is one of the
characteristic features of Java that makes it a more
secure
language to program in as variable type size
can't be used as an avenue to introduce
sinister code
into a Java program.


Summary of the Primitive Types

Following is a table which shows Java's primitive types.

Table Categorizing the Java Primitives
 
 Type  Values
 boolean  - holds the values 'true' or 'false'
 int, long,
 byte, short
 - hold integral values,
    { 1 , 2 , 3  }
 double,
 float
 hold real (floating point) numbers,
 { 1.1, 2.2, 3.3 }
 char   - holds character values,   {  'A ' }


Creating and Assigning Values to Primitive Variables

Variables in Java are stored and accessed in built-in 'low-level'
container types called 'primitives' which we described above,
namely boolean, int, long, byte short, double, float and char.
In a Java program, an legal identifier is picked and declared
to a one of the primitive types as in the following example.

Example   

boolean boo;   

// boolean type declaration


Values may be assigned to primitive type variables, using
the assignment operator, commonly known as the equal
sign.

Example   

boolean  boo = true; 

// declaration and assignment in one step

It is common to see assignments and declaration as above
in a single step but you will also encounter declarations
where assignments occur further inside the program.

Example   

boolean boo;
boo = true;

// declaration in one step followed by assignment in  a second step


Class Scope

To review a point made earlier, class scope is in the
zone defined by the curly brace that follows immediately
after the class name and the corresponding curly brace
at the end of the class, but not in zones defined by further
nested blocks, constructors or variables.

Consider the following class definition.

class Scope
         {
         // this is class scope
         Scope( )
             {
             // this is not class scope, rather
             // the local scope of a constructor

             }
         // a method
     void method( )
            {
             // this is not class scope, rather
            // the local scope of a method

            }
         // a block
             {
         // this is not class scope, rather
         // the local scope of a block

                }
          // here we are back in class scope
          // note methods and constructors are
         // defined in class scope

            }


Local Scope Variables

Variables that are defined inside the scope of a constructor,
method, or block are referred to as 'local' or 'nested' variables.
Local variables are not assigned default values. For example
if you declare a variable in the local scope or a method,
constructor or block, and do not assign it an explicit value,
with code that attempts to access that value,  the compile
will fail and a report like that shown in the following example
will result.

Example

class NestedVar
         {
                
byte method( )
            {
            byte bee;
            return bee;
            // code that accesses an unassigned local scope variable
            }
        
     public static void main(String[] args)
      {       
      }  
}    

 Output

[peter@localhost Examples]$ javac NestedVar.java
NestedVar.java:7: variable bee might not have been initialized
            return bee;
                   ^
1 error

If this declaration is made in class scope, then Java will
supply a default value for you. For instance the boolean
value above has a default value, 'false' . The following
table summarizes the default values for the primitive
types.

Default Values of Primitive Types

 Type  Default Values
 boolean   false
 int, long,
 byte, short
  0
 double, float   0.0
 char   space character



Class Variables are Marked 'static'


The following code shows a default value expressed for
a boolean type variable. Notice this variable is marked
static. Marking a variable static fixes that member as part
of the class definition and subsequently no new copies of
this member will be created in instances of this class.
Instances will refer back to this variable in the class
definition. The static keyword makes the variable a
'class' variable.

Java modifiers, such as 'static', do not effect the value
that is stored in a variable.

Example

class Primitives{
      static boolean boo;
     
      // note static methods like main are only
      // able to directly reference static variables

      public static void main(String [] args){
            System.out.println("\n Class scope default");
        System.out.println("__________________________");
            System.out.println("\n boolean type: " + boo + "\n");
     
        }
     }  

Output // Linux

$ java Primitives

 Class scope default
__________________________

 boolean type: false

 


Primitive Types in Detail



Java does Hex & Octal     // for reference

Java can work with number systems other than decimal.
Octal values are prefixed with a zero, 0. Hex values are
prefixed with zero, upper or lower case 'X'. ( 0X or 0x ).

class Hex
       {    // this is class scope
       public static void main(String[]args)
          {
           // hex example 
           int i = 0x11; // think 16 plus 1
           System.out.println(i);
           // octal example
           int k = 024; //  think 2 times 8, plus 4
           System.out.println(k);
          }
       }

Output 

17
20


boolean

The boolean type is used to store just two reserved values,
'true' or 'false'. These are the case sensitive literal values
for boolean types.
Number values cannot be assigned
to 'boolean'. Similarly boolean types can't be assigned

to other primitives including type 'char'. Almost all of
Java's flow control mechanisms use
tests for boolean
expressions to control where execution will continue in
a program.


Examples
 

boolean yes= true;      // compiles fine
yes=1;                       // won't compile, only true false values
int number=yes;         // also won't compile, can't cross assign


char

The char type is two bytes long and is used to store
Unicode characters. We saw it
earlier when talking
about Unicode and escape sequences. The char type
is unsigned
and as such has a range of 0 to 65,536.
A negative number can't be assigned to char type.

Char is in essence a numeric type and so can be
assigned to other number types. In
this case it is it's
numeric value that is stored and not the character
mapping of a Unicode character.

In reverse, the compiler will interfere if other numeric
types are being assigned to a char
variable unless
a cast is used. ( We demonstrate casting later in the
note. )

Example  

  char c='A';
  System.out.println(c);     // prints out the letter A
  int i=c;
  System.out.println(i );  // As an int it prints it's binary value, 65
  char c=65;
  System.out.println(c);  // Maps the 65 and prints out the letter A


Also recall the form used to make a 'char' assignment of
a Unicode character using the Unicode escape
sequence.


Example

 char A= '\u0041';    // Unicode escape for the character A.
                              //  Notice 41hex is 65 in decimal.

byte

The byte type is the first and smallest of the four signed,
two's compliment number types Java uses. The byte is
the smallest and uses a single byte or 8 bits to store it's
value. It is economical and well suited for storing the
numerical binary equivalents of legacy ASCII code.

The byte can store 256 values in the range -128 to 127.
As mentioned earlier, the zero on the positive side of the
range introduces an offset that makes the range seem to
be imbalanced, having one less positive number than
negative number.

Byte's range, as the other Java integral types, can also
be described in powers of 2, from -2 7  to  2 7- 1.

byte's range     

-128 --- 0 --- 127

//  2 7- 1  =  ( 2 * 2 * 2 * 2 * 2 * 2* 2 ) - 1


In computer 'think', using binary 0s and 1s, the number
eight is represented in a byte with the following bit pattern.

eight represented in the 8 bits of a byte      

0001000

The following statement, ended by a semi-colon, shows
a byte primitive variable named 'b' being declared to the
'byte' type and being assigned the numerical value, 127.


Example         
 

byte b = 127;     

// the upper range limit of byte
 

short

The short type is similar to the byte but twice as large.
The short is 16 bits or 2 bytes
long. It is a signed signed,
two's compliment number. It has a range of -32,768 to

32,767. The range of short can also be described in
powers of 2, from  -2 15  to  215- 1. 
 

short's  range   

-32,768--- --- 0 --- --- 32,767


Example    
 

short  b = 32767;      // the upper range limit of short
 

int

The int is the integer work horse of Java. It is similar to
short but twice as big again. It is 32 bits or 4
bytes long.
The int has a range of  -2147483648 to 2147482647,
(approximately + or -
2.1 billion.)

In powers of 2, int's range is -231  to  231- 1.

int's  range   

-2,147,483,648 --- --- --- 0 --- --- --- 2,147,483,647


Example    
 

int b = -2147483648;   // the lower range  limit of an int
 

long

The long primitive type is the final in the series of signed,
two's compliment integer types.
It is also the biggest
requiring the 64 bits of 8 bytes. It has a huge range of
approximately
plus or minus  9.2 billion, billion. This
range is expressed precisely in powers of 2 as -2 63  to 
2 63- 1.

long's  range

-9,223,372,036,854,775,808 -- 0 -- 9,223,372,036,854,775,807
 

Example          

long b = 9223372036854775807L;

// the upper range limit of long

Notice the L specifies a long literal. Otherwise the value
will default to an int. Upper or lower case can be used.
Using
uppercase prevents the L from being mistaken as
the number character 1.   // l

 

float

The float is the first of two floating point number types
Java uses. It is stored in 4 bytes. A floating point number
representation will default to double if the literal isn't
appended with a F as shown in the following example.

Example   

float num=673221F;

Using float without the F in the assignment will result in
an error. This is because, without the F, the compiler
assumes the number is the bigger type, a 'double' which
takes up more bytes in memory and is capable of a higher
degree of precision than a 'float'. When assigned to a float
a degree of precision may be lost so the compiler reports
this as is shown by the following code and output.


Example   

class FloatingPoint{
    public static void main(String[] args){      
       float f = 35.3; 
     // needs 'F' as in '35.3F'  or a cast to float
     // as in float f=(float)35.3;
     System.out.println( f );
     } 
  }   

Output  // Linux

$ javac FloatingPoint.java
FloatingPoint.java:6: possible loss of precision
found   : double
required: float
      float f = 35.3;
                ^
1 error

We can cast the value to a float, (we describe casting
later) or be sure to include the 'F' designation immediately
following the number.

The float can be supplied with a literal value or using
floating point notation. The range of float specified in
floating point notation is ~ +/-  3.4E38. That's a potential
to store a number with 38 trailing zeros. Compare that
to long's 18 zeros and you see float can store a much
larger number than long.

The floating point notation must not have spaces between
the initial value, the exponent symbol E and the number
of zeros after the decimal point. ( The ' e ' can be upper
or lower case.)


Example
     

float f = 3.2E14F;

// double is generally a more practical choice on modern PCs.


Today's CPUs have large registers so using float won't
necessarily be faster than using double. The float type
may be useful when a large amount of numerical data is
being stored and there is a need to conserve memory.


double

The Java double is like the float, however, where the float
uses
four bytes, the double "doubles" the float and uses
eight bytes to hold it's floating point number. The double
holds a value that may have 308 trailing zeros. To put this
in perspective, Peter Van der Linden, in his popular Java
text, 'Just Java' mentions that the number of cubic
centimeters in the known universe
is a number with an
exponent value E82. The following example is very close
to the limit allowed by a double. (For instance
1.798E308 doesn't compile and is reported to be 'too big'.)

Example

class DoublesLimit
         {
 
     public static void main(String[] args)
      {       
       
      double d = 1.797E308;
      System.out.println("double's limit: " + d );

      // assigning -1.797E308 works too
      
      }  
}     
     
The float & double Follow IEEE754  Specifications

The float type as well as the double follows the rules
specified by the IEEE, Institute of Electrical and Electronic
Engineers in the Specification numbered 754. This
specification provides definitions for items such as a
floating point divide of 0.0 by 0.0.

Example  

float f=0.0f/0.0f;
System.out.println( f );      

// will print to screen NaN.

The IEEE specifies other constants used by Java
'float' and 'double' types such as the constant values
NEGATIVE_INFINITY & POSITIVE_INFINITY for each
of float and double types. These values are stored in
a special set of utility classes for numbers called
wrapper classes that are defined for each primitive
types. We look at the wrappers later in the course.

Examples 

// Max and Min values are similarly obtained

The following table summarizes the information we
just covered describing the primitive types.
 

Table Summary of the Primitive Types
 
 primitive   bits  bytes  type  range range in
exponents

 literals
 boolean   8  1   boolean  false & true
 true & false 
 char  16  2  unsigned
 number
  0
 to
 65,535, 



to   
2
16
 use single 
quotes,
'x'
 byte   8   1  signed,
 two's 
compliment
 -128
  to
  127 


-2 7 
to  
2
7- 1
 use int literals that 
 fall into byte range
 short  16  2  signed,
 two's
 compliment

-32,768
to
32,767, 


 -215  
to  
2
15- 1
               " "
 int  32  4  signed,
 two's
 compliment
 ~ 
+/- 2.1 billion 

 
-231  
to  
2
31- 1
 
 long  64   8  signed,
 two's
 compliment
 ~
+/- 9.2 billion,
          billion

 

-2
63   
to  
2
63- 1
suffix with an L
(uppercase for
clarity)
(defaults
 to int )
 float  32  4  floating 
 point *
 ~ +/- 3.4E38 
 ~ +/- 340
billion,
billion,
billion,billion

 suffix with an
 F
(defaults to
 double)
 double  64   8  floating 
 point *
 ~ +/- 1.7E308 
// astronomical +


*as per IEEE standard #754



Assignment  and Conversion

 
Assignment is the simple case where a number or a
variable is used with an assignment operator to place
a value in another variable.

Example

byte bee = 7;    

// the value 7 is assigned to the byte variable b


byte boo = bee; 

// the value contained in the variable bee is assigned to byte variable boo


Conversion

We mentioned earlier that a char type could be assigned
to another numeric type but not the
other way around,
where a number type is assigned to a char. We noticed
too that when a 'char' is stored as in 'int' it displays as
a number
not a character. That is because the 'char'
value was converted to an 'int'. When one type of

variable is assigned to another type, the value is
converted to the type of the variable that is
receiving
the assignment. This process is called conversion.

// Conversion --> when one type is assigned to another
// the value is converted to the type of the receiving variable

The General Rule, Widening Conversion are Legal

There is a general rule that states that assignments are
always legal if the assignment results
in a widening
conversion. What this means is a two-byte type can
always be assigned to
a  4-byte type and a 4-byte can
always be assigned to an 8-byte type etc.  The reverse
is not allowed as there is a loss of precision. The
following example shows a legal assignment which is a
widening conversions.

Example 

short too = 77;
int foor = too;

// generally, assignments are legal if the result is a widening conversion

Exceptions to the Rule

There are always exceptions to general rules! For instance
boolean can't participate in any kind of cross assignment.

A byte cannot be assigned to the 'char' type though the
char is twice as wide as a byte. A 'potential loss of precision'
is reported by the compiler. This makes sense if you recall
'char' type is not signed and therefore doesn't have the
potential to store bytes negative numbers.

The following schematic is a facsimile of diagrams that
can be found in the excellent text, Heller & Robert's 'Java
Certification Guide' which has been released in several
versions tracking versions of the Java JDK.  It shows the
order of legal assignment. Anything
on the left can be
assigned to anything on the right. Nothing can be assigned
to 'char' or byte type.
 

Diagram Showing Legal Assignments All
Resulting in Widening Conversions

byte --> short -->
                  int --> long--> float--> double
          char -->

// note boolean absence

Summary of Assignment Rules

The implications of the diagram are:


The rule depicted in the above diagram is demonstrated
in the following code sample.


Example

class Conversions{
  public static void main(String[]args){
    byte b=1;
    short s=b;
    // char c=s;  error: possible loss of precision
    // short s=c; error: possible loss of precision
    int i=s;
    long l=i;
    float f=l;
    double d=f;
   
    System.out.println(d);
    }
  }


Casting and Promotion


While the compiler permits widening conversions it does
not allow the reverse where a loss of precision occurs.
This is called a
narrowing conversion. That is you can't
assign
a double to int, or a short to a byte. You can
however force this conversion using a
cast. A cast is
a type of operator that allows a type to be forced to
another type,
specified inside round brackets.

Example    

int i = 127;
byte b =(byte)  i;      

// ok! still within range
// narrowing conversions are not assignable and require a cast


Cast Values May Not Be Meaningful

Casting doesn't guarantee that the value stored will be
meaningful. No information will be
lost as long as the type
receiving the cast has the range to hold the value it is
being assigned.
A long holding the value 44 can be cast
to a byte and the byte will hold the 44 with no loss
of
information. On the other hand, if a long has the value
444 and it is cast to a byte and
stored in a byte the value
stored there will now be meaningless as bytes that held
part of
the information describing the number will have
been truncated. Only the lowest byte
information will have
been transferred.

 

Example   

int i = 128;   
// one too many to be meaningfully assigned to a byte type

byte b =(byte)  i;
// creates the binary for the lowest number in byte range, -128


Truncation Caused By Casting

Consider what happened here. In the first example the
int would have four bytes to
store 127 as in the following
binary representation of the number. (The spaces just

provide visual organization. ) When the int was cast to
the byte the top three bytes
would have been truncated
and we still have a correct representation of the number

in memory.
 

127 as an' int' in binary

00000000  00000000  00000000  0111111

After the cast  
                           
                        
                           |  0111111
 
// OK no information lost

In the second case the int would have four bytes to store
128 as shown in the following
representation. This time
when the int was cast to the byte and the the top three
bytes
are truncated a meaningless value is stored.
Though meaningless, it is still logical. The
following
example shows how 128, as an int, is still a positive
value while interpreted as
a byte it becomes the lowest
possible negative number for a byte type, -128.

 

128 as an 'int' in binary

00000000  00000000  00000000  10000000

After the cast                             
 

                                                               
  |  10000000
// creates the byte value,  -128                                   


The following code snippet demonstrates this sort of
value truncation.

Example                                  |

class Trunk{
  public static void main(String[]args){
    
    long l=127L;
    byte b=(byte)l;
    System.out.println("Byte holds long value: " + b);

    l=128L;
    b=(byte)l;
    System.out.println
    ("The byte holds a truncation of the long value: " + b); 
   }
 }

Arithmetic Promotion

The following example looks like it should work
but fails!


Example
 

short a=5;
short b=3;
short c= a + b;

This is because the compiler promotes types before
doing arithmetic operations on them.
Both the short
values are promoted to the int type before they are
added. This is called
'arithmetic promotion'. The two
alternatives to make the code in the example run is
to
cast the results of the add back to short or change
the receiving variable type to an int.


Operation Related  Promotions

The general rule is that, whether passing parameters
into methods or doing operations with
operators, values
that are less than an int will undergo a
n arithmetic
promotion to an int value.

Example   

short c=(short)(a + b);      //  or
int c= a + b;

The second part of arithmetic promotion is if an int or
narrower value is combined in an
arithmetic operation
with a wider type, such as a long or double, the smaller
type will be
promoted to match the larger type.
 

Example

short aShort=44;
long aLong= 22L;
long longToo= aLong * aShort;

// The variable that receives the addition has to be long
// as the short is promoted to long



String Promotion & the Overloaded + Operator


If a numeric type is passed into a System.out.println
statement the number appears to be written to
screen.
The only reason this is works is that there are
several
versions of the println method available, one of which
takes an int value and convert
it to a String value.

Example

System.out.println(99);

// a version of println( ) converts the int to a String type

The following doesn't work, because the constructor
expects the value to be passed in as a String type,
"2001".

Example 

JTextField field = new JTextField( 2001 );   

// doesn't compile

Passing in an int to the constructor is the wrong type.
Beside using the String literal form, "2001",
a 'fudge'
can be used as follows.  

'Fudge' That Promotes a Number to a String

"" + 2001

// "" + 2001 works because of the one case of operator
//    overloading in Java for the + operator

The latter form, where an empty string is added to a
numeric literal works because the + operator is the
one case in Java. where an
operator is overloaded to
perform two functions.
Aside from adding it also does
the job of concatenating String values.

Example

String together = " Put it " + " Together ";

The operator also will promote a primitive type to it's
String representation. This is shown again in a variation
in the following example
.

Example   

int i=11;
String mix = " The number is: " + i;

This will print out " The number is 11 ". Here the  +
operator promotes the
primitive type to a String
representation of the type.



Self Test                        Self Test With Answers


1) If a two's compliment procedure was applied to the
   following byte, which of the following numbers would
   be generated.

    00001001            // binary representation of an byte

 a)  -9
 b) -10
 c)  -7
 d)  -8

2) Which of the following types must be suffixed with a letter
    or otherwise will default to another values.
     a ) byte
     b ) char
     c ) double
     d ) long

3) True or False. Boolean cannot be assigned but may be
    cast to the char type.
  True / False

4) True or False. A byte may be assigned to a char type
   True / False    


5)  Which of the following can represent the largest number.
       a ) float
       b ) int
       c ) long
       d ) char

6) True or False. The following will compile.   True / False

      float f = 654.3;   

7) Using the following variables in assignment, which of the
   following assignments will
not compile.
    
char c=" " ;

short s = 3;
byte b = 2;

int i = 4;

a) s = b;
b) i = c;
c) s = c;

d) i = s;
 
 

 8 ) Using the following variables in assignment, which of the following casts
      will not compile? ( Try and answer these first from your understanding.
      Then test your answers by compiling inside a main method.) 
 

short s =223;
double d = 333.08;

int i = 412;

boolean boo;

char c=' ';

a) s = (short) d;
b) c = (byte ) i;
c) s = (byte) i;
d) i =  (int) s;
 

9) Which of the following types is needed to store the results of the following expression.

     short s = 21983;
     double d  = 22;
     ___ variable =  s  + d;

     a) float
     b) short
     c) int
     d) double

10) The number in the following expression, ( 890 + " skiers " ) is promoted which
      of the following types.
      a) short
      b) int
      c) String
      d) char


Exercise

Using the System.out.println statement and basic arithmetic
operations execute the following instructions.

1) Create a new class called Primitives or something like that.
 In class scope create a variable for each primitive type which
 is declared but not assigned. (Mark each variable with the static
 modifier so it is recognized by the static main( ) method).

2) Inside main( ), use a System.out.println statement for each
    default value and print the defaults to console.

Example 

System.out.println("The default value of a char is " + char );

Example

class Primitives{
   static boolean boo;
    static byte b;
    // etc.
 
public static void main(String[] args){
 System.out.println("boolean: " + boo);
 System.out.println("byte: " + b);
  // etc.
}
}


3) Next, within main( ), locally, create a set of two each, of
the primitive types, using identifiers like minChar or maxChar
and assign each the minimum and maximum values for the
range of the type.

// you could also declare these variables
in class scope

Hint:
1 ) You can experiment and find the max and min values.
2 )  You can calculate the max and min values using the
formulas noted above describing the ranges. You might
use
3) You can use the constants described in the associated
   wrapper classes but it is probably more rewarding to use
    methods described in 1 ) or 2 )

example       Double.MAX_VALUE

Example  

byte byteMin = -128


4) Use println statements to output these values to console.


5) Use Scientific View of the Calculator that comes with
    your OS to confirm that the maximum values are what
    was predicted as a power of 2.

// Record values and or simply report if the values were the same or not.

6) Demonstrate all the legal assignments by assigning a
   byte to a short, a short to an int etc. ( You don't need
   to do 'every' legal assignment, just the smaller to the
   next larger up etc.. )

  byte --> short --> int --> long--> float--> double
            char -->


7) Assign a value that is one more than the maximum
    that each of the type variables can hold. Report what
    happens.

// Do this for two or three types to find out what happens

8) Now repeat 6 ) using a cast to force the type to receive
   a value greater than the type can hold. Is the value meaningful?

Example 

byte  bee =  (byte)128;


9) Show all legal casts by doing the reverse of the actions
 done in question 6. (Cast the type down to next smaller type. )

Optional

10) Demonstrate that arithmetic promotion occurs by adding
  two values which are of types that are narrower than an int.
 Show the promotions that occur when types equal and larger
 than int are used together.

( This is proven if one eliminates an error by providing an int
 to receive the results of a promotion. )