Java OOP Concepts Question Bank 2025-26
Java OOP Concepts Question Bank 2025-26
Method overloading in Java occurs when two or more methods in the same class have the same name but different parameters (different type, number, or both of parameters). This allows methods to perform similar tasks with different inputs. For example, you might overload a method 'add()' that can handle adding both two integers or two double values. Method overriding, in contrast, involves redefining a method in a subclass that already exists in the superclass, with the same signature. Overloading is about the same method name with different signatures within the same class, whereas overriding changes the implementation of an inherited method in a subclass.
Multilevel inheritance in Java is when a class is derived from a class that is also a derived class. For example, a class 'Animal' is extended by 'Mammal', which is then extended by 'Dog'. In this hierarchy, 'Dog' inherits features from both 'Mammal' and indirectly from 'Animal'. This contrasts with multiple inheritance, which Java does not support natively due to the ambiguity it can create, like the diamond problem where a class could inherit from multiple classes with the same method signatures, leading to ambiguity. Java circumvents this by allowing a class to implement multiple interfaces, providing structure flexibility without the complexity of class-based multiple inheritance.
Java uses call-by-value for parameter passing, meaning that a copy of the variable is passed to methods. When primitives are passed, a copy of the actual value is received by the method, so changes to the variable within the method do not affect the original value. When objects are passed, a copy of the reference to the object is passed, allowing methods to modify the object's attributes, but not the reference itself. Understanding parameter passing is crucial as it affects how changes within methods impact variable states outside these methods, influencing code behavior and debugging practices. Programmers leverage this understanding to control the flow and state of data effectively in Java applications.
In Java, a class is a blueprint for creating objects. A class defines a datatype by bundling data and methods that manipulate data into a single unit. An object, on the other hand, is an instance of a class. Classes are important as they provide the structure for creating objects, encapsulating data for the object, and defining behavior through methods. For example, if you have a class 'Car', it might have properties like 'color' and 'model', and methods like 'drive()' and 'brake()'. You can instantiate objects such as 'myCar' from this class, giving each object its unique properties and behaviors. This encapsulation and abstraction are key elements of object-oriented programming, allowing for modular, reusable, and maintainable code.
In Java, there are primarily two types of constructors: default constructors and parameterized constructors. A default constructor is created by the compiler if no constructor is provided and initializes objects with default values. Parameterized constructors allow initializing objects with specific values provided by the user. Additionally, Java supports copy constructors as a means to create a new object by copying the existing values from another object. Constructors are different from methods as they have no return type and are called implicitly when an instance of a class is created.
The IS-A relationship in Java is a type of inheritance where a child class is a subtype of a parent class, implying that the child inherits the attributes and behaviors of the parent. The two main types of the IS-A relationship are class inheritance and interface implementation. In class inheritance, a subclass, such as 'Car', extends a superclass, like 'Vehicle'. This relationship indicates 'Car' IS-A 'Vehicle', inheriting fields and methods from 'Vehicle'. In interface implementation, a class, such as 'Laptop', might implement an interface 'ComputingDevice', denoting that 'Laptop' IS-A 'ComputingDevice', implementing its abstract methods. IS-A relationships are crucial for polymorphism, allowing objects to be treated as instances of their parent class, fostering reusable and intuitive code structure.
Recursion in Java is a technique where a method calls itself to solve a problem incrementally. Each recursive call has its own execution context, maintaining individual variables and state. A well-defined base case stops the recursion to prevent infinite loops. An example of a recursive function is calculating the factorial of a number: ```java int factorial(int n) { if (n == 0) return 1; else return n * factorial(n - 1); } ``` In this example, 'factorial' calls itself with a decremented value of 'n' until 'n' reaches 0, where it returns 1. Each layer of recursion builds on the return value of the deeper call, eventually unravelling back to the original call with the full computed result. Recursive solutions often simplify problems that can be approached by iterative methods.
Java provides four types of access modifiers: public, private, protected, and default (package-private). Public access modifier allows visibility of a class or member across all packages. Private access restricts visibility to within the same class only. Protected access permits visibility within the same package and subclasses. Default access (no keyword) allows visibility only within the same package. These modifiers control the level of access of classes, constructors, methods, and fields, fundamentally shaping the encapsulation and scope within Java applications. Proper use of access modifiers is essential for securing data and fostering modular design in software development.
The 'final' keyword in Java is used to restrict the user. It can be applied to variables, where it prevents reassignment after initialization; to methods, where it prevents method overriding in subclasses; and to classes, where it prevents inheritance. For example, a class with a final method might look like: ```java class Vehicle { final void run() { System.out.println("Vehicle is running"); } } class Car extends Vehicle { // void run() { // This would cause a compile-time error // System.out.println("Car is running"); // } } ``` In this example, `run()` method in `Vehicle` is declared as final, so it cannot be overridden by the `Car` class. This enforces a contract that 'run' behavior in 'Vehicle' cannot be altered, helping preserve intended logic and enhance code reliability.
The 'this' keyword in Java is used within an instance method or a constructor to refer to the current object. It is often used to disambiguate variable names that might overlap between class variables and parameters, for example, 'this.value = value;' distinguishes between the class variable 'value' and the parameter 'value'. The 'static' keyword is used to indicate that a particular member belongs to the class itself, rather than instances of the class. Static members can be accessed without creating an instance of the class. For example, a static method 'calculateArea()' within a class 'Geometry' can be called using 'Geometry.calculateArea()'. The 'this' keyword helps clarify variable scope and cohort object methods, while 'static' is crucial for memory management and utility functions.