JAVA BASICS AND OOPS
JAVA BASICS AND OOPS
BASICS
AND
OOPS JAVA BASICS
JAVA KEY FEATURES
1. Object-Oriented Programming (OOP)
Java follows the OOP paradigm, which means it focuses on objects and classes. OOP
principles such as inheritance, encapsulation, polymorphism, and abstraction make the
language modular, reusable, and easier to maintain.
3. Secure
The Java Security Manager, which defines access rules for Java classes.
Bytecode verification.
9. Architecture-Neutral
Java bytecode is designed to be architecture-neutral, meaning it is not dependent on the
underlying hardware architecture. This ensures that a Java program will run in the same
way on different hardware platforms.
DATA MEMBERS:
NON-ACCESS MODIFIERS:
ARGUMENTS:
COMMAND LINE ARGS:
These are typped in command promt,args are provided during
exceution
TYPE CASTING:
WHY IS MAIN CLASS ALWAYS PUBLIC:
Coz it should be visible for JRE and main method is called by JRE
Main method is called by JRE w/o creating an object or instance
ADVANTAGES OF THIS:
Method Overloading enhances flexibility, reduces complexity, and improves code readability and
maintenance through compile-time polymorphism.
Method Overriding provides runtime flexibility, enabling subclasses to modify or extend the
behavior of parent classes, promoting code reusability, abstraction, and adherence to OOP principles
like polymorphism and inheritance. Both techniques are essential for writing robust, reusable, and
extensible Java applications.
RECURSION
Recursion is a programming technique where a function calls itself to solve a problem. The function
typically solves a small part of the problem and then calls itself to solve the remaining parts,
breaking down the problem into smaller subproblems.
CONSTRUCTORS :
A constructor in Java is a special method that is called when an object of a class is created. It is used
to initialize the object’s state (i.e., assign values to fields or perform startup actions). Unlike regular
methods, constructors have the same name as the class and no return type, not even void.
WHY ONLY CONSTRUCTOR:
Explicitly using constructors in Java is important because they provide a structured, predictable, and
controlled way to initialize objects. While Java offers some default behavior, explicitly defining
constructors ensures that objects are initialized properly, and it gives you more control over the
initialization process.
Avoiding Uninitialized Objects: Ensures that all necessary fields are initialized when the object is
created.
Immutable Objects: Helps in creating immutable objects that cannot be changed after they
are initialized.
Flexibility via Overloading: Provides multiple ways to create objects, offering flexibility to
users.
Control over Initialization: Ensures that objects are initialized with valid, meaningful data.
TYPES OF CONSTRUCTORS:
DEAFULT CONSTRUCTOR
PARAMETERISED CONSTRUCTOR
COPY CONSTRUCTOR:
This constructor is like the behaviour of the car but another copy and we
can change the name also we want
INHERITANCE:
TYPES :
WHY JAVA DOES NOT SUPPORT MULTIPLE INHERITANCE:
Java does not support multiple inheritance through classes to avoid complexity and ambiguity and
diamond problem
Alternate Way :
While Java doesn't allow multiple inheritance with classes, it does allow it using interfaces. An
interface in Java can be implemented by multiple classes, and a class can implement multiple
interfaces. Interfaces don't provide method implementations (at least until Java 8, when default
methods were introduced). This allows Java to support multiple inheritance at the behavioral level
(method signatures) without the ambiguity introduced by class-based inheritance.
ADVANTAGES:
Inheritance is a powerful feature of object-oriented programming that promotes code reuse,
flexibility, and maintainability. It allows for the creation of well-organized class hierarchies, reduces
redundancy, and supports polymorphism, making programs more scalable and easier to maintain in
the long run.
OBJECT CLASS:
The Object class is the root class from which every class directly or indirectly inherits. It is the
parent of all classes, whether user-defined or predefined. If a class doesn't explicitly extend another
class, it implicitly extends the Object class.
protected Object clone()
Description: Creates and returns a copy (clone) of the object. The cloning
mechanism in Java is shallow by default unless you manually implement deep
copying.
Note: The class must implement the Cloneable interface; otherwise, it will throw
a CloneNotSupportedException.
java
Copy code
class A implements Cloneable {
int i;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
FINAL:
1. Final Variables
A final variable is a constant and can only be assigned once. Once initialized, its value cannot be
changed.
Where can we use final variables?
Local Variables: Inside methods, constructors, or blocks.
Instance Variables: Variables that belong to an instance of the class.
Static Variables: Class-level variables (shared by all instances of the class).
Final Methods
A final method is a method that cannot be overridden by subclasses. Once a method is declared
as final, its implementation is locked and cannot be changed by any subclass.
Where can we use final methods?
In Any Class: In any class, you can declare certain methods as final to prevent
overriding. This ensures the integrity of that method's behavior across all subclasses.
Final Classes
A final class is a class that cannot be subclassed (i.e., no class can extend it). Declaring a class
as final prevents any class from inheriting from it, ensuring that the class's functionality is
locked.
Where can we use final classes?
Any Class: Any class that you want to prevent from being extended can be declared as
final. This is especially useful when you want to ensure that no one can modify or extend
the behavior of that class
Final Parameters
A method parameter can be declared as final, meaning that the parameter value cannot be
modified inside the method. However, the final parameter can still be used normally within the
method (for reading).
Where can we use final parameters?
In Any Method or Constructor: You can mark any method parameter as final to prevent
modification inside the method body.
IS-A describes the hierarchical relationship. A Dog IS-A Animal, meaning it inherits
properties and methods of Animal.
public Car() {
this.engine = new Engine(); // Composition
}
Here, Car HAS-A Engine, meaning Car uses an Engine object to perform certain tasks.
Diamond Problem
The Diamond Problem occurs in multiple inheritance when a class inherits from two classes that
both inherit from the same parent class. This creates ambiguity when the child class attempts to use
a method from the grandparent class, as it doesn’t know which method to inherit.
interface Animal {
void sound();
}
class School {
private String name;
private List<Student> students; // Aggregation (HAS-A)
Here, the Student can exist independently of the School, representing aggregation.
Composition (Strong HAS-A Relationship)
Composition is a stronger form of the HAS-A relationship. In composition, the part cannot exist
independently of the whole. If the whole object is destroyed, the part is destroyed as well.
Example:
java
Copy code
class Engine {
public void start() {
System.out.println("Engine starts.");
}
}
public Car() {
this.engine = new Engine(); // Engine is created within Car, strong
association
}
Here, Car HAS-A Engine, and the Engine object is tightly coupled with the Car. If the
Car is destroyed, the Engine cannot exist separately, representing composition.
Explanation:
Animal myAnimal = new Dog(); — A Dog object is upcasted to the Animal
reference. The method makeSound() will use the Dog's overridden implementation due to
runtime polymorphism.
Although the object is of type Dog, you can only access methods defined in the Animal
class using the myAnimal reference.
2. Downcasting
Downcasting is the reverse of upcasting. It is the process of converting a superclass reference back
to a subclass reference. Downcasting requires explicit casting, and it is usually performed when you
need to access specific subclass methods that are not available in the superclass.
In downcasting:
You cast the superclass reference back to its original subclass type.
Explicit casting is required because it's a potentially unsafe operation (the superclass
reference may not always be of the subclass type).
Why Use Downcasting?
Access subclass-specific methods: If a subclass object was upcasted to a superclass, you
can downcast it back to the subclass type to access subclass-specific methods.
Object processing: In some cases, you may handle objects of different types using
upcasting, but later you need to perform subclass-specific operations, which requires
downcasting.
Example of Downcasting:
java
Copy code
class Animal {
public void makeSound() {
System.out.println("Some generic animal sound");
}
}
Explanation:
Dog myDog = (Dog) myAnimal; — This is an explicit cast to convert the Animal
reference back to Dog.
After downcasting, you can access the fetch() method that is specific to Dog, which
wasn't possible with the Animal reference.
Unsafe Downcasting Example:
If downcasting is performed incorrectly, it will throw a ClassCastException at runtime.
java
Copy code
class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }
Explanation:
In this example, myAnimal is actually of type Cat, but an attempt is made to downcast it
to Dog. This causes a ClassCastException at runtime because the actual object is not
of type Dog.
Key Concepts:
Upcasting: Vehicle myVehicle = new Car(); allows us to handle Car objects in
a generic manner.
Downcasting: Car myCar = (Car) myVehicle; allows us to regain access to
methods specific to the Car class (like playRadio()).
instanceof check: Always check using instanceof before downcasting to avoid
ClassCastException.
Conclusion
Upcasting and downcasting are integral parts of polymorphism in Java. Upcasting allows
treating objects of derived classes as objects of a base class, while downcasting gives access
to subclass-specific behavior.
These techniques help make code flexible, reusable, and decoupled by allowing different
objects to be processed uniformly.
However, downcasting requires caution to avoid ClassCastException at runtime.
Always use instanceof checks to ensure safe downcasting.
BINDING:
Binding in Java
In programming, binding refers to the process of associating a method call or a variable reference
with its corresponding code or value. In Java, binding determines which method or variable a name
refers to during program execution. There are two main types of binding:
1. Static Binding (Early Binding)
2. Dynamic Binding (Late Binding)
Understanding these types of binding is crucial for grasping concepts like polymorphism, method
overloading, and method overriding in Java.
Explanation:
Even though obj is a reference to a Child object, the display() method from Parent
is called because static methods are statically bound based on the reference type (Parent),
not the object type (Child).
Example 2: Variables
java
Copy code
class Parent {
int x = 10;
}
Explanation:
Variables are statically bound. Even though obj refers to a Child object, obj.x accesses
the variable x defined in Parent, outputting 10.
Explanation:
Here, display() is an instance method overridden in Child.
The method call obj.display() is dynamically bound at runtime to Child's
display() method because obj refers to a Child object.
Explanation:
Final methods cannot be overridden, so show() in Parent is statically bound.
Dynamic Binding with Interfaces
java
Copy code
interface Animal {
void sound();
}
Explanation:
Animal is an interface with a method sound().
Both Cat and Dog implement sound() differently.
The method calls are dynamically bound to the actual object's sound() method at runtime.
Practical Applications
Using Polymorphism with Dynamic Binding
java
Copy code
abstract class Employee {
public abstract void work();
}
Explanation:
Both emp1 and emp2 are of type Employee but refer to different subclasses.
The work() method is dynamically bound to the respective subclass implementations at
runtime.
Summary
Static Binding:
Occurs at compile-time.
Associated with static, final, and private methods, as well as variables.
Faster execution but less flexible.
Dynamic Binding:
Occurs at runtime.
Associated with overridden instance methods.
Enables polymorphism and flexible code design.
ABSTRACT:
1. Abstract Class
An abstract class is a class that cannot be instantiated on its own and is meant to be subclassed. It
can contain both abstract methods (methods without a body) and concrete methods (methods with
an implementation).
Key Features of Abstract Classes:
Cannot be instantiated: You cannot create objects of an abstract class directly.
Can contain abstract methods: These are methods declared without an implementation.
Can contain concrete methods: These are regular methods with an implementation.
Can have constructors: An abstract class can have constructors that are called when an
instance of a subclass is created.
Can have member variables: Abstract classes can have fields (attributes) to store data.
Syntax of an Abstract Class:
java
Copy code
abstract class AbstractClassName {
// Abstract method (without a body)
abstract void abstractMethod();
// Concrete method
void concreteMethod() {
System.out.println("This is a concrete method.");
}
}
// Concrete method
void eat() {
System.out.println("This animal eats food.");
}
}
Explanation:
The Animal class is an abstract class that has one abstract method makeSound() and one
concrete method eat().
The Dog and Cat classes are concrete subclasses that extend Animal and provide
implementations for the makeSound() method.
In the Main class, we can create instances of Dog and Cat, but we cannot create an
instance of Animal.
2. Abstract Method
An abstract method is a method that is declared without an implementation. This means that
subclasses must provide an implementation for this method.
Key Features of Abstract Methods:
No body: An abstract method does not have a body; it ends with a semicolon.
Must be in an abstract class: Abstract methods can only exist in abstract classes.
Subclass implementation required: Any subclass of an abstract class must implement all
abstract methods, or it must also be declared abstract.
Syntax of an Abstract Method:
java
Copy code
abstract void methodName();
Example of Interface:
java
Copy code
interface Animal {
void makeSound();
void eat();
}
Summary
Abstract Classes: Used when you want to define a base class with some common
functionality but still want subclasses to provide specific implementations for certain
methods.
Abstract Methods: Define a method that must be implemented by any non-abstract
subclass.
Abstraction in Java enhances code organization, reusability, and maintainability, providing a
clear structure for software design.
COUPLING
Loose Coupling
Loose coupling refers to a design principle in which components (modules or classes) have
minimal dependencies on each other. In a loosely coupled system, changes in one module do not
significantly affect other modules, leading to improved maintainability, scalability, and flexibility.
Characteristics of Loose Coupling:
Independence: Modules can be developed, tested, and updated independently.
Flexibility: Easier to replace or modify components without affecting the entire system.
Interchangeability: New implementations can be easily substituted for old ones without
changing the dependent code.
Reduced Impact of Changes: Changes in one module have little to no effect on other
modules.
Example of Loose Coupling
Using interfaces is a common way to achieve loose coupling. Below is an example illustrating loose
coupling in Java using interfaces.
java
Copy code
// Define an interface
interface Payment {
void pay(int amount);
}
Tight Coupling
Tight coupling refers to a design principle where components are highly dependent on each other.
In tightly coupled systems, changes in one module can significantly impact other modules, making
the system rigid and harder to maintain.
Characteristics of Tight Coupling:
Dependency: Modules are highly dependent on each other, often directly referencing
specific implementations.
Limited Flexibility: Changing one module usually requires changes in dependent modules.
Difficult Testing: Testing individual modules becomes challenging due to their
interdependencies.
Lower Reusability: Modules are often designed for specific contexts, making them less
reusable.
Example of Tight Coupling
In this example, a class directly instantiates another class, demonstrating tight coupling.
java
Copy code
class CreditCardPayment {
public void pay(int amount) {
System.out.println("Paid " + amount + " using Credit Card.");
}
}
class Order {
private CreditCardPayment creditCardPayment;
public Order() {
// Directly creating a CreditCardPayment instance
this.creditCardPayment = new CreditCardPayment();
}
1. Encapsulation
Definition
Encapsulation is the bundling of data (attributes) and methods (functions or behaviors) that operate
on the data into a single unit, usually a class. It restricts direct access to some of an object’s
components, which is a means of preventing unintended interference and misuse of the methods and
data.
Characteristics
Access Modifiers: Encapsulation utilizes access modifiers (private, protected, public) to
control visibility and access to class members.
Data Hiding: By making class variables private, you can hide the internal state of the object
and expose only necessary methods.
Getter and Setter Methods: These methods allow controlled access to the private data of a
class.
Benefits
Control: Encapsulation provides control over the data by allowing validation and other logic
to be implemented in getter and setter methods.
Maintainability: Changes to the internal implementation of a class can be made without
affecting external code that uses the class.
Improved Security: Sensitive data can be hidden from outside access.
Example
java
Copy code
class BankAccount {
// Private variables
private String accountNumber;
private double balance;
// Constructor
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
Explanation
The BankAccount class encapsulates the account number and balance.
The attributes accountNumber and balance are private, meaning they cannot be
accessed directly outside the class.
The class provides public methods to deposit and withdraw money, ensuring the balance
remains valid.
2. Polymorphism
Definition
Polymorphism means "many forms." It allows methods to do different things based on the object it
is acting upon. In Java, polymorphism can be achieved through method overloading and method
overriding.
Characteristics
Method Overloading: This occurs when multiple methods in the same class have the same
name but different parameter lists (types, number, or both).
Method Overriding: This occurs when a subclass provides a specific implementation of a
method that is already defined in its superclass.
Benefits
Flexibility and Reusability: Polymorphism allows methods to be used in different contexts,
enhancing code flexibility and reusability.
Dynamic Method Resolution: In the case of method overriding, Java resolves the method
to be executed at runtime based on the object’s type.
Example
Method Overloading
java
Copy code
class MathOperations {
// Method to add two integers
public int add(int a, int b) {
return a + b;
}
Method Overriding
java
Copy code
class Animal {
public void sound() {
System.out.println("Animal makes sound");
}
}
Explanation
In the first example, the MathOperations class demonstrates method overloading with
multiple add methods.
In the second example, Animal is the superclass with a sound method, which is
overridden by Dog and Cat subclasses, allowing for specific implementations.
3. Abstraction
Definition
Abstraction is the concept of hiding the complex implementation details of a system and exposing
only the necessary parts. In Java, abstraction is achieved using abstract classes and interfaces.
Characteristics
Abstract Classes: An abstract class cannot be instantiated and may contain abstract methods
(without implementation) and concrete methods (with implementation).
Interfaces: An interface can only contain method signatures and constants. Since Java 8,
interfaces can also have default and static methods.
Benefits
Simplification: Abstraction simplifies complex systems by allowing users to interact with
simpler interfaces.
Maintainability: Changes to the implementation can be made without affecting the code
that uses the abstraction.
Code Reusability: Common functionality can be defined in an abstract class or interface,
promoting reusability across different classes.
Example
Using Abstract Classes
java
Copy code
abstract class Shape {
abstract void draw(); // Abstract method
Using Interfaces
java
Copy code
interface Drawable {
void draw(); // Abstract method
}
Explanation
In the first example, the abstract class Shape defines an abstract method draw that must be
implemented by subclasses like Circle and Rectangle.
In the second example, the Drawable interface defines a method draw, which is
implemented by both Circle and Rectangle, demonstrating abstraction.
Summary
Encapsulation: Bundles data and methods that operate on the data into a single unit and
restricts access to some components, promoting data hiding and controlled access.
Polymorphism: Allows methods to behave differently based on the object they are acting
upon, achieved through method overloading and overriding.
Abstraction: Hides complex implementation details and exposes only the necessary
features, making systems easier to use and maintain.
PARSE METHOD:
The parse method in Java is commonly associated with converting a String representation of
data into its respective primitive data type or an object of a certain class. This is particularly useful
for handling user inputs, reading data from files, or converting data formats.
The parse method is not a single method but is implemented in various classes within the Java
standard library, such as Integer, Double, Boolean, etc. Each of these classes provides static
parse methods to convert a String to the corresponding primitive type.
1. Integer.parseInt(String s):
Types of Cloning
There are two primary types of cloning in Java:
1. Shallow Cloning
2. Deep Cloning
Let's explore each type in detail.
1. Shallow Cloning
Shallow cloning creates a new object that is a copy of the original object, but it only copies the
references to the objects (not the objects themselves) that the original object references. As a result,
if the original object contains references to mutable objects, changes made to those mutable objects
via one object will be reflected in the other.
Example of Shallow Cloning
java
Copy code
class Address {
String city;
Address(String city) {
this.city = city;
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // Shallow copy
}
}
Output
vbnet
Copy code
Original: Alice, New York
Cloned: Alice, New York
Explanation:
In the example above, when the city of the cloned object's address is changed, it also reflects
in the original object since they both reference the same Address object.
2. Deep Cloning
Deep cloning creates a new object and also recursively copies all objects that are referenced by the
original object. This means that changes made to mutable objects in the cloned object do not affect
the original object.
Example of Deep Cloning
java
Copy code
class Address {
String city;
Address(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone(); // Shallow copy
cloned.address = this.address.clone(); // Deep copy for Address
return cloned;
}
}
Output
vbnet
Copy code
Original: Alice, New York
Cloned: Alice, New York
Explanation:
In this example, the Address class has a clone method that creates a new Address
object with the same city. When the cloned Person object's address is modified, it does not
affect the original object.
Conclusion
Shallow Cloning: Creates a new object and copies references of the original object's fields,
leading to shared references for mutable objects.
Deep Cloning: Creates a new object and recursively copies all objects referenced by the
original object, resulting in completely independent objects.