Learn how Java SE 25 handles private methods, reflective access, interface return types, overloading, and runtime overriding.
Answer: A private method can be called directly from code that has private access, such as another method in the declaring class. A private instance method still requires an object receiver when called from a static context. A public operation can delegate internally to a private helper without making that helper part of the public API.
Reflection is another possibility, subject to access rules. getDeclaredMethod looks for a method declared by the specified class, including a private one; it does not search inherited methods. A caller can try method.trySetAccessible() and invoke the method if access is available. That attempt can return false when module boundaries prevent suppressing access checks. Private members in another module generally require the relevant package to be open to the caller's module.
The old recipe of using SecurityManager permissions or AccessController privileged blocks to obtain access is obsolete for Java SE 25: the Security Manager is permanently disabled. This does not remove module encapsulation. Prefer a supported API where available, and handle reflective lookup and invocation failures explicitly.
Answer: Yes. Access control is based on the calling code's context, not on whether the method being called is public. For example, a public save() method can call a private validate() method in the same class.
Private access also works among appropriately nested classes within the same enclosing top-level class; it is not limited to statements inside the immediate declaring class body. Private methods are not inherited or overridden by subclasses. A subclass method with the same name and signature is a separate method, assuming its declaration is otherwise valid.
Answer: It uses compile-time information: the type of the receiver expression, accessible method declarations, argument expressions and their types, applicable conversions, and rules for overload resolution and generic inference. The receiver's static type is important, but it is not the only input.
If an Animal variable refers to a Dog, a method declared only on Dog is not automatically callable through that variable. A valid cast or pattern variable can provide a Dog-typed expression, or the operation can be placed on the common contract when appropriate. A variable declared with var still has a compile-time type; it does not make method lookup dynamic.
Answer: Sometimes. One implementation can satisfy both declarations if its return type is compatible with both. For reference returns, covariant return types permit an implementation returning Integer to satisfy methods returning Number and Integer.
Incompatible return types cannot be reconciled by choosing either one. For example, same-signature methods returning int and long cannot both be implemented by one declaration, and return type alone cannot distinguish overloaded methods. Methods with different parameter lists are a separate overloading case. Conflicting default implementations may also require an explicit override, even when their return types are compatible.
Answer: Overload resolution selects a method signature using compile-time types and applicable language rules. For an ordinary virtual instance call to the selected method, runtime dispatch then selects the overriding implementation for the actual object.
public class DispatchChoices {
interface First { Number value(); }
interface Second { Integer value(); }
static class Both implements First, Second {
@Override
public Integer value() { return 7; }
}
static class Animal {
String sound() { return "Animal sound"; }
}
static class Dog extends Animal {
@Override
String sound() { return "Bark"; }
}
static String choose(Animal animal) { return "Animal overload"; }
static String choose(Dog dog) { return "Dog overload"; }
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(choose(animal));
System.out.println(animal.sound());
First result = new Both();
System.out.println(result.value());
}
}
The output is Animal overload, Bark, and 7 on separate lines. The argument variable is typed Animal, so the Animal overload is chosen. The sound call reaches Dog's override because the actual object is a Dog. Both's Integer-returning method satisfies both interface contracts.
Answer: No. An override is declared in the program and checked by the compiler. For a virtual method invocation, the JVM selects the applicable overriding implementation using the actual receiver object's class and the method-resolution rules.
@Override lets the compiler check that a declaration really overrides or implements a method. It does not turn an otherwise unrelated method into an override. An explicit super.method() call has special invocation semantics and is not an ordinary request to dispatch back to the subclass's override.
Answer: No. Overridable instance method calls provide the familiar dynamic dispatch behavior. Field access is determined using compile-time rules, and static methods are hidden rather than overridden. Calling a static method through an instance expression does not make it virtual; use the class name for clarity.
Constructors are not inherited or overridden. Private methods are not overridden, and final methods cannot be overridden. Method overloading remains a compile-time selection process even when the selected method subsequently participates in virtual dispatch.
Answer: It lets a subtype provide behavior behind a common contract, so callers can work with an abstraction instead of writing a separate type test for every implementation. This can support substitution, extension, and testing when the design preserves the parent's behavioral promises.
Overriding is a semantic feature, not a promise that code will run faster. Performance depends on the workload and runtime optimization. Likewise, a final class prevents subclassing but does not by itself make its instances immutable. Decide which operations are overridable based on the intended API contract.
Answer: It must have concrete implementations for all abstract methods it is required to implement, but those implementations may be inherited. A concrete superclass method can satisfy an interface method if its declaration meets the relevant requirements, and an applicable interface default method can also provide an implementation.
If an obligation remains unresolved, the class must supply a valid implementation or be abstract. Access level, return type, and checked exceptions matter: for example, implementing a public interface method with a protected method does not satisfy the contract. An abstract class can deliberately leave required behavior for subclasses.
Answer: No. It checks the program's declarations and expressions, including object creation, assignments, casts, method applicability, generic constraints, accessibility, and control-flow rules. The reference expression's compile-time type determines which members are candidates for an ordinary call, while the actual receiver can determine the overridden implementation used at runtime.
Pattern matching illustrates the cooperation between these rules: after a successful value instanceof String text test, text has type String in the appropriate scope and String methods are available through it. The compiler does not simply assume that a general reference always holds the particular object most recently discussed by the programmer.
References: JLS: method overriding and inheritance, JLS: method invocation, AccessibleObject API, and Security Manager permanently disabled.