Java defines two types of data types: primitive types and objects. Topics covered in this lecture are
The following primitive types are supported:
byte
- a 8 bit signed integer. Can represent any value between -128 and 127short
- a 16 bit signed integer. Can represent any value between -32,768 and of 32,767 int
- a 32 bit signed integer. Can represent any value between -$2^{31}$ and $2^{31}$ - 1 long
- a 64 bit signed integer. Can represent any value between -$2^{63}$ and $2^{63}$ - 1float
- a 32 bit floating point number. A single-precision 32-bit IEEE 754 floating point double
- a 64 bit floating point number. A double-precision 64-bit IEEE 754 floating pointchar
- a single 16-bit Unicode characterboolean
- a boolean value (true
or false
)Integer literals are just the numbers themselves, e.g., 4
, or -15
. Alternatively, integer values can be specified in binary by prefixing the value with 0b
or hexadecimal by prefixing the value with 0x
.
// a short constant
return (short) 1;
// an int constant
return 1;
// a long constant
return 1L;
// 15 in hexadecimal
return 0xF;
// 15 in binary
return 0b1111;
Numbers in binary can become quite long. For convenience Java allows _
characters to be inserted into the number to separate parts of a long number. These underscores do not change the semantics of the number.
// 15 in binary as an int (31 bit)
return 0b00000000_00000000_00000000_00001111;
Negative numbers using 0b
and 0x
are writting with prefix -
. Note that internally one bit of information is required to store the sign. For example, only 7 bits of information are available store the value. In Java the largest positive byte values is internally represented as 10000000
(128) while negative numbers are stored using the two's complement of a number. The two's complement adds one to the number and then inverts all the bits. For example, consider -1
. We have -1 + 1 = 0
. Zero in binary is 00000000
. Then inverting the bits we get 11111111
.
// -15 in binary
int b = -0b0001111;
return Integer.toBinaryString(b); // -15 + 1 = -14. 14 in binary (32 bits) is 000000 00000000 00000000 00001110. Inverting all the bits we get the number shown below.
Floating point constants are identified by the decimal point, e.g,. 3.0
is a floating point literal. By adding a suffix f
or d
such literals can be identified as float
or double
. Scientific notation (speciying $10^n$ as en
) is also allowed.
// a float constant
return 3.0f;
// a double contant
return 3.0; // alternatively 3.0d
// scientific notation
return 1.5e5;
There are only two boolean constants true
and false
.
// a boolean constant
return true;
Variables of a primitive type are declared using <type> <name>
. For instance, long x;
declares a variable called x
of type long
. Variables can be either initialized during declaration or explicitly at any time they have been declared. Using a variable before it has been initialized may lead to a compile time error (we will revisit this later and learn under which circumstances it is necessary to initialize a variable).
// no intialization -> compile time error
int x;
return x;
// initialization during declaration
int x = 1;
return x;
// initialization after declaration
int x;
x = 15;
return x;
The Java language defines several operators. Operators cannot be overloaded in Java. That is it not possible to redefine the semantics of such operators. The following operators are defined for primitive types (we will introduce additional operators when covering Classes and Objects later).
+
is addition and -
is subtraction. Both are binary (two inputs), e.g., 3 + 4 = 7
*
is multiplication, /
is division, %
is modulo, e.g., 12 % 7 = 5
+
and -
can also be used as unary operators (operators with one input), e.g., -x
if x
is a variable of type int
boolean
==
is equality (note that two equal signs are used, not one). Equality returns true
if the compared values are equal<
, >
, <=
, >=
, relational operators smaller, larger, smaller than or equal, and larger than or equal!
is not
($\neg$)&&
is logical and
($\wedge$)||
is logical or
($\vee$)&
, |
, and ^
are bit-wise or
, and
, and xor
<<
, >>
shift left and shift right. This preserves the sign of the number. That is, after shifting a positive number will still be positive while a negative number will be negative.<<<
, >>>
. logical shift left and right. This just treats the value as a bit array and is oblivious to whether it is negative or positive.=
- basic assignment. Assigns a the value of an expression to a variable like this: <variable> = <expr>;
+=
, -=
, *=
, /=
, %=
, &=
, ^=,
|=
<<=
, >>=
, >>>=
. The structure is still <variable> X= <expr>
. This is a syntactic shortcut to assigning the target of the assignment to the result of applying the binary operator to the target and the result of the expression expr
, e.g., x += 3
is equivalent to writing x = x + 3
.++
and --
increment (decrement) the value of a variable by 1. These operators exist as prefix and suffix versions, e.g., ++x
(prefix) and x++
(postfix). Both versions return the value of the incremented/decremented variable. The difference is that the prefix operator returns the value after applying the increment/decrement, which the postfix operator returns the value before the operation.<condition> ? <expr1> : <expr2>
. If <condition>
evaluates to true
then the operator evaluates to <expr1>
, otherwise it evaluates to <expr2>
.// arithmetic operators
return (12 % 7) + 3;
int x = 3;
int y = 7;
int z = x + y;
return z;
float f1 = 3.0f;
float f2 = 5.1f;
float f3 = f1 + f2;
return f3;
double d1 = 3.0;
double d2 = 4.1;
double d3 = d1 + d2;
return d3;
int x = 3;
return -x;
return 3 == 3;
return 3 == 5;
return 3 < 5;
return 'a' == 'a';
// relational operators on chars use lexicographical order
return 'a' < 'b';
return 'b' < 'a';
// relational operators are not defined for type boolean
return false < true;
return !true;
return true || false;
return true || true;
return false || false;
return true && true;
return true && false;
return ((!false) && true) || false;
boolean x = (true && true);
boolean y = x || false;
return y;
// shifting
byte b = 0b00000001; // 1 in binary representation
b <<= 3; // shifting to the left by 3 bits
return b == 0b00001000; // now we have 8
// bit and
byte b1 = (byte) 0b00101000;
byte b2 = (byte) 0b00100000;
return Integer.toBinaryString(b1 & b2);
// bit or
byte b1 = (byte) 0b00101000;
byte b2 = (byte) 0b00100000;
return Integer.toBinaryString(b1 | b2);
// bit not
byte b1 = (byte) 0b10101000;
return Integer.toBinaryString(~b1);
// using ints
int b = 0b01000000000000000000000000000000;
return Integer.toBinaryString(~b);
// prefix (return the value after increment)
int x = 0;
return ++x; // return 1
// suffix (return the value before increment)
int x = 0;
return (x++ + 15); // returns 0
// since 5 is larger than 3 the condition is true and 15 is returned
return (5 > 3) ? 15 : -15;
// another example, here the condition evaluates to false and the second value is returned
return (5 < 3) ? 15 : -15;
Like most programming languages Java defines a precendence order among its operators. This order determines how expressions using multiple operators are interpreted if the execution order is not made explicit through parentheses. You already know this from basic algebra, e.g., 3 + 2 * 7
is equal to 3 + (2 * 7)
and not (3 + 2) * 7
because it is generally understood that multiplication has precedence over addition. Java's precedence rules are summarized in the table below.
Operators | Precedence |
---|---|
postfix | expr++ expr-- |
unary | ++expr --expr +expr -expr ~ ! |
multiplicative | * / % |
additive | + - |
shift | << >> >>> |
relational | < > <= >= instanceof |
equality | == != |
bitwise AND | & |
bitwise exclusive OR | ^ |
bitwise inclusive OR | | |
logical AND | && |
logical OR | || |
ternary | ? : |
assignment | = += -= *= /= %= &= ^= |= <<= >>= >>>= |
For example, as expected multiplication has higher precedence than addition.
int x = 3 + (2 * 7);
return x;
int x = 3 + 2 * 7;
return x;
Casting allows values of one data type to be translated into another data type. In Java casted as written as (<newtype>) <expression>
. For example,
int x = 4;
double y = (double) x;
Here we are casting the int
value 4
as a double
(floating point number).
int x = 4;
double y = (double) x;
return y;
short b = 0b0000000100010011;
char c = (char) b;
return c;
char c = 'a';
return (short) c;
char c = 'A';
return (short) c;
char c = 'A';
short b = (short) c;
b += 32;
char c2 = (char) b;
return c2;