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 |
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
Four of Java's primitive types types are signed, twos
compliment numbers.
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
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
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
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, |
0 to 216 |
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 215- 1 |
" " |
int | 32 | 4 | signed,
two's compliment |
~
+/- 2.1 billion |
-231
to 231- 1 |
|
long | 64 | 8 | signed,
two's compliment |
~
+/- 9.2 billion, billion |
-263 to 263- 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 + |
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);
}
}
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 an 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
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.
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