Set 1
Why main method is always declared with public static void?
In Java, public static void main(String[] args)
is the entry point of any Java program. L
public
: It means that themain
method can be accessed from anywhere. It's necessary because the Java Virtual Machine (JVM) needs to access this method to start the execution of the program.static
: It means that themain
method belongs to the class itself, rather than to any instance of the class. This is because Java starts the program before any objects are created.void
: It indicates that themain
method doesn't return any value.main
: This is the name of the method.main
is a special method name recognized by the JVM.(String[] args)
: This is the parameter thatmain
accepts.args
is an array of strings that can be passed to the program from the command line. These are typically arguments that you want to pass to your program when you run it.
So, when we run a Java program from the command line, we can pass arguments to it like this. args
will contain ["arg1", "arg2", "arg3"]
, and we can access these values inside the main
method.
Rules for variable names in Java:
Variable names must begin with a letter (a-z or A-Z), an underscore (_), or a currency character ($ or €).
First character of a variable name cannot be a digit. It can start with currency or underscore also.
Variable names are case-sensitive, meaning
myVariable
andMyVariable
are considered different variables.Variable names cannot be a Java keyword or reserved word, such as
int
,class
,public
, etc
Shallow Copy vs Deep Copy
Shallow Copy
Shallow copy creates a new object and then copies the reference of the original object into it. In other words, it duplicates the reference, not the underlying data.
So, any changes made to the copied object will reflect in the original object and vice versa because they both refer to the same underlying data.
Shallow copy is relatively simple and fast, but it can lead to unexpected behavior if you're not careful about how changes propagate across objects.
Deep Copy
Deep copy, on the other hand, creates a new object and then, recursively, copies each field of the original object into the new object.
This means that changes made to the copied object won't affect the original object, and vice versa, because they refer to different sets of data.
Deep copying can be more complex and computationally expensive, especially for complex objects with nested structures or references to other objects.
Example 1
Changes made to the shallow copy (shallowCopy
) affect the original object (original
) because they both refer to the same object in memory. However, changes made to the deep copy (deepCopy
) do not affect the original object because they are separate instances with their own memory space.
Example 2
In this method, a new ArrayList
(clonedStyles
) is created, and the elements from the original styles
list are copied into it. This process of creating a new list and copying elements ensures that the styles
list of the cloned Document
object refers to a different memory location than the styles
list of the original Document
object. Therefore, changes made to the styles
list of one Document
object will not affect the styles
list of the other Document
object.
Example 3
Here, the clone()
method creates a new Orc
object (clone
) using the constructor with parameters name
, health
, and weapon
. However, since no special handling is done for the weapon
field, it's simply copied by reference. This means the weapon
field of the cloned Orc
object will reference the same Weapon
object as the original Orc
object. Therefore, any changes made to the Weapon
object through the cloned Orc
object will affect the original Orc
object, and vice versa. This behavior indicates that it's a shallow copy
Java Interfaces and abstract classes
Interfaces and abstract classes are both tools for achieving abstraction in Java, but they serve different purposes.
Use Interfaces When
Defining a Contract: Interfaces are used to define a contract or a set of methods that a class must implement. They specify what a class can do, without providing any implementation details.
Multiple Inheritance of Type: Java doesn't support multiple inheritance of classes, but it does support implementing multiple interfaces. This makes interfaces useful when a class needs to inherit behavior from multiple sources.
Loose Coupling: Interfaces promote loose coupling between components by providing a common abstraction. Classes can interact through interfaces without being tightly bound to each other's implementations.
API Design: Interfaces are often used in API design to define a set of methods that other classes must implement. This allows for flexibility and extensibility in the implementation details.
Use Abstract Classes When
Partial Implementation: Abstract classes can provide partial implementations of methods, along with abstract methods that must be implemented by subclasses. This is useful when you have a base class that contains common behavior shared by multiple subclasses.
Code Reusability: Abstract classes allow you to define common behavior once and reuse it across multiple subclasses. They can contain fields, constructors, and methods that are shared among subclasses.
Stronger Encapsulation: Abstract classes can have member variables with different access modifiers (e.g., private, protected), providing stronger encapsulation compared to interfaces, which can only have public members.
Evolution Over Time: Abstract classes provide more flexibility for evolving the API over time. You can add new methods (abstract or concrete) to an abstract class without breaking existing implementations, whereas adding new methods to an interface requires modifying all implementing classes.
Example of Interface
The Comparable
interface in Java is a good example. It's used to define a contract for classes that can be compared to each other. Classes that implement Comparable
must provide an implementation for the compareTo
method, which compares the object with another object of the same type and returns an integer indicating the comparison result. For example, the String
class implements Comparable
Example of Abstract Class
Creating an abstract class Shape
to represent common behavior and characteristics of all different shapes. It provides common functionality like printDetails()
Example using both interface and abstract class
Consider an example of payment processing system. PaymentProcessor
interface defines a contract. Any class implementing PaymentProcessor
must have a processPayment
method that takes an amount and returns true if the payment is successful. AbstractPaymentGateway
abstract class extends the PaymentProcessor
interface and provides some common functionalities:
When is the object created with new keyword
In Java, the object is created with the new
keyword during runtime.
The new
keyword plays a crucial role in the object creation process:
Memory Allocation: It triggers the allocation of memory for the new object on the heap. The heap is a special area of memory dedicated to storing objects in Java.
Constructor Call: It invokes the constructor of the class specified after
new
. The constructor is responsible for initializing the object's state by assigning values to its fields.
Therefore, the new
keyword initiates object creation and memory allocation at runtime, not during compilation. This allows for dynamic object creation based on your program's needs.
Statically Typed (like Java) and Dynamically Typed Languages
Statically Typed Languages (like Java):
Type declaration at compile time: We explicitly declare the data type (e.g.,
int
,String
) of a variable when we define it.Compile-time type checking: The compiler verifies if the assigned values match the declared data type during compilation. This helps catch errors early on.
Strong type safety: Variables can only hold values of their declared type, preventing unexpected behavior at runtime.
Dynamically Typed Languages:
Type inferred at runtime: The data type of a variable is determined by the value assigned to it at runtime, not by explicit declaration.
Runtime type checking: Type checking happens during program execution, not before. This offers more flexibility but can lead to runtime errors if incorrect types are used.
Weaker type safety: Variables can hold different data types throughout the program, potentially causing issues if not handled carefully.
final
keyword on field, method and class
final
keyword on field, method and classThe final
keyword in Java is used to restrict modifications or inheritance. Here's a breakdown of its meaning when applied to fields (variables), methods, and classes:
Final Field (Variable):
When a field (variable) is declared as
final
, its value cannot be changed after it's initialized. This ensures the value remains constant throughout the program.Example:
Final Method:
When a method is declared as
final
, it cannot be overridden by subclasses. This prevents subclasses from modifying the behavior of that specific method.Example:
Final Class:
When a class is declared as
final
, it cannot be extended or subclassed. This means you cannot create new classes that inherit from the final class.Example:
When to Use final
:
final
:Consider using final
when:
We want to ensure a variable's value remains constant.
We want to prevent method overrides in subclasses (for specific well-defined behaviors).
We have a class that serves a utility purpose and doesn't need subclasses.
By understanding the meaning of final
with fields, methods, and classes, we can effectively control mutability, inheritance, and code structure in Java programs.
transient
keyword in java
transient
keyword in javaThe transient
keyword in Java is used specifically in the context of serialization. Serialization is the process of converting an object's state into a stream of bytes that can be stored or transmitted. Deserialization is the opposite process of recreating an object from a byte stream. Transient fields are initialized to their default values during deserialization.
Here's how the transient
keyword affects serialization:
Purpose:
When we declare a field (variable) of a class as
transient
, its value will not be serialized when the object is serialized.This is useful for data members that don't represent the essential state of the object or that can be easily recalculated during deserialization. Or when we have fields that do not need to be saved or transferred along with the object's state.
Example:
Last updated