Series: Java Core for Beginners Lecture: 02 of 12 Topics: Primitive types · Reference types · Variables · Type casting · Operators · Strings
What Is a Variable?
A variable is a named container for storing a value in memory. When you write a program, you constantly need to hold pieces of information — a user’s age, a product price, whether a door is open or closed — and variables are how you do that.
In Java, every variable has three things:
- A type — what kind of data it holds (a whole number, a decimal, a true/false value, etc.)
- A name — how you refer to it in your code
- A value — the actual data stored inside it
Java is a statically typed language. This means you must declare the type of a variable when you create it, and that type cannot change for the lifetime of the variable. This is different from dynamically typed languages like Python or JavaScript, where a variable can hold any type of value at any time.
Static typing has a significant advantage: the compiler catches type mismatches before your program runs. If you declare a variable as an integer and accidentally try to store a name string in it, Java refuses to compile — you learn about the mistake immediately rather than discovering it as a bug in production.
Primitive Data Types
Java has eight primitive data types. These are the most basic building blocks — they hold simple values directly in memory and are not objects. Knowing these eight types and their characteristics is foundational to everything else in Java.
Integer types
These types store whole numbers (no decimal point).
| Type | Size | Range | Default value |
|---|---|---|---|
byte |
8 bits | −128 to 127 | 0 |
short |
16 bits | −32,768 to 32,767 | 0 |
int |
32 bits | −2,147,483,648 to 2,147,483,647 | 0 |
long |
64 bits | −9.2 × 10¹⁸ to 9.2 × 10¹⁸ | 0L |
int is your default choice for whole numbers. You reach for long only when a number might exceed roughly 2.1 billion — think timestamps in milliseconds, large financial calculations, or population counts.
int age = 25;
int temperature = -10;
long worldPopulation = 8_100_000_000L; // L suffix marks a long literal
Notice the underscore in 8_100_000_000L. Java allows underscores inside numeric literals to improve readability. The compiler ignores them — they are purely visual separators, like commas in a written number.
byte and short are rarely used directly in application code. They exist mainly to save memory when working with large arrays or binary data.
Floating-point types
These types store numbers with a decimal component.
| Type | Size | Precision | Default value |
|---|---|---|---|
float |
32 bits | ~7 significant digits | 0.0f |
double |
64 bits | ~15 significant digits | 0.0 |
double is your default choice for decimal numbers. It provides sufficient precision for most applications and is what Java’s math library methods return by default.
double price = 19.99;
double pi = 3.141592653589793;
float discount = 0.15f; // f suffix marks a float literal
Important: float and double use binary floating-point representation, which cannot represent all decimal fractions exactly. For example, 0.1 + 0.2 in floating-point does not equal exactly 0.3. This is not a Java quirk — it is a property of how IEEE 754 floating-point arithmetic works in virtually every programming language. For financial calculations where exact decimal precision is required, use java.math.BigDecimal instead.
System.out.println(0.1 + 0.2); // prints 0.30000000000000004
The boolean type
boolean stores one of two values: true or false. It is the foundation of all conditional logic in Java.
boolean isLoggedIn = true;
boolean hasPermission = false;
boolean in Java is not numeric — unlike C, you cannot use 1 or 0 in place of true or false. A boolean is only ever true or false.
The char type
char stores a single Unicode character, enclosed in single quotes.
char grade = 'A';
char symbol = '@';
char newline = '\n'; // escape sequence for a newline character
Under the hood, char is a 16-bit unsigned integer representing a Unicode code point (range 0 to 65,535). This means you can do arithmetic with characters, though it is rarely necessary:
char c = 'A';
System.out.println(c + 1); // prints 66 (the int value of 'B')
Common escape sequences for char and String
| Sequence | Meaning |
|---|---|
\n |
Newline |
\t |
Tab |
\\ |
Literal backslash |
\" |
Literal double quote (inside a String) |
\' |
Literal single quote (inside a char) |
Primitive types summary
Whole numbers: byte → short → int → long (increasing size)
Decimal numbers: float → double (increasing precision)
True/false: boolean
Single character: char
When in doubt: use int for whole numbers, double for decimals, boolean for flags, and char when you genuinely need a single character (though String is more common in practice).
Reference Types — A First Look
Beyond the eight primitives, everything else in Java is a reference type. Where a primitive variable holds its value directly, a reference variable holds a pointer — a memory address pointing to where an object lives on the heap.
You will study reference types in depth starting in Lecture 4 (Classes & Objects). For now, there are two you will encounter immediately.
String
String is the most commonly used reference type in Java. It represents a sequence of characters — text. String literals are enclosed in double quotes:
String name = "Alice";
String greeting = "Hello, World!";
String empty = "";
String is a class, not a primitive, but Java gives it special treatment. You can create string literals with double quotes without using the new keyword, and the + operator is overloaded to concatenate strings.
Arrays
An array is a fixed-size, ordered collection of values of the same type:
int[] scores = {95, 87, 72, 100, 88};
String[] days = {"Monday", "Tuesday", "Wednesday"};
You will cover arrays in full in Lecture 7. For now, know that they are reference types and that square brackets [] denote an array type.
null
Reference variables can hold a special value called null, meaning they point to nothing — no object has been assigned yet:
String message = null; // message points to nothing
Attempting to call a method on a null reference causes a NullPointerException at runtime — one of the most common errors in Java. You will learn strategies to avoid this in Lectures 10 and 12.
Variable Declaration and Initialization
Declaration
Declaring a variable reserves a named slot in memory for a value of a given type:
int score;
double salary;
boolean isActive;
At this point, the variables exist but have no assigned value. Attempting to use an uninitialized local variable before assigning it is a compile-time error in Java:
int count;
System.out.println(count); // ERROR: variable count might not have been initialized
Initialization
Initializing a variable assigns it its first value:
int score; // declaration
score = 100; // initialization
Declaration and initialization together
In practice, you almost always declare and initialize in a single statement:
int score = 100;
double salary = 55000.0;
boolean isActive = true;
char grade = 'B';
String name = "Alice";
The var keyword (Java 10+)
Since Java 10, you can use var instead of an explicit type when the compiler can infer the type from the assigned value. This is called local variable type inference:
var age = 30; // inferred as int
var name = "Alice"; // inferred as String
var price = 9.99; // inferred as double
var is purely a convenience — the type is still fixed at compile time. You cannot later assign a value of a different type. Also, var can only be used for local variables (inside methods) — not for fields, method parameters, or return types.
Use var when the type is obvious from context and repeating it would add noise. Avoid it when the type is not immediately clear from reading the right-hand side.
Naming rules and conventions
Java variable names must follow these rules:
- Must start with a letter, underscore (
_), or dollar sign ($) — not a digit - Can contain letters, digits, underscores, and dollar signs
- Cannot be a Java reserved keyword (
int,class,return, etc.) - Case-sensitive:
countandCountare different variables
By convention, use camelCase for variable names and make them descriptive:
// Poor names
int x = 25;
double d = 19.99;
// Good names
int customerAge = 25;
double productPrice = 19.99;
Constants with final
Adding the final keyword to a variable declaration makes it a constant — its value can be assigned once and cannot change afterward:
final double TAX_RATE = 0.08;
final int MAX_ATTEMPTS = 3;
TAX_RATE = 0.09; // ERROR: cannot assign a value to final variable TAX_RATE
By convention, constants are named in UPPER_SNAKE_CASE. Use final generously — it communicates intent (this value should not change) and can enable compiler optimizations.
Type Casting
Because Java is statically typed, you sometimes need to explicitly convert a value from one type to another. This is called casting.
Widening conversion (implicit)
A widening conversion moves a value to a larger type — no data is lost, so Java does it automatically:
int count = 42;
long bigCount = count; // int → long: automatic
double d = count; // int → double: automatic
float f = 3.14f;
double d2 = f; // float → double: automatic
The widening order for numeric types is:
byte → short → int → long → float → double
Any conversion that follows this left-to-right order is implicit.
Narrowing conversion (explicit cast)
A narrowing conversion moves a value to a smaller type. Data loss is possible, so Java requires you to write an explicit cast — a type name in parentheses:
double price = 9.99;
int truncated = (int) price; // explicit cast: double → int
System.out.println(truncated); // prints 9 (decimal part is discarded, NOT rounded)
long bigNumber = 1_000_000_000_000L;
int smallNumber = (int) bigNumber; // WARNING: data loss — value wraps around
System.out.println(smallNumber); // prints 727379968 (overflow)
The cast operator (int) tells the compiler: “I know this conversion might lose data — do it anyway.” This is your explicit acknowledgment of the risk.
Casting with char
char can be cast to and from int because it is stored as a numeric Unicode code point:
char letter = 'A';
int code = letter; // widening: char → int, prints 65
char back = (char) (code + 1); // narrowing: int → char, back = 'B'
System.out.println(back); // prints B
String conversion
Converting other types to String is done with String.valueOf() or by concatenating with an empty string:
int n = 42;
String s1 = String.valueOf(n); // "42"
String s2 = "" + n; // "42" — concatenation converts n to String
// Parsing a String to a numeric type
String input = "123";
int parsed = Integer.parseInt(input); // 123
double d = Double.parseDouble("3.14"); // 3.14
Operators
An operator is a symbol that tells Java to perform an operation on one or more values (called operands).
Arithmetic operators
| Operator | Name | Example | Result |
|---|---|---|---|
+ |
Addition | 5 + 3 |
8 |
- |
Subtraction | 5 - 3 |
2 |
* |
Multiplication | 5 * 3 |
15 |
/ |
Division | 5 / 2 |
2 |
% |
Modulus (remainder) | 5 % 2 |
1 |
Integer division truncates. When both operands are integers, / performs integer division and discards the remainder:
int result = 7 / 2; // 3, not 3.5
double result2 = 7.0 / 2; // 3.5 — one operand is double, so result is double
double result3 = (double) 7 / 2; // 3.5 — cast one operand to force double division
The modulus operator returns the remainder after division. It is extremely useful:
int remainder = 10 % 3; // 1 (10 = 3×3 + 1)
// Common use: check if a number is even
boolean isEven = (number % 2 == 0);
// Common use: wrap around a range (e.g., clock hours)
int hour = (currentHour + 1) % 24;
Assignment operators
| Operator | Equivalent to | Example |
|---|---|---|
= |
— | x = 5 |
+= |
x = x + n |
x += 3 |
-= |
x = x - n |
x -= 3 |
*= |
x = x * n |
x *= 2 |
/= |
x = x / n |
x /= 2 |
%= |
x = x % n |
x %= 3 |
int score = 100;
score += 10; // score is now 110
score -= 5; // score is now 105
score *= 2; // score is now 210
Increment and decrement operators
These add or subtract 1 from a variable:
| Operator | Name | Meaning |
|---|---|---|
++x |
Pre-increment | Increment, then return new value |
x++ |
Post-increment | Return current value, then increment |
--x |
Pre-decrement | Decrement, then return new value |
x-- |
Post-decrement | Return current value, then decrement |
int a = 5;
System.out.println(++a); // prints 6, a is now 6
System.out.println(a++); // prints 6, a is now 7
System.out.println(a); // prints 7
The pre/post distinction matters when the expression is used inside another expression. When the ++ appears as a standalone statement, both forms are equivalent:
count++; // same as ++count when used alone
Relational (comparison) operators
These operators compare two values and return a boolean result.
| Operator | Meaning | Example | Result |
|---|---|---|---|
== |
Equal to | 5 == 5 |
true |
!= |
Not equal to | 5 != 3 |
true |
> |
Greater than | 5 > 3 |
true |
< |
Less than | 5 < 3 |
false |
>= |
Greater than or equal | 5 >= 5 |
true |
<= |
Less than or equal | 4 <= 3 |
false |
Critical warning: == vs =
= is assignment. == is comparison. Mixing them up is one of the most common beginner bugs:
int x = 5;
if (x = 10) { } // COMPILE ERROR in Java (fortunately)
if (x == 10) { } // correct: checks whether x equals 10
== compares references for objects, not content. For String and other reference types, == checks whether two variables point to the same object in memory, not whether their contents are equal. Use the .equals() method to compare content:
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false — different objects in memory
System.out.println(a.equals(b)); // true — same content
Logical operators
Logical operators combine boolean values or expressions.
| Operator | Name | Meaning | ||
|---|---|---|---|---|
&& |
Logical AND | true only if both operands are true |
||
| `\ | \ | ` | Logical OR | true if at least one operand is true |
! |
Logical NOT | Inverts the boolean value |
int age = 20;
boolean hasTicket = true;
boolean canEnter = (age >= 18) && hasTicket; // true
boolean needsHelp = (age < 13) || (age > 65); // false
boolean isDenied = !canEnter; // false
Short-circuit evaluation. && and || are short-circuit operators:
- In
A && B: ifAisfalse, Java does not evaluateBat all — the result is alreadyfalse - In
A || B: ifAistrue, Java does not evaluateBat all — the result is alreadytrue
This is not just an optimization — it is a common pattern for safe code:
// Safe: if list is null, the second condition is never evaluated
if (list != null && list.size() > 0) {
// ...
}
Operator precedence
When multiple operators appear in an expression, Java applies them in a defined order (similar to PEMDAS/BODMAS in arithmetic):
Highest precedence
1. Unary: ++, --, !, (cast)
2. Multiplicative: *, /, %
3. Additive: +, -
4. Relational: <, >, <=, >=
5. Equality: ==, !=
6. Logical AND: &&
7. Logical OR: ||
8. Assignment: =, +=, -=, ...
Lowest precedence
When in doubt, use parentheses to make the intended order explicit:
int result = 2 + 3 * 4; // 14 (not 20) — multiplication first
int result2 = (2 + 3) * 4; // 20 — parentheses override precedence
boolean check = a > 0 && b < 10; // reads clearly already
String Basics
String deserves its own section because it is the type you will use in virtually every Java program you write.
Creating strings
String s1 = "Hello"; // string literal (most common)
String s2 = new String("Hello"); // explicit object creation (rarely needed)
Prefer string literals. Java maintains a string pool — a cache of string literals. When you write "Hello" in two places, Java reuses the same object from the pool rather than creating two separate objects.
String concatenation with +
The + operator concatenates strings. When one operand is a String, Java automatically converts the other operand to a String:
String firstName = "Alice";
int age = 30;
String message = "Name: " + firstName + ", Age: " + age;
System.out.println(message);
// prints: Name: Alice, Age: 30
Watch out for unexpected addition vs concatenation:
System.out.println("Sum: " + 1 + 2); // prints "Sum: 12" (concatenation left-to-right)
System.out.println("Sum: " + (1 + 2)); // prints "Sum: 3" (parentheses force addition first)
String immutability
String objects in Java are immutable — once created, their content cannot change. Methods that appear to modify a string actually return a new String object:
String original = "hello";
String upper = original.toUpperCase();
System.out.println(original); // "hello" — unchanged
System.out.println(upper); // "HELLO" — a new String object
This has a performance implication: building a string by concatenating many pieces inside a loop creates many temporary String objects. For such cases, use StringBuilder (covered in Lecture 7).
Essential String methods
String s = " Hello, World! ";
s.length() // 18 — number of characters (including spaces)
s.trim() // "Hello, World!" — removes leading/trailing whitespace
s.toLowerCase() // " hello, world! "
s.toUpperCase() // " HELLO, WORLD! "
s.contains("World") // true
s.startsWith(" Hello") // true
s.endsWith("! ") // true
s.replace("World", "Java") // " Hello, Java! "
s.indexOf("o") // 5 — index of first occurrence (-1 if not found)
s.substring(2, 7) // "Hello" — characters from index 2 up to (not including) 7
s.charAt(2) // 'H' — character at index 2
s.isEmpty() // false
s.trim().isEmpty() // false
"".isEmpty() // true
Checking string equality
Always use .equals(), never ==, to compare string content:
String input = "admin";
if (input.equals("admin")) {
System.out.println("Access granted");
}
// Defensive style: put the known string first to avoid NullPointerException
if ("admin".equals(input)) {
System.out.println("Access granted");
}
// Case-insensitive comparison
if (input.equalsIgnoreCase("ADMIN")) {
System.out.println("Access granted");
}
String.format() and text blocks
For more readable string construction, use String.format():
String name = "Alice";
int age = 30;
double gpa = 3.85;
String report = String.format("Student: %s | Age: %d | GPA: %.2f", name, age, gpa);
System.out.println(report);
// prints: Student: Alice | Age: 30 | GPA: 3.85
Common format specifiers: %s (String), %d (integer), %f (floating-point), %.2f (floating-point with 2 decimal places).
Since Java 15, text blocks allow multiline strings without concatenation or escape characters:
String json = """
{
"name": "Alice",
"age": 30
}
""";
The leading whitespace is stripped relative to the closing """. Text blocks are extremely useful for embedding SQL, JSON, HTML, or any multiline content in your code.
Summary
This lecture covered the raw materials that every Java program is built from.
- Java has eight primitive types:
byte,short,int,long,float,double,boolean, andchar. Default choices areintfor whole numbers anddoublefor decimals. - Reference types like
Stringhold a memory address pointing to an object, not the value itself.nullmeans no object is assigned. - Variables must be declared with a type and initialized before use. The
finalkeyword makes a variable a constant.varallows type inference for local variables (Java 10+). - Widening conversions (small → large type) happen automatically. Narrowing conversions (large → small) require an explicit cast and may lose data.
- Java provides arithmetic, assignment, relational, and logical operators. Short-circuit evaluation applies to
&&and||. Stringis immutable. Use.equals()(not==) to compare content.String.format()and text blocks provide clean alternatives to concatenation.
Exercises
Exercise 1 — Declare and print Declare one variable of each primitive type, assign meaningful values, and print each one with a label. For example: "Age: 25", "Price: 9.99", "Passed: true".
Exercise 2 — Integer division trap Write a program that calculates the average of three test scores: 85, 90, and 78. First use integer division and print the result. Then fix it to produce the correct decimal result. Explain in a comment why the first version gives the wrong answer.
Exercise 3 — Operator precedence Without running the code, predict the output of each line. Then verify by running them:
System.out.println(10 + 5 * 2);
System.out.println((10 + 5) * 2);
System.out.println(10 / 3);
System.out.println(10 % 3);
System.out.println(10 / 3.0);
System.out.println(true && false || true);
System.out.println(true && (false || true));
Exercise 4 — Type casting Declare a double variable with the value 9.99. Cast it to int and print both values. Then declare a char variable 'Z' and print its numeric value. Finally, add 1 to it and print the resulting character.
Exercise 5 — String manipulation Write a program that:
- Stores the string
" java programming "in a variable - Trims the whitespace and converts it to title case (first letter of each word uppercase — hint: you can use
substringandtoUpperCasetogether) - Checks whether the trimmed string contains the word
"java"(case-insensitive) - Prints the length of the trimmed string
- Replaces
"java"with"Java"and prints the result
Exercise 6 — Short-circuit evaluation Run the following code and explain in a comment why it does not throw a NullPointerException:
String s = null;
if (s != null && s.length() > 0) {
System.out.println("Not empty");
} else {
System.out.println("Null or empty");
}
Up next: Lecture 3 — Control Flow — where you will learn how to make decisions with if/else and switch, repeat actions with loops, and control execution with break and continue.
