Is Java fully object-oriented, primitives vs references, null and pointers, == vs equals(), wrapper classes, autoboxing and its traps.
Published September 25, 2026
These questions look basic, but they hide some of the most common bugs in real Java code: comparing Integers with ==, and NullPointerExceptions from unboxing. Answer them with a small code example; it proves you've actually hit these issues.
Short answer: No. Java has eight primitive types (byte, short, int, long, float, double, char, boolean) that are not objects. It also has static members that belong to a class rather than an object. A "pure" object-oriented language, such as Smalltalk, treats everything as an object.
Key points to cover:
static methods and fields as non-OO features.Learn it in depth → Classes and Objects
Short answer: Performance and simplicity. Primitives are stored directly (on the stack, or inline inside objects and arrays), with no object header and no garbage-collection cost. That makes arithmetic-heavy code fast and memory-efficient.
Key points to cover:
int[] of a million elements is about 4 MB. A List<Integer> of the same size is several times larger, because each element is a separate object with a header, plus a reference to it.Short answer: Large systems need to be divided among many developers and to keep changing for years. OOP helps by modelling the domain as objects with clear responsibilities, hiding internal details behind interfaces, and allowing reuse and extension without rewriting existing code.
Key points to cover:
ifs.Learn it in depth → Object-Oriented Design Refresher
Short answer: Primitives hold the value itself. They have a fixed size, can't be null, and have no methods. Non-primitive (reference) types hold a reference to an object on the heap. They can be null, they have methods, and their size depends on the object.
Key points to cover:
| Primitive | Reference | |
|---|---|---|
| Examples | int, double, boolean, char | String, arrays, Integer, any class or interface |
| Default value (fields) | 0, 0.0, false, '\u0000' | null |
| Stored | The value itself | A reference; the object lives on the heap |
Compared with == | By value | By identity (same object?) |
| Generics / collections | Not allowed (List<int> is invalid) | Allowed |
byte 1 byte, short 2, char 2 (UTF-16 code unit), int 4, float 4, long 8, double 8. boolean's size is JVM-specific.null?Short answer: No. A primitive always holds a value. Fields get a default (0, false, …), and local variables must be assigned before use, or the code won't compile. To represent "no value", use the wrapper type (Integer, which can be null), or OptionalInt.
Common trap: a JPA entity with an int column that's nullable in the database. A NULL either fails to load or silently becomes 0. Use Integer for nullable columns.
Short answer: Not in the C/C++ sense. Java has references, which point to objects, but you can't do pointer arithmetic, take the address of a variable, or cast an integer to a reference.
Key points to cover:
NullPointerException is named after the underlying idea: dereferencing a reference that points to nothing.sun.misc.Unsafe, and the Foreign Function & Memory API (standard since Java 22).== and .equals()?Short answer:
== compares values.== compares references (is it the same object?), while .equals() compares logical content, as defined by the class.String a = new String("java");
String b = new String("java");
System.out.println(a == b); // false: two different objects
System.out.println(a.equals(b)); // true: same characters
Key points to cover:
Object.equals() defaults to ==. Classes such as String, Integer, LocalDate and records override it to compare content.equals, you must override hashCode as well, or HashMap and HashSet break.Objects.equals(a, b) to compare safely when either side may be null.Common trap: "java" == "java" is true, because string literals are interned in the string pool. That fools people into thinking == works for strings.
Learn it in depth → equals() and hashCode()
Short answer: Classes that wrap a primitive in an object: Byte, Short, Integer, Long, Float, Double, Character and Boolean in java.lang.
Key points to cover:
Integer.parseInt("42"), Integer.valueOf(42), Integer.MAX_VALUE, Character.isDigit(c), Double.compare(a, b).Number.Short answer: Many Java APIs work only with objects. Generics and collections (List<Integer>, Map<String, Long>) can't hold primitives, because type parameters must be reference types. Wrappers also let you represent a missing value (null), and they supply parsing and conversion methods.
Key points to cover:
Optional<Integer>, reflection, serialisation frameworks, and nullable database columns in JPA entities.IntStream) that avoid boxing.Learn it in depth → Generics
Short answer: Autoboxing is the compiler automatically converting a primitive to its wrapper (int → Integer). Unboxing is the reverse. The compiler inserts Integer.valueOf(x) and x.intValue() calls for you.
List<Integer> scores = new ArrayList<>();
scores.add(90); // autoboxing: scores.add(Integer.valueOf(90))
int first = scores.get(0); // unboxing: scores.get(0).intValue()
Short answer: Comparing wrappers with ==. Integer.valueOf caches the values −128 to 127. Inside that range, equal values share one object, so == happens to return true. Outside it, you get two different objects, and == returns false.
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b); // true: both come from the cache
System.out.println(c == d); // false: two distinct objects
System.out.println(c.equals(d)); // true: always compare wrappers with equals()
Key points to cover:
Long sum = 0L; for (…) sum += i; creates a new Long object on every iteration. Use the primitive long.list.remove(1) on a List<Integer> removes the element at index 1, not the value 1. Use list.remove(Integer.valueOf(1)) to remove by value.NullPointerException?Short answer: Whenever a null wrapper is unboxed, because the compiler calls .intValue() on null.
Map<String, Integer> stock = new HashMap<>();
int qty = stock.get("apple"); // NPE: get() returns null, and unboxing null fails
Integer discount = null;
boolean flag = true;
int value = flag ? discount : 0; // NPE too: the ternary unboxes 'discount'
Key points to cover:
stock.getOrDefault("apple", 0), keeping the wrapper type until you've checked for null, or using Optional.Q: What's the difference between Integer.valueOf() and new Integer()?
A: valueOf can return a cached instance (−128 to 127), while new Integer always created a new object. The new Integer(…) constructors are deprecated for removal. Always use valueOf, or let autoboxing call it.
Q: What does Integer.parseInt("12a") do?
A: It throws a NumberFormatException, which is unchecked. Validate the input, or catch that exception, when you parse user-provided strings.
Q: Why does 0.1 + 0.2 != 0.3 in Java?
A: double is binary floating point, and it can't represent 0.1 exactly, so small rounding errors accumulate. For money, use BigDecimal (created from a String), or store amounts as long minor units such as paise or cents.
Q: What is the default value of a local int variable?
A: It doesn't have one. Local variables aren't initialised automatically, and the compiler rejects reading one before it's assigned. Only fields and array elements get default values.
Q: What happens with int x = Integer.MAX_VALUE + 1?
A: It silently overflows to Integer.MIN_VALUE. Use Math.addExact, which throws on overflow, or long, when overflow is possible.