Senior 5 min · March 05, 2026

Type Casting Java — Missed instanceof Broke Payment Gateway

A missed instanceof in Java type casting caused a payment gateway to crash every 200th transaction.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • Widening casting converts smaller to larger types automatically with no data loss
  • Narrowing casting requires explicit syntax and risks truncation or overflow
  • Object casting uses instanceof to avoid ClassCastException at runtime
  • Performance cost: instanceof is ~O(1) but adds a vtable lookup penalty
  • Production trap: casting without guard in collections causes silent failures
  • Biggest mistake: assuming (int) rounds instead of truncates toward zero
Plain-English First

Imagine you have a big water jug and a small glass. Pouring water from the jug into the glass is risky — it might overflow (that's narrowing casting, going from a bigger type to a smaller one). Pouring from the glass into the jug is safe — there's always enough room (that's widening casting). Type casting is just Java's way of saying: 'I know this value is one type right now, but I need to treat it as a different type.' You're not changing the water — just changing the container.

Every variable in Java has a type — int, double, long, and so on — and Java takes those types very seriously. Unlike some loosely typed languages where you can mix and match values freely, Java will flat-out refuse to compile your code if you try to use a double where it expected an int without being explicit about it. That strictness is actually a feature, not a flaw — it catches bugs before your program ever runs.

The problem type casting solves is this: real programs constantly need to move data between types. You calculate a price as a double but need to store it as an int. You receive an object as a generic Animal but know it's actually a Dog underneath. Without a formal mechanism to handle these conversions, you'd be stuck writing entirely separate code paths for every possible type combination. Type casting is that mechanism — a controlled, intentional way to convert a value from one type to another.

By the end of this article you'll understand the difference between widening and narrowing casting, know exactly when Java does the conversion for you versus when you have to do it manually, be able to safely cast objects in inheritance hierarchies, and avoid the three most common mistakes beginners make that cause data loss or runtime crashes.

Widening Casting — When Java Does the Work for You

Widening casting (also called implicit casting) happens when you convert a smaller type into a larger type. Think of it like upgrading your seat on a flight — going from economy to business class always works because there's more room. Java performs this conversion automatically because there is zero risk of losing data.

The hierarchy of primitive types from smallest to largest is: byte → short → int → long → float → double. Any conversion that moves left-to-right in that chain is a widening cast and Java handles it silently, without you writing any extra syntax.

Why does this matter? Because you'll do this constantly without realising it. When you pass an int to a method that expects a double, or add an int and a long together, Java is quietly widening your values behind the scenes. Understanding this stops you wondering why code that 'should not work' compiles just fine.

The trade-off is minimal — you use a little more memory (a long takes 8 bytes vs an int's 4 bytes) but you never lose precision with whole numbers. With floating-point widening from long or int to float, there can actually be a subtle precision quirk, which we'll flag in the callout below.

io/thecodeforge/basics/WideningCastingDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package io.thecodeforge.basics;

public class WideningCastingDemo {
    public static void main(String[] args) {
        // Start with a small integer value — byte can hold -128 to 127
        byte playerLevel = 42;

        // Java automatically widens byte → short → int → long → float → double
        short levelAsShort   = playerLevel;  
        int   levelAsInt     = playerLevel;  
        long  levelAsLong    = playerLevel;  
        float levelAsFloat   = playerLevel;  
        double levelAsDouble = playerLevel;  

        System.out.println("Original byte value  : " + playerLevel);
        System.out.println("Widened to double    : " + levelAsDouble);

        // Mixing int arithmetic with double
        int   totalPoints  = 950;
        int   maxPoints    = 1000;
        // Explicit widening to avoid integer division truncation
        double percentageScore = (double) totalPoints / maxPoints * 100;
        System.out.println("Score percentage     : " + percentageScore + "%");
    }
}
Output
Original byte value : 42
Widened to double : 42.0
Score percentage : 95.0%
Watch Out: int/long to float Can Lose Precision
Widening from int or long to float is technically allowed but can silently lose precision for very large numbers. A float has only 23 bits of mantissa, so large int values like 123456789 may be rounded to 123456792.0 after widening. If you need exact large numbers, widen to double (53 bits of mantissa) instead of float.
Production Insight
Widening is free in terms of execution cost — it's a register renaming or a single CPU instruction.
But in code reviews, I've seen engineers mistakenly use explicit casts for widening, adding noise and risk of typos.
Rule: If you write (int) when widening, you're asking for accidental data corruption during refactoring.
Key Takeaway
Widening is always safe and implicit.
Any left-to-right conversion in byte→short→int→long→float→double is automatic.
The only subtlty is precision loss int/long → float.

Narrowing Casting — When YOU Have to Take Responsibility

Narrowing casting is the reverse journey — going from a larger type to a smaller one. This is like trying to pour a bathtub of water into a coffee mug: some of it is going to spill. Because data loss is possible, Java refuses to do this automatically. You must write an explicit cast using parentheses to tell Java: 'I know what I'm doing, proceed anyway.'

The syntax is simple — you put the target type in parentheses directly before the value: (int) myDoubleValue. This is your promise to the compiler that you've thought about the consequences.

What actually happens during narrowing? For decimal-to-integer casts, the fractional part is simply truncated (chopped off, not rounded — 9.99 becomes 9, not 10). For integer-to-smaller-integer casts, bits are dropped from the left, which can produce completely unexpected values — 300 stored as a byte becomes 44 because only the lowest 8 bits survive.

Narrowing is genuinely useful — converting a pixel coordinate from double to int, truncating a financial calculation to whole cents, or storing a large computed ID into a smaller field — but you need to understand what you're giving up.

io/thecodeforge/basics/NarrowingCastingDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package io.thecodeforge.basics;

public class NarrowingCastingDemo {
    public static void main(String[] args) {
        // --- Example 1: double to int (Truncation) ---
        double precisePosition = 47.89;
        int pixelPosition = (int) precisePosition;  // 47.89 → 47

        System.out.println("Precise position : " + precisePosition);
        System.out.println("Pixel position   : " + pixelPosition);

        // --- Example 2: int to byte (Overflow/Bit-dropping) ---
        int largeNumber = 300;  
        byte narrowedToByte = (byte) largeNumber;  // Keeps only lower 8 bits

        System.out.println("Original int : " + largeNumber);
        System.out.println("Cast to byte : " + narrowedToByte); // Result is 44
    }
}
Output
Precise position : 47.89
Pixel position : 47
Original int : 300
Cast to byte : 44
Pro Tip: Truncation ≠ Rounding
Casting a double to int always truncates toward zero — it never rounds. (int) 9.99 is 9, and (int) -9.99 is -9. If your logic requires rounding, always call Math.round(value) first and then cast. This one distinction shows up in interviews and eliminates a whole class of calculation bugs.
Production Insight
A common production bug is using (int) Math.random() * 100 — the cast applies to the result of Math.random(), always 0.
Fix: cast the entire product: (int)(Math.random()*100).
Rule: cast the whole expression, not just the first term.
Key Takeaway
Narrowing requires explicit (type) syntax.
Decimal→integer truncates, not rounds.
Integer→narrower drops high-order bits — validate range first.

Object Casting — Working With Inheritance Hierarchies

Primitive casting is just the warm-up. In real Java applications you'll constantly work with objects in inheritance hierarchies, and that's where object casting becomes essential.

Here's the setup: when a Dog extends Animal, every Dog IS an Animal — but not every Animal is a Dog. Java lets you store a Dog reference in an Animal variable (upcasting, always safe, automatic). The tricky part is going the other direction — taking that Animal reference and treating it as a Dog again (downcasting, requires explicit cast, can fail at runtime).

Upcasting is like checking into a hotel under the label 'guest' — you're still you, just described more generally. Downcasting is like the concierge looking at a 'guest' record and guessing it's a VIP member. If they guess wrong, things go badly. In Java, a wrong downcast throws a ClassCastException at runtime — not a compile error, a crash.

The solution is the instanceof operator — always check before you cast. Since Java 16 you can use the pattern matching syntax (instanceof Dog d) which checks and casts in a single line, eliminating the double-mention of the type.

io/thecodeforge/basics/ObjectCastingDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package io.thecodeforge.basics;

class Animal { void makeSound() { System.out.println("Generic sound"); } }

class Dog extends Animal {
    void bark() { System.out.println("Woof!"); }
    void fetch() { System.out.println("Fetching ball..."); }
}

public class ObjectCastingDemo {
    public static void main(String[] args) {
        // UPCASTING: Safe and Implicit
        Animal myAnimal = new Dog();
        myAnimal.makeSound(); 

        // SAFE DOWNCASTING: Pattern Matching (Java 16+)
        if (myAnimal instanceof Dog dog) {
            dog.fetch(); // dog is already casted within this scope
        }

        // UNSAFE DOWNCASTING: Manual way (Risk of ClassCastException)
        try {
            Dog manualDog = (Dog) myAnimal;
            manualDog.bark();
        } catch (ClassCastException e) {
            System.err.println("Invalid cast: " + e.getMessage());
        }
    }
}
Output
Generic sound
Fetching ball...
Woof!
Interview Gold: Why Does Upcasting Even Exist?
Upcasting enables polymorphism — the ability to write one method that accepts Animal and works with any subclass (Dog, Cat, Bird). Without upcasting you'd need a separate method for every animal type. This is the foundation of the Open/Closed Principle: open for extension (add new animal subclasses), closed for modification (never touch the existing Animal-accepting method).
Production Insight
I once debugged a ClassCastException where a DAO returned Object and the service blindly cast to a concrete type. The root cause: a new JPA entity class was introduced but the service was never updated.
Fix: always use instanceof before downcasting; collections should be generically typed.
Rule: Object references are a code smell — avoid raw types in collections.
Key Takeaway
Upcasting is automatic and safe.
Downcasting requires instanceof guard — pattern matching in Java 16+ is preferred.
ClassCastException is a runtime error you prevent, not catch.

Casting with Wrapper Classes: Autoboxing Pitfalls

Java's wrapper classes (Integer, Double, Boolean etc.) bridge primitives and objects, but they bring a special casting trap: you cannot directly cast between wrapper types like you do with primitives. For example, (Double) someObject fails even if someObject is an Integer that could be widened to double. The reason: wrapper classes are sibling classes—they don't share an inheritance chain.

Common mistake: trying to cast an Object that holds an Integer into a Double to use it in a calculation. This compiles but throws ClassCastException at runtime. The correct approach is to unbox first, then widen: ((Number) obj).doubleValue().

Autoboxing itself is a form of implicit widening when converting primitive to wrapper: int → Integer, double → Double. But autoboxing does not convert between wrapper types. That is, Integer i = 42 is fine, but Double d = (Double) i is not—you must go through the primitive: double dVal = i.doubleValue(); Double d = dVal;.

Why does this matter in production? Consider a JSON deserialization that returns Number objects. If you assume Integer and cast to Double, you get failure. Using Number's doubleValue() is the safe way to handle unknown numeric types.

io/thecodeforge/basics/WrapperCastingDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package io.thecodeforge.basics;

public class WrapperCastingDemo {
    public static void main(String[] args) {
        // Autoboxing works: primitive → wrapper
        int primitive = 42;
        Integer wrapped = primitive; // fine

        // Direct cast between wrapper types? No.
        Object obj = Integer.valueOf(42);
        // Double d = (Double) obj; // Compiles but throws ClassCastException

        // Correct way: unbox, then widen
        Number num = (Number) obj;
        double d = num.doubleValue();
        System.out.println("Unboxed and widened: " + d);

        // Realistic example: handling mixed numeric types
        Object[] numbers = { Integer.valueOf(10), Double.valueOf(20.5), Long.valueOf(100L) };
        for (Object val : numbers) {
            Number n = (Number) val;
            System.out.println(n.getClass().getSimpleName() + " -> double: " + n.doubleValue());
        }
    }
}
Output
Unboxed and widened: 42.0
Integer -> double: 10.0
Double -> double: 20.5
Long -> double: 100.0
The Number Trick That Saves Production
When dealing with JSON or deserialized numeric data, always cast to Number (the common superclass) and call .doubleValue(), .intValue() etc. This works for Integer, Long, Double, BigDecimal, etc. Avoid casting directly to specific wrapper types unless you have strict guarantees. This pattern saved a payment system where a field changed from integer to decimal in the API—no code changes needed.
Production Insight
Autoboxing has a hidden cost: it creates new objects for each primitive. In hot loops, this increases GC pressure.
Use primitive streams (IntStream, LongStream) instead of Stream<Integer> for numeric operations.
Rule: prefer primitives over wrappers in performance-critical paths.
Key Takeaway
Can't cast between wrapper types directly.
Use Number superclass for polymorphic numeric values.
Autoboxing is convenient but not free—watch memory in tight loops.

Common Pitfalls with Generics and Type Erasure

Generics in Java are compile-time—they're erased at runtime (type erasure). This means that at runtime, List<String> and List<Integer> are both just List. Casting on raw types or unchecked casts is where production bugs breed.

Common scenario: you have a List<? extends Animal> but need to call Dog-specific methods. You can't directly cast the list—you must check each element. The no-go pattern: (Dog) list.get(0) without checking if that element is actually a Dog.

Another gotcha: unchecked cast warnings. Suppressing them with @SuppressWarnings("unchecked") is like ignoring a smoke alarm. One day, someone passes a different type into the collection, and you get a ClassCastException far from the insertion point.

Bridge methods generated by the compiler for covariance can also cause confusing cast failures in reflection or serialization scenarios. Remember: generics are syntactic sugar—the JVM sees raw types.

io/thecodeforge/basics/GenericsCastingDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package io.thecodeforge.basics;

import java.util.*;

public class GenericsCastingDemo {
    public static void main(String[] args) {
        // Unchecked cast warning example
        List rawList = new ArrayList();
        rawList.add("Not a number");
        // Casting raw list to parameterized type (dangerous)
        List<Integer> intList = (List<Integer>) rawList; // unchecked warning
        // Later: Integer val = intList.get(0); // ClassCastException at runtime

        // Correct approach: use bounded wildcards and explicit checks
        List<? extends Animal> animals = new ArrayList<Dog>();
        // Can't add to this list (wildcard restriction)
        // To downcast safely:
        for (Animal a : animals) {
            if (a instanceof Dog dog) {
                dog.bark();
            }
        }
    }
}
Output
(Complies with warnings, no output if safe)
// Runtime error when accessing intList: ClassCastException: String cannot be cast to Integer
Mental Model: Generics are Just Compiler Safety Nets
  • At runtime, List<Integer> is just List—the type info is erased.
  • Unchecked casts suppress warnings but don't change runtime behavior.
  • Bridge methods (generated for covariance) can introduce hidden casts.
  • Always prefer List<? extends T> over raw types and suppress warnings only after careful review.
  • ClassCastException from generics often points to a place where a raw type was used or an unchecked cast was ignored.
Production Insight
I've seen production outages caused by a single @SuppressWarnings("unchecked") that allowed a mixed-type list to survive.
The fix: replace raw types with strongly typed containers and validate each element type on insertion.
Rule: every unchecked warning is a potential ClassCastException in disguise.
Key Takeaway
Generics are erased at runtime—casts may still fail.
Never suppress unchecked warnings without understanding the risk.
Use wildcards and instanceof for safe downcasting in parameterized collections.
● Production incidentPOST-MORTEMseverity: high

The Pervasive ClassCastException: A Real Downcast That Took Down a Payment Gateway

Symptom
Every 200th transaction threw ClassCastException: 'class io.thecodeforge.payment.CreditCard cannot be cast to class io.thecodeforge.payment.PayPal'. The error was transient – not reproducible on demand.
Assumption
The team assumed that because the method always received a PayPal object in their unit tests, the same would hold in production. They believed that the 'instanceof' check was unnecessary overhead.
Root cause
A new payment provider type (CreditCard) was added to the system. The upcast to the base Payment interface worked, but a downcast to PayPal inside a handler bypassed instanceof. Mixed type lists were possible due to a previous code merge that allowed multiple provider types in the same batch.
Fix
Added an instanceof guard before the downcast. The handler now checks 'if (payment instanceof PayPal payPal) { processPayPal(payPal); } else if (payment instanceof CreditCard cc) { ... }', eliminating the unsafe cast. Used Java 16 pattern matching instanceof for cleaner code.
Key lesson
  • Never skip instanceof when downcasting objects – even if you 'know' the runtime type.
  • Unit tests often mask polymorphic bugs because they test single paths. Integration tests with mixed types catch this.
  • Pattern matching instanceof (Java 16+) compiles to the same bytecode but improves readability and eliminates redundant cast lines.
Production debug guideSymptom → Action guide for runtime casting failures in production5 entries
Symptom · 01
ClassCastException in polymorphic code
Fix
Add instanceof check before downcast. Use Java 16+ pattern matching if available. Log the actual runtime type via obj.getClass().getName() to identify unexpected subclasses.
Symptom · 02
Unexpected integer value after narrowing (e.g., 300 → 44)
Fix
Check the target type's range. Use Byte.MAX_VALUE / Integer.MAX_VALUE to validate. Prefer Math.toIntExact() for safe narrowing of long to int – it throws ArithmeticException on overflow.
Symptom · 03
Division yields zero when expecting a decimal (int/int widening)
Fix
Cast one operand to double before the division: (double) a / b. This triggers widening, not narrowing. The cast must apply to at least one operand.
Symptom · 04
Compile error 'incompatible types: possible lossy conversion'
Fix
You needs an explicit narrowing cast. Add (targetType) before the value. Verify the value fits; otherwise handle truncation or overflow explicitly.
Symptom · 05
Float precision loss when widening large int to float
Fix
Widen to double instead of float. For very large numbers, even double may lose precision – consider using BigDecimal for exact decimal arithmetic.
★ Quick Debug Cheat Sheet: Type CastingFive common runtime errors and the exact commands to diagnose them instantly.
ClassCastException at line 45
Immediate action
Check the object's runtime type with getClass().getName() and log it.
Commands
java -ea -cp . io.thecodeforge.basics.ObjectCastingDemo 2>&1 | grep 'class.*cannot be cast'
Add -XX:+TraceClassCast to JVM args for full trace.
Fix now
Wrap downcast in instanceof block and test with mixed types.
Truncation bug: (int) 9.99 returns 9, expected 10+
Immediate action
Use Math.round() before casting if rounding is intended.
Commands
java -cp . io.thecodeforge.basics.NarrowingCastingDemo 2>&1 | grep 'Pixel position'
Check for other expressions that rely on implicit truncation.
Fix now
Replace (int) value with (int) Math.round(value) for rounding.
int overflow: storing 300 in byte gives 44+
Immediate action
Verify the value is within target type's range using MIN_VALUE/MAX_VALUE.
Commands
java -cp . io.thecodeforge.basics.NarrowingCastingDemo 2>&1 | grep 'Cast to byte'
Add range check before cast: if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) { byte b = (byte) val; } else { throw new ArithmeticException(); }
Fix now
Use Math.toIntExact() for long→int narrowing to get exception on overflow.
Division of two ints gives 0 instead of 0.95+
Immediate action
Cast one operand to double before performing division.
Commands
java -cp . io.thecodeforge.basics.WideningCastingDemo 2>&1 | grep 'Score percentage'
Check all arithmetic expressions with integer division.
Fix now
Write (double) numerator / denominator to trigger widening.
Widening vs Narrowing Casting
AspectWidening (Implicit) CastNarrowing (Explicit) Cast
DirectionSmall type → Large type (byte→int→double)Large type → Small type (double→int→byte)
Syntax requiredNone — Java handles it automaticallyExplicit: (targetType) value
Risk of data lossNone for integers; minor precision risk int/long→floatYes — decimals truncated, bits dropped on overflow
Compile resultAlways compiles silentlyCompile error if cast syntax is missing
Runtime riskZero — always succeedsPossible data corruption for primitives; ClassCastException for objects
Common use casePassing int to a double parameter; mixed-type arithmeticConverting pixel coordinates double→int; narrowing API return values
Object equivalentUpcasting: Dog reference → Animal reference (automatic)Downcasting: Animal reference → Dog reference (must use instanceof first)

Key takeaways

1
Widening casting (byte→int→double) is automatic
Java handles it because no data can be lost. Narrowing (double→int) is manual because data WILL be lost and Java forces you to own that decision.
2
Casting a double to int always truncates toward zero
9.99 becomes 9, never 10. Use Math.round() before casting if rounding is what you actually need.
3
Upcasting (Dog→Animal) is always safe and implicit. Downcasting (Animal→Dog) requires an explicit cast AND an instanceof check first
skipping that check is a runtime ClassCastException waiting to happen.
4
Java 16+ pattern matching instanceof (if (animal instanceof Dog d)) checks and casts in one step
prefer this over the old two-line check-then-cast pattern for cleaner, less error-prone code.
5
Wrapper types cannot be cast directly to each other; use Number's doubleValue() / intValue() methods for safe numeric conversion.

Common mistakes to avoid

5 patterns
×

Expecting (int) to round instead of truncate

Symptom
(int) 9.9 returns 9 instead of the expected 10, causing off-by-one errors in score or display logic
Fix
Use (int) Math.round(value) when rounding is required; only use a raw cast when truncation is the deliberate intent.
×

Downcasting an object without instanceof guard

Symptom
ClassCastException at runtime with a cryptic 'class X cannot be cast to class Y' message
Fix
Always precede a downcast with if (ref instanceof TargetType) { TargetType var = (TargetType) ref; }. On Java 16+ use pattern matching: if (ref instanceof TargetType t) { } to eliminate the redundant cast line.
×

Casting int 300 to byte expecting 300

Symptom
byte result is 44 instead of 300 with no compile warning, causing silent data corruption
Fix
Before narrowing integers, validate the value is within the target type's range using the type's MIN_VALUE and MAX_VALUE constants (e.g. Byte.MIN_VALUE to Byte.MAX_VALUE), and handle the out-of-range case explicitly.
×

Directly casting between wrapper types (e.g., Double to Integer)

Symptom
ClassCastException: java.lang.Integer cannot be cast to java.lang.Double when the actual runtime type is different
Fix
Cast to the common superclass Number and use methods like doubleValue() and intValue() to convert. Never assume the wrapper type matches your expectation.
×

Suppressing unchecked cast warnings without verification

Symptom
ClassCastException occurs far from the cast point, making debugging difficult; the root cause is a raw type or mixed-type collection
Fix
Replace raw types with parameterized types. If you must suppress, add explicit runtime type checks (getClass()) before accessing elements.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
Explain the internal mechanics of narrowing an integer from a 32-bit int...
Q02SENIOR
Why does Java not allow automatic narrowing of primitives, but allows au...
Q03SENIOR
What is the performance cost of dynamic type checking (instanceof) versu...
Q04SENIOR
How does the JVM handle 'ClassCastException' internally, and why is it c...
Q05SENIOR
Given 'Object obj = "Forge";', will '(Integer) obj' compile? Will it run...
Q06SENIOR
How does autoboxing interact with method overload resolution? Can autobo...
Q01 of 06JUNIOR

Explain the internal mechanics of narrowing an integer from a 32-bit int to an 8-bit byte. What happens to the high-order bits?

ANSWER
The JVM discards the high-order bits, retaining only the lowest 8 bits. For example, int 300 in binary is 0000 0000 0000 0000 0000 0001 0010 1100. Truncating to 8 bits leaves 0010 1100, which equals 44. This is a bit-mask operation: (byte) intValue is equivalent to intValue & 0xFF for non-negative values, but for negative ints the two's complement representation is preserved in the lower bits.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
What is the Big O complexity of an object cast in Java?
02
Why can't I cast a String to an Integer if they both inherit from Object?
03
Does casting affect the actual object in memory?
04
What's the difference between (int) Math.random()*100 and (int)(Math.random()*100)?
05
Is it safe to cast List to List?
🔥

That's Java Basics. Mark it forged?

5 min read · try the examples if you haven't

Previous
Operators in Java
7 / 13 · Java Basics
Next
Input and Output in Java