Java Basic Technical Knowledge Summary

Object-Oriented and Procedural Programming

Object-oriented programming decomposes problems into abstract objects, then combines and calls these objects to solve problems. It has relatively higher resource usage and slower execution speed.

Procedural programming follows a top-down design, breaking problems into individual steps implemented as functions, which are called sequentially. It uses fewer resources and runs faster.

Object-Oriented Programming Features

  • Inheritance: Allows subclasses to extend parent class functionality without rewriting code, with two implementation forms: implementation inheritance and interface inheritance.
  • Polymorphism: Refers to the same method of a class instance behaving differently in different scenarios, where the same operation produces different results for different objects. Strict polymorphism requires runtime dynamic binding, meeting three conditions: inheritance or interface implementation, subclass overriding parent class methods, and parent class reference pointing to subclass objects. Static polymorphism (compile-time binding) refers to method overloading.
  • Encapsulation: Wraps objective things into abstract classes, providing different levels of protection for internal data. Classes can expose data and methods only to trusted objects, hiding information from untrusted ones.

Overload vs Override

  • Overload: Resolved at compile time, occurs when multiple methods share the same name but have different parameter lists (return types, access modifiers, and thrown exceptions can vary). Thrown exceptions can be broader than parent class methods.
  • Override: Resolved at runtime, requires subclass methods to have the same name, parameter list, and return type as parent class methods. Access modifier restrictions must be weaker or equal to parent class methods, and thrown exceptions must be narrower or equal to parent class methods.

Java Inheritance vs Implementation

  • Inheritance: Use extends keyword to inherit a parent class, used for code reuse. Parent classes can define properties, methods, variables, and constants. Ideal when multiple classes share common functionality.
  • Implementation: Use implements keyword to implement interfaces. Interfaces define global constants (static final) and abstract methods (default methods were added in Java 8). Ideal when multiple classes share the same target but different implementation logic.

Java Inheritance vs Composition

  • Inheritance: Follows the "is-a" relationship, resolved at compile time. Advantages: subclasses automatically inherit parent class interfaces. Disadvantages: tight coupling between subclass and parent class, reduced independence.
  • Composition: Follows the "has-a" relationship, resolved at runtime. Advantages: low coupling and good extensibility. Disadvantages: composite classes cannot automatically obtain the same interfaces as component classes.

Composition is generally preferred over inheritance.

Java Variables

Java defines three types of variables: class variables, member variables, and local variables, stored in the JVM's method area, heap memory, and stack memory respectively.

Access Modifier Scope

The following table compares the access permissions of public, protected, private, and default (package-private) modifiers:

Modifier Visibility Scope
public Accessible by all classes and objects
private Only accessible within the current class; subclasses and other classes cannot access
protected Accessible within the current class and same-package classes; accessible by subclasses even in different packages
default Accessible only within the current class and same-package classes; not accessible by subclasses in different packages

Platform Independence Implementation

Java's platform independence is implemented across the entire Java ecosystem, with core components including:

  1. Front-end Compilation: The javac compiler converts .java source files into platform-neutral .class bytecode files.
  2. Back-end Compilation: The Java Virtual Machine (JVM) translates bytecode into native machine code for the target operating system and hardware.

Key supporting components:

  • Java Language Specification: Defines the value ranges and behaviors of basic data types to ensure consistent language behavior across platforms.
  • Class Files: All Java code is compiled into a unified class file format, eliminating platform-specific source code differences.
  • JVM: Each platform has its own JVM implementation, which shields underlying hardware and operating system differences by translating class files into native code.

Java also supports multiple JVM languages like Kotlin, Groovy, JRuby, Jython, and Scala, as all can be compiled into JVM bytecode regardless of the source language.

Pass by Value and Pass by Reference

  • Pass by Value: Copies the actual parameter and passes the copy to the function; modifications to the parameter inside the function do not affect the original actual parameter.
  • Pass by Reference: Passes the direct memory address of the actual parameter to the function; modifications to the parameter inside the function affect the original actual parameter.

Java uses only pass by value: when passing object references, the reference itself is copied and passed to the function, so modifications to the referenced object inside the function will affect the original object, but reassigning the reference inside the function will not change the original reference.

Primitive and Wrapper Classes

All wrapper classes are located in the java.lang package. The following table lists the corresponding wrapper classes for each primitive type:

Primitive Type Wrapper Class
byte Byte
boolean Boolean
short Short
char Character
int Integer
long Long
float Float
double Double
  • Primitive Types: Stored in stack memory, offering high execution efficiency.
  • Wrapper Classes: Are objects stored in heap memory, accessed via stack references. They are more resource-intensive than primitive types but provide object-oriented features like methods and properties, and are required for collection frameworks that only accept object types.

Auto-Boxing and Unboxing

Auto-boxing automatically converts primitive types to wrapper classes, e.g., Integer i = 10; is equivalent to Integer i = Integer.valueOf(10);. Auto-unboxing automatically converts wrapper classes to primitive types, e.g., int b = i; is equivalent to int b = i.intValue();.

Common Auto-Boxing/Unboxing Scenarios

  1. Storing primitive types in collection classes
  2. Comparing wrapper types with primitive types
  3. Performing arithmetic operations on wrapper types
  4. Using ternary operators
  5. Function parameters and return values

Auto-Boxing Cache Mechanism

Most integer wrapper classes cache instances for values between -128 and 127:

  • Byte, Short, Long: Cache values from -128 to 127, range cannot be modified.
  • Character: Caches values from 0 to 127, range cannot be modified.
  • Integer: Caches values from -128 to 127 by default; the upper limit can be adjusted via the JVM parameter java.lang.Integer.IntegerCache.high in Java 6+.

Issues with Auto-Boxing

  1. Numeric comparison of wrapper objects should use equals() instead of ==, except for values within the cached range.
  2. Auto-unboxing a null wrapper object will throw a NullPointerException.
  3. Mass auto-boxing/unboxing in loops can waste significant memory resources.

Correct Boolean Naming in POJOs

When defining boolean fields in POJOs, RPC parameters, or return values:

  1. Use wrapper type Boolean instead of primitive boolean to avoid serialization erors.
  2. Do not use field names starting with is (e.g., isSuccess), use success instead, as primitive type getters use the isXXX() naming convention which can cause serialization issues.
  3. Use primitive boolean for local variables for better performance.

String Handling

String Immutability

Once a String object is created in heap memory, its value cannot be modified. All String class methods return new string objects instead of modifying the original string. For mutable string operations, use StringBuffer or StringBuilder to avoid excessive garbage collection from frequent string object creation.

substring() Method Differences Between JDK 6 and JDK 7

  • JDK 6: The substring() method shared the original character array with the parent string, which could cause memory leaks if only a small substring was extracted from a large string. A common workaround was x = x.substring(x, y) + "" to create a new string.
  • JDK 7+: The substring() method creates a new character array for the extracted substring, eliminating the memory leak issue.

replaceFirst(), replaceAll(), and replace() Differences

The three string replacemant methods have the following distinctions:

  1. replace(CharSequence target, CharSequence replacement): Replaces all exact matches of the target string with the replacement string. Both parameters are plain text strings.
  2. replaceAll(String regex, String replacement): Replaces all matches of the given regular expression with the replacement string.
  3. replaceFirst(String regex, String replacement): Same as replaceAll(), but only replaces the first matching result.

String Concatenation

Java supports multiple string concatenation methods, with performance rankings (from fastest to slowest): StringBuilder < StringBuffer < concat < + < StringUtils.join. StringUtils.join is ideal for concatenating string arrays or lists.

  • +: Compile-time optimization uses StringBuilder.append() for non-constant concatenation, but creates unnecessary objects in loops.
  • concat(): Creates a new character array by combining the lengths of the two strings, copies both strings, then returns a new String object.
  • StringBuilder: Mutable character array, non-thread-safe, fastest for single-threaded scenarios.
  • StringBuffer: Thread-safe via synchronized on the append() method, slower than StringBuilder.
  • StringUtils.join: Uses StringBuilder internally, optimized for array/list concatenation.

Best practices:

  1. Use + for simple concatenation outside loops.
  2. Use StringBuffer for concurrent scenarios.
  3. Use StringBuilder for loop-based concatenation to avoid performance and memory issues.

String.valueOf() vs Integer.toString()

Three common ways to convert an int to String:

int num = 5;
String str1 = "" + num; // Equivalent to new StringBuilder().append(num).toString()
String str2 = String.valueOf(num); // Internally calls Integer.toString(num)
String str3 = Integer.toString(num);

String.valueOf(num) and Integer.toString(num) are functionally identical, while "" + num creates additional StringBuilder and String objects.

Class Constant Pool and Runtime Constant Pool

Class Constant Pool

The class constant pool is a resource repository in the .class file. In addition to class version, fields, methods, and interface descriptions, the class file contains a constant pool table storing compiler-generated literals and symbolic references.

  • Literals: Fixed value representations in source code, such as integers, floating-point numbers, strings, booleans, and characters.
  • Symbolic References: References relative to direct references, including fully qualified class/interface names, field names and descriptors, and method names and descriptors.

During JVM loading, symbolic references are resolved to direct memory addresses during class creation or runtime.

Runtime Constant Pool

The runtime constant pool is the runtime representation of the class constant pool for each class or interface. It stores both compile-time literals and runtime-resolved method/field references, allocated to the JVM's method area when the class is loaded.

Differences and Connections Between Class Constant Pool, Runtime Constant Pool, and String Constant Pool

  1. The class constant pool is part of the .class file, loaded into the runtime constant pool during JVM class loading.
  2. The string constant pool is a subset of the runtime constant pool, storing string literal values. String literals from the class constant pool are moved to the string constant pool during class loading.

String.intern() Method

The intern() method adds a string to the string constant pool if it does not already exist, then returns a reference to the pooled string. For example, String s = new String("abc").intern() will return a reference to the "abc" string in the constant pool.

String Length Limits

  • Compile Time: String constants in the class constant pool have a maximum length of 65534 characters, enforced by the javac compiler.
  • Runtime: The maximum length of a String object is limited by the range of the int type (2^31 -1), as the internal character array length is stored as an int. Exceeding this limit will throw an OutOfMemoryError or other runtime exceptions.

Java Keywords

transient Keyword

The transient modifier marks instance variables that should not be serialized. When an object is serialized via Java's serialization mechanism, transient fields are excluded from the serialized data, and their values are set to default values (0 for primitives, null for objects) after deserialization. A common use case is the elementData array in ArrayList, which uses transient to avoid serializing the unused underlying array capacity.

instanceof Keyword

instanceof is a binary operator that tests whether an object is an instance of a specified class, interface, or subclass, returning a boolean value.

volatile Keyword

The volatile keyword solves concurrency issues related to atomicity, visibility, and order:

  1. Visibility: When a volatile variable is modified, the JVM sends a lock prefix instruction to flush the variable from the processor cache to main memory. All other processors sniff the bus to detect cached value changes, invalidate their local caches, and reload the latest value from main memory.
  2. Ordering: Prevents instruction reordering by inserting memory barriers.

volatile guarantees visibility and order but not atomicity. For example, volatile int count ensures visibility of count changes, but count++ is not atomic as it involves read-modify-write operations.

final Keyword

The final keyword indicates "unmodifiable" and can be used to define variables, methods, and classes:

  • Final Variables: Cannot be reassigned after initialization. Instance final variables must be initialized in the constructor or at declaration.
  • Final Methods: Cannot be overridden by subclasses.
  • Final Classes: Cannot be inherited.

static Keyword

The static keyword belongs to the class rather than instances:

  • Static Variables: Shared across all class instances, not thread-safe. Often used with final for shared global resources, accessible via ClassName.variableName if not privatized.
  • Static Methods: Belong to the class, can only call other static methods and access static variables. Common examples include utility classes like java.util.Collections.
  • Static Code Blocks: Execute once when the class is loaded by the class loader, used to initialize static variables or resources. Multiple static blocks can exist in a class, executed in declaration order.
  • Static Nested Classes: Nested classes marked static, can be accessed without an instance of the outer class, used for organizational purposes.

const Keyword

const is a reserved keyword in Java that is not currently used, intended for future language extansions. Its usage is similar to final, but it is rarely employed in practice.

Tags: java object-oriented-programming JVM string-handling java-keywords

Posted on Tue, 15 Sep 2026 16:18:42 +0000 by poisa