Classes and Objects in Java
Java is an object-oriented programming language that uses classes and objects as the fundamental building blocks. Understanding these concepts is crucial for mastering Java. This guide will cover everything you need to know about classes and objects in Java.
Defining a Class
A class in Java is a blueprint for creating objects. It defines the structure and behavior that the objects of the class will have.
Syntax
public class ClassName {
// Fields (Variables)
// Methods (Functions)
}
Example
public class Car {
// Fields
String color;
String model;
int year;
// Methods
void displayInfo() {
System.out.println("Model: " + model);
System.out.println("Color: " + color);
System.out.println("Year: " + year);
}
}
Creating Objects
Objects are instances of classes. You create an object from a class using the new
keyword.
Syntax
ClassName objectName = new ClassName();
Example
public class Main {
public static void main(String[] args) {
Car myCar = new Car(); // Creating an object of the Car class
myCar.color = "Red";
myCar.model = "Tesla";
myCar.year = 2022;
myCar.displayInfo();
}
}
Fields and Methods
Fields (also known as variables or properties) represent the state of an object, while methods define the behavior of the object.
Fields
Fields are variables that hold the data of an object.
Example
public class Car {
String color;
String model;
int year;
}
Methods
Methods are functions defined within a class that describe the behaviors of the objects.
Example
public class Car {
String color;
String model;
int year;
void displayInfo() {
System.out.println("Model: " + model);
System.out.println("Color: " + color);
System.out.println("Year: " + year);
}
}
Constructors
Constructors are special methods that are called when an object is instantiated. They initialize the newly created object.
Default Constructor
If no constructor is defined, Java provides a default constructor with no arguments.
Example
public class Car {
String color;
String model;
int year;
// Default constructor
public Car() {
}
void displayInfo() {
System.out.println("Model: " + model);
System.out.println("Color: " + color);
System.out.println("Year: " + year);
}
}
Parameterized Constructor
A parameterized constructor allows you to initialize an object with specific values.
Example
public class Car {
String color;
String model;
int year;
// Parameterized constructor
public Car(String color, String model, int year) {
this.color = color;
this.model = model;
this.year = year;
}
void displayInfo() {
System.out.println("Model: " + model);
System.out.println("Color: " + color);
System.out.println("Year: " + year);
}
}
Using the Parameterized Constructor
public class Main {
public static void main(String[] args) {
Car myCar = new Car("Red", "Tesla", 2022);
myCar.displayInfo();
}
}
Constructor Overloading
You can have multiple constructors in a class, each with a different parameter list. This is called constructor overloading.
Example
public class Car {
String color;
String model;
int year;
// Default constructor
public Car() {
this.color = "Unknown";
this.model = "Unknown";
this.year = 0;
}
// Parameterized constructor
public Car(String color, String model, int year) {
this.color = color;
this.model = model;
this.year = year;
}
void displayInfo() {
System.out.println("Model: " + model);
System.out.println("Color: " + color);
System.out.println("Year: " + year);
}
}
Using the Overloaded Constructors
public class Main {
public static void main(String[] args) {
Car defaultCar = new Car();
defaultCar.displayInfo();
Car myCar = new Car("Red", "Tesla", 2022);
myCar.displayInfo();
}
}
Encapsulation, Access Modifiers, and Static Members in Java
Encapsulation
Encapsulation is the principle of bundling data (fields) and methods (functions) that operate on the data within a single unit, called a class. It keeps the internal state of an object safe from outside interference and misuse.
Access Modifiers
Access modifiers control the visibility and accessibility of classes, fields, methods, and constructors within Java programs. There are four main access modifiers:
- public: Accessible from any other class.
- protected: Accessible within the same package and by subclasses (even if they are in different packages).
- (default) package-private: Accessible only within the same package.
- private: Accessible only within the same class.
Example Usage:
public class Car {
public String color; // accessible everywhere
protected String model; // accessible within the same package and subclasses
int year; // package-private (default), accessible within the same package
private String vin; // accessible only within the class
// Constructor and methods
}
Static Members
Static members (variables and methods) belong to the class itself rather than instances of the class. They are shared among all instances of the class and can be accessed without creating an object of the class.
Static Variables (Class Variables):
Static variables are shared among all instances of a class. They are initialized only once, at the start of the execution, and retain their value until the program terminates.
public class Car {
public static int count; // static variable to count instances
// Constructor and methods
}
Static Methods:
Static methods belong to the class rather than any specific instance. They can access static variables and other static methods directly.
public class Car {
public static void displayCount() {
System.out.println("Number of cars created: " + count);
}
// Constructor and other methods
}
Accessing Static Members:
Static members are accessed using the class name, not through object references.
public class Main {
public static void main(String[] args) {
Car.count = 0; // Accessing static variable
Car.displayCount(); // Calling static method
}
}
Access Modifiers in Java
Access modifiers in Java are keywords that define the accessibility (visibility) of classes, methods, variables, and constructors within Java programs. They control how these elements can be accessed by other classes and methods, helping to enforce encapsulation and ensure code integrity.
Types of Access Modifiers
Java provides four main access modifiers:
- public
- protected
- default (no modifier)
- private
Let's explore each of these access modifiers in detail:
1. public
- Accessible from: Any other class in the same Java program, regardless of package.
-
Usage: Use
public
when you want a class, method, variable, or constructor to be widely accessible. - Example:
public class MyClass {
public int publicVar;
public void publicMethod() {
// Method implementation
}
}
2. protected
- Accessible from: Classes in the same package and subclasses (even if they are in different packages).
-
Usage: Use
protected
to provide visibility within the same package and to subclasses. - Example:
package mypackage;
public class ParentClass {
protected int protectedVar;
protected void protectedMethod() {
// Method implementation
}
}
class ChildClass extends ParentClass {
void accessProtected() {
protectedVar = 10; // Accessing protected variable from subclass
protectedMethod(); // Accessing protected method from subclass
}
}
3. default (package-private)
- Accessible from: Classes in the same package only.
- Usage: When no access modifier is specified, it is default (package-private). Use this when elements need to be accessed only within the same package.
- Example:
package mypackage;
class MyClass {
int defaultVar;
void defaultMethod() {
// Method implementation
}
}
public class AnotherClass {
void accessDefault() {
MyClass obj = new MyClass();
obj.defaultVar = 20; // Accessing default variable from another class in the same package
obj.defaultMethod(); // Accessing default method from another class in the same package
}
}
4. private
- Accessible from: Only within the same class.
-
Usage: Use
private
when you want to restrict access to within the same class, providing the highest level of encapsulation. - Example:
public class MyClass {
private int privateVar;
private void privateMethod() {
// Method implementation
}
public void accessPrivate() {
privateVar = 30; // Accessing private variable within the same class
privateMethod(); // Accessing private method within the same class
}
}
Non-Access Modifiers in Java
Non-access modifiers in Java modify the behavior of classes, methods, variables, and constructors without affecting their accessibility. They provide additional functionality and characteristics to these elements, enhancing code functionality and behavior.
Types of Non-Access Modifiers
Java provides several non-access modifiers:
- static
- final
- abstract
Let's explore each of these non-access modifiers in detail:
1. static
-
Usage: The
static
keyword is used to declare members (variables and methods) that belong to the class rather than instances of the class. - Variables: Static variables (class variables) are shared among all instances of a class. They are initialized only once, at the start of the execution, and retain their value until the program terminates.
- Methods: Static methods belong to the class rather than any specific instance. They can access static variables and other static methods directly.
- Example:
public class MyClass {
public static int count; // Static variable (class variable)
public static void staticMethod() {
// Static method implementation
}
}
public class Main {
public static void main(String[] args) {
MyClass.count = 10; // Accessing static variable
MyClass.staticMethod(); // Calling static method
}
}
2. final
-
Usage: The
final
keyword is used to declare constants, prevent method overriding, and prevent inheritance (when applied to classes). - Variables: Final variables (constants) cannot be changed once initialized.
- Methods: Final methods cannot be overridden by subclasses.
- Classes: Final classes cannot be subclassed.
- Example:
public class MyClass {
public static final int MAX_VALUE = 100; // Constant variable
public final void finalMethod() {
// Final method implementation
}
}
public class SubClass extends MyClass {
// Cannot override finalMethod()
}
3. abstract
-
Usage: The
abstract
keyword is used to declare abstract classes and methods. - Abstract Classes: Abstract classes cannot be instantiated on their own. They may contain abstract methods (methods without a body) that must be implemented by subclasses.
- Abstract Methods: Abstract methods are declared without a body and must be implemented by subclasses (unless the subclass itself is abstract).
- Example:
public abstract class Shape {
abstract void draw(); // Abstract method
}
public class Circle extends Shape {
@Override
void draw() {
// Method implementation
}
}
Inheritance in Java and Access Modifiers
Inheritance
Inheritance in Java is a mechanism where one class (subclass or derived class) inherits the properties and behaviors (methods and fields) of another class (superclass or base class). This allows for code reuse and allows you to create a hierarchical relationship between classes.
Syntax for Inheritance
public class SuperClass {
// Fields and methods
}
public class SubClass extends SuperClass {
// Fields and methods of SubClass
}
Example
public class Animal {
String name;
public void eat() {
System.out.println(name + " is eating.");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println(name + " is barking.");
}
}
In this example:
-
Animal
is the superclass with a fieldname
and a methodeat()
. -
Dog
is the subclass that inheritsname
andeat()
fromAnimal
and adds its own methodbark()
.
Access Modifiers in Inheritance
Access modifiers control the visibility and accessibility of classes, methods, and fields in Java. They play a crucial role in inheritance as they determine whether a subclass can access members (fields and methods) of its superclass.
Access Modifiers for Normal Attributes and Methods
- public: Accessible from any other class.
- protected: Accessible within the same package and by subclasses (even if they are in different packages).
- default (no modifier): Accessible within the same package only.
- private: Accessible only within the same class.
public class SuperClass {
public String publicVar;
protected String protectedVar;
String defaultVar;
private String privateVar;
public void publicMethod() {
// Method implementation
}
protected void protectedMethod() {
// Method implementation
}
void defaultMethod() {
// Method implementation
}
private void privateMethod() {
// Method implementation
}
}
public class SubClass extends SuperClass {
public void accessSuperClassMembers() {
publicVar = "Public"; // Accessible
protectedVar = "Protected"; // Accessible
defaultVar = "Default"; // Accessible
// privateVar = "Private"; // Not accessible (compile-time error)
publicMethod(); // Accessible
protectedMethod(); // Accessible
defaultMethod(); // Accessible
// privateMethod(); // Not accessible (compile-time error)
}
}
Access Modifiers for Static Attributes and Methods
Static members belong to the class rather than instances. They are inherited in a similar way to instance members, but their access is determined by the same rules as non-static members.
public class SuperClass {
public static String staticVar = "Static Variable";
public static void staticMethod() {
System.out.println("Static method in SuperClass.");
}
}
public class SubClass extends SuperClass {
public void accessSuperClassStaticMembers() {
System.out.println(staticVar); // Accessing static variable
staticMethod(); // Calling static method
}
}
Are Static Methods Inherited?
Static methods are inherited in Java, but they cannot be overridden like instance methods. When a subclass defines a static method with the same signature as a static method in the superclass, it hides the superclass's static method rather than overriding it.
public class SuperClass {
public static void staticMethod() {
System.out.println("Static method in SuperClass.");
}
}
public class SubClass extends SuperClass {
public static void staticMethod() {
System.out.println("Static method in SubClass.");
}
public static void main(String[] args) {
SuperClass.staticMethod(); // Output: Static method in SuperClass.
SubClass.staticMethod(); // Output: Static method in SubClass.
}
}
Syntax for Declaring Top-Level Class
For a top-level class (a class declared outside of any other class), here's the comprehensive list and order:
Keywords that can be used:
- Access modifier:
public
abstract
final
Order:
[public] [abstract|final] class ClassName
Syntax:
[AccessModifier] [AbstractOrFinal] class ClassName {
// Class body
}
Important notes:
- If no access modifier is specified, the class has package-private access (visible only within its package).
-
abstract
andfinal
are mutually exclusive - a class cannot be both. -
protected
andprivate
are not allowed for top-level classes. - The order of keywords matters - access modifier should come first, followed by
abstract
orfinal
.
Syntax for Declaring Nested Classes
Keywords that can be used:
- Access modifiers:
public
,protected
,private
static
abstract
final
Order:
[AccessModifier] [static] [abstract|final] class ClassName
Syntax:
class OuterClass {
[AccessModifier] [static] [AbstractOrFinal] class NestedClassName {
// Nested class body
}
}
Types of nested classes:
- Static nested classes (use
static
keyword) - Non-static nested classes (inner classes, no
static
keyword) - Local classes (defined inside a method)
- Anonymous classes (unnamed classes defined and instantiated in a single expression)
Important notes:
- Nested classes can use any access modifier (
public
,protected
,private
, or package-private). - Static nested classes don't have access to instance members of the outer class.
- Non-static nested classes (inner classes) have access to all members of the outer class, even private ones.
-
abstract
andfinal
are mutually exclusive for nested classes, just as with top-level classes. - Local and anonymous classes can't use access modifiers or be declared static.
- The order of keywords matters - access modifier first, then
static
(if used), followed byabstract
orfinal
.
Syntax for Declaring Attributes in Classes
Keywords that can be used:
- Access modifiers:
public
,protected
,private
static
final
Order:
[AccessModifier] [static] [final] dataType attributeName
Syntax:
class ClassName {
[AccessModifier] [static] [final] dataType attributeName [= initialValue];
}
Important notes:
- If no access modifier is specified, the attribute has package-private access.
-
static
attributes belong to the class rather than instances of the class. -
final
attributes cannot be reassigned after initialization. - The order of keywords matters - access modifier first, then
static
andfinal
(if used). - Initialization is optional. Uninitialized attributes get default values (0, false, or null depending on the type).
Syntax for Declaring Methods in Classes
Keywords that can be used:
- Access modifiers:
public
,protected
,private
static
final
abstract
Order:
[AccessModifier] [static] [final|abstract] returnType methodName(parameters)
Syntax:
class ClassName {
[AccessModifier] [static] [final|abstract] returnType methodName(paramType1 param1, paramType2 param2, ...) [throws ExceptionType] {
// Method body
}
}
Important notes:
- If no access modifier is specified, the method has package-private access.
-
static
methods belong to the class and can be called without creating an instance. -
final
methods cannot be overridden in subclasses. -
abstract
methods have no body and must be implemented by non-abstract subclasses. -
abstract
andfinal
are mutually exclusive. -
abstract
methods cannot beprivate
,static
, orfinal
. - The order of keywords matters - access modifier first, then
static
, followed byfinal
orabstract
.
Inner Classes in Java
Inner classes in Java are classes defined within another class. They offer a way to logically group classes that are only used in one place, increase encapsulation, and improve code organization. Java supports several types of inner classes, each with its own characteristics and use cases.
Types of Inner Classes
Java supports the following types of inner classes:
- Nested Inner Class (Non-static Inner Class)
- Static Nested Class
- Local Inner Class (Method-Local Inner Class)
- Anonymous Inner Class
Let's explore each type in detail:
1. Nested Inner Class (Non-static Inner Class)
- Definition: A nested inner class is a non-static inner class that has access to the enclosing class's instance variables and methods.
- Usage: Typically used for logical grouping and to access outer class members.
- Syntax:
public class OuterClass {
// Outer class members
class InnerClass {
// Inner class members
}
}
- Accessing Inner Class:
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
2. Static Nested Class
- Definition: A static nested class is a nested class that is declared static. It does not have access to the enclosing class's instance variables and methods unless explicitly passed an instance.
- Usage: Useful for grouping classes that are only used in conjunction with the outer class and do not need access to instance-specific data.
- Syntax:
public class OuterClass {
// Outer class members
static class NestedStaticClass {
// Static nested class members
}
}
- Accessing Static Nested Class:
OuterClass.NestedStaticClass nested = new OuterClass.NestedStaticClass();
3. Local Inner Class (Method-Local Inner Class)
- Definition: A local inner class is defined within a method or scope block and has limited visibility and lifespan.
- Usage: Useful when you need to perform some specific tasks and do not want to reuse the class elsewhere in the outer class.
- Syntax:
public class OuterClass {
// Outer class members
public void someMethod() {
class LocalInnerClass {
// Local inner class members
}
LocalInnerClass inner = new LocalInnerClass();
// Use local inner class instance
}
}
- Accessing Local Inner Class: Local inner classes are instantiated within the method/block where they are defined and cannot be accessed outside of it.
Abstract Classes in Java
Abstract classes in Java are used to define common characteristics and behaviors for a group of related classes while allowing for some methods to be implemented by the subclasses. Here’s a comprehensive guide to understanding and using abstract classes in Java:
1. Introduction to Abstract Classes
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 a body).
2. Declaring an Abstract Class
To declare an abstract class, use the abstract
keyword before the class keyword.
Example:
public abstract class Animal {
abstract void makeSound(); // abstract method
void sleep() { // concrete method
System.out.println("Sleeping...");
}
}
3. Abstract Methods
Abstract methods are methods declared without a body and must be implemented by subclasses.
Example:
public abstract class Animal {
abstract void makeSound();
}
public class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
4. Concrete Methods
Concrete methods in an abstract class have a body and can be inherited by subclasses.
Example:
public abstract class Animal {
void eat() {
System.out.println("Eating...");
}
}
5. Creating Subclasses
Subclasses of an abstract class must provide implementations for all abstract methods in the superclass. If a subclass does not implement all abstract methods, it must also be declared abstract.
Example:
public abstract class Animal {
abstract void makeSound();
}
public class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
public class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow");
}
}
6. Instantiating Abstract Classes
Abstract classes cannot be instantiated directly. They can only be instantiated through their concrete subclasses.
Example:
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.makeSound(); // Output: Bark
Animal cat = new Cat();
cat.makeSound(); // Output: Meow
}
}
7. Constructors in Abstract Classes
Abstract classes can have constructors, which are called when a concrete subclass is instantiated.
Example:
public abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
abstract void makeSound();
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
void makeSound() {
System.out.println(name + " says: Bark");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog("Rex");
dog.makeSound(); // Output: Rex says: Bark
}
}
8. Abstract Classes with Fields and Methods
Abstract classes can contain fields (instance variables) and concrete methods that operate on those fields.
Example:
public abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
abstract void makeSound();
void sleep() {
System.out.println(name + " is sleeping");
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
void makeSound() {
System.out.println(name + " says: Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal cat = new Cat("Whiskers");
cat.makeSound(); // Output: Whiskers says: Meow
cat.sleep(); // Output: Whiskers is sleeping
}
}
9. Static Methods in Abstract Classes
Abstract classes can also contain static methods. These methods belong to the class itself rather than to any instance of the class. Static methods in an abstract class can be called without creating an instance of the class.
Example:
public abstract class Animal {
abstract void makeSound();
static void info() {
System.out.println("Animals are multicellular organisms that form the biological kingdom Animalia.");
}
}
public class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
Animal.info(); // Output: Animals are multicellular organisms that form the biological kingdom Animalia.
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
}
}
Syntax for Declaring Abstract Classes in Java
Keywords that can be used:
- Access modifier:
public
abstract
Order:
[public] abstract class ClassName
Syntax:
[public] abstract class ClassName [extends SuperClass] [implements Interface1, Interface2, ...] {
// Abstract class body
}
Examples:
public abstract class Shape { }
abstract class Animal extends LivingOrganism implements Movable { }
Important features and notes:
- Abstract classes can have both abstract and concrete methods.
- Abstract methods syntax:
abstract returnType methodName(parameters);
- Concrete methods are declared normally.
- Abstract classes can have constructors, instance variables, and static members.
- Abstract classes cannot be instantiated directly.
- Subclasses of an abstract class must implement all its abstract methods, or be declared abstract themselves.
Example with methods and variables:
public abstract class Vehicle {
protected String brand;
public Vehicle(String brand) {
this.brand = brand;
}
public abstract void start();
public void stop() {
System.out.println("Vehicle stopped");
}
}
Important notes:
- If no access modifier is specified, the abstract class has package-private access.
- Abstract classes can extend other classes and implement interfaces.
- Abstract classes can have
final
methods, which cannot be overridden in subclasses. - Abstract classes can have static methods and variables.
- Abstract methods cannot have a body.
- Abstract classes cannot be declared as
final
. - Abstract classes can have any number of abstract and non-abstract methods.
Interfaces in Java
Interfaces in Java are a powerful tool for defining contracts that classes can implement. They allow for the definition of methods that must be implemented by any class that chooses to implement the interface. Here's a comprehensive guide to understanding and using interfaces in Java:
1. Introduction to Interfaces
An interface in Java is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. The methods in interfaces are abstract by default (except default and static methods), meaning they do not have a body and must be implemented by classes that implement the interface.
2. Declaring an Interface
To declare an interface, use the interface
keyword.
Example:
public interface Animal {
void eat(); // abstract method
void sleep(); // abstract method
}
3. Implementing an Interface
A class implements an interface by using the implements
keyword. The class must provide concrete implementations for all abstract methods declared in the interface.
Example:
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("Dog is eating");
}
@Override
public void sleep() {
System.out.println("Dog is sleeping");
}
}
4. Multiple Interfaces
A class can implement multiple interfaces, allowing it to inherit the behavior of more than one interface.
Example:
public interface Mammal {
void walk();
}
public class Human implements Animal, Mammal {
@Override
public void eat() {
System.out.println("Human is eating");
}
@Override
public void sleep() {
System.out.println("Human is sleeping");
}
@Override
public void walk() {
System.out.println("Human is walking");
}
}
5. Default Methods
Java 8 introduced default methods in interfaces. These methods have a body and provide a default implementation. Classes that implement the interface can use the default implementation or override it.
Example:
public interface Vehicle {
void start();
default void honk() {
System.out.println("Honking...");
}
}
public class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car is starting");
}
}
6. Static Methods
Interfaces can also have static methods, which belong to the interface itself rather than to instances of classes that implement the interface.
Example:
public interface MathUtils {
static int add(int a, int b) {
return a + b;
}
}
public class Calculator {
public static void main(String[] args) {
int sum = MathUtils.add(5, 3);
System.out.println("Sum: " + sum);
}
}
7. Constants
Interfaces can declare constants, which are implicitly public
, static
, and final
.
Example:
public interface Constants {
int MAX_AGE = 100;
String GREETING = "Hello, World!";
}
public class TestConstants {
public static void main(String[] args) {
System.out.println("Max Age: " + Constants.MAX_AGE);
System.out.println(Constants.GREETING);
}
}
8. Inheritance in Interfaces
An interface can extend another interface, inheriting its methods. A class that implements the sub-interface must implement methods from all parent interfaces.
Example:
public interface Animal {
void eat();
void sleep();
}
public interface Pet extends Animal {
void play();
}
public class Cat implements Pet {
@Override
public void eat() {
System.out.println("Cat is eating");
}
@Override
public void sleep() {
System.out.println("Cat is sleeping");
}
@Override
public void play() {
System.out.println("Cat is playing");
}
}
Syntax for Declaring Interfaces in Java
Keywords that can be used:
- Access modifier:
public
interface
Order:
[public] interface InterfaceName
Syntax:
[public] interface InterfaceName [extends Interface1, Interface2, ...] {
// Interface body
}
Examples:
public interface Drawable { }
interface Runnable extends Executable { }
Components of an interface:
- Constants
(implicitly public, static, and final)
:
Type CONSTANT_NAME = value;
- Abstract methods
(implicitly public and abstract)
:
returnType methodName(parameters);
- Default methods (Java 8+):
default returnType methodName(parameters) {
// Method body
}
- Static methods (Java 8+):
static returnType methodName(parameters) {
// Method body
}
Example interface:
public interface Vehicle {
int MAX_SPEED = 120;
void start();
void stop();
default void honk() {
System.out.println("Beep beep!");
}
static int getMaxSpeed() {
return MAX_SPEED;
}
}
Important notes:
- If no access modifier is specified, the interface has package-private access.
- Interfaces can extend multiple other interfaces.
- All methods in an interface are implicitly
public
andabstract
unless specified asdefault
orstatic
. - All fields in an interface are implicitly
public
,static
, andfinal
. - Interfaces cannot be instantiated directly.
- A class can implement multiple interfaces.
- Since Java 8, interfaces can have default and static methods with implementations.
- Interfaces cannot have constructors.
- Interfaces cannot contain instance fields (non-static variables).
Comparable Interface in Java
In Java, the Comparable
interface is used to define the natural ordering of objects. Classes that implement Comparable
can be sorted into ascending order based on their natural ordering. This interface contains a single method, compareTo
, which compares the current object with another object of the same type.
Overview
- Interface Purpose: Provides a way to impose a natural ordering on the objects of a class.
-
Single Method: Contains the
compareTo
method for comparing objects. -
Generic Support: Supports generic types (
<T extends Comparable<T>>
) to enforce type safety in comparisons.
Method
-
compareTo(T o)
: Compares the current object with the specified object for order. Returns a negative integer, zero, or a positive integer if the current object is less than, equal to, or greater than the specified object, respectively.
public interface Comparable<T> {
public int compareTo(T o);
}
Usage
-
Sorting: Classes that implement
Comparable
can be sorted using methods likeCollections.sort()
orArrays.sort()
which rely on the natural ordering defined bycompareTo
. -
Tree-Based Collections: Used in collections like
TreeSet
orTreeMap
where elements are stored in sorted order based on the natural ordering defined bycompareTo
.
Example
Here's an example of a Person
class implementing Comparable
to define ordering based on age:
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Implementing compareTo method based on age
@Override
public int compareTo(Person otherPerson) {
return Integer.compare(this.age, otherPerson.age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
// Sort people based on natural ordering (age)
Collections.sort(people);
// Print sorted list
System.out.println("Sorted People by Age:");
for (Person person : people) {
System.out.println(person);
}
}
}
Comparator Interface in Java
In Java, the Comparator
interface provides a way to define custom ordering for objects. Unlike Comparable
, which defines natural ordering for a class, Comparator
allows sorting objects based on different criteria that may not be intrinsic to the objects themselves. This interface is particularly useful when you need to sort objects in multiple ways or when you don't have control over the class whose objects you want to sort.
Overview
- Interface Purpose: Allows defining external ordering on objects of a class.
-
Single Method: Contains the
compare
method for comparing two objects. -
Functional Interface: Since Java 8,
Comparator
is a functional interface, but can be implemented without using lambda expressions or anonymous classes.
Method
-
compare(T o1, T o2)
: Compares its two arguments for order. Returns a negative integer, zero, or a positive integer if the first argument is less than, equal to, or greater than the second.
public interface Comparator<T> {
int compare(T o1, T o2);
}
Usage
-
Sorting: Used with sorting methods like
Collections.sort()
orArrays.sort()
to provide custom ordering. -
Tree-Based Collections: Essential for defining sorting order in collections like
TreeSet
orTreeMap
. - Multiple Criteria: Allows sorting objects based on different attributes or criteria.
Example
Here's an example of using Comparator
to sort Person
objects based on their age without using lambda expressions or anonymous classes:
import java.util.*;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getter methods
public String getName() {
return name;
}
public int getAge() {
return age;
}
// Comparator for sorting by age
static class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return Integer.compare(p1.getAge(), p2.getAge());
}
}
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
// Sorting people by age using AgeComparator
Collections.sort(people, new AgeComparator());
// Print sorted list
System.out.println("Sorted People by Age:");
for (Person person : people) {
System.out.println(person.getName() + " - " + person.getAge());
}
}
}
Methods
-
reversed()
: Returns a comparator that imposes the reverse ordering of the current comparator.
Comparator<Person> ageComparator = new AgeComparator();
Comparator<Person> reverseAgeComparator = ageComparator.reversed();
Methods from Object
Class in Java
In Java, every class directly or indirectly inherits from the Object
class. The Object
class provides several fundamental methods that are inherited by all Java objects. Here, we'll explore and explain these methods along with their uses and examples.
toString()
-
Method Signature:
public String toString()
- Description: Returns a string representation of the object. By default, it returns a string consisting of the class name followed by "@" and the object's hash code.
public class Example {
private int value = 10;
@Override
public String toString() {
return "Example{" +
"value=" + value +
'}';
}
public static void main(String[] args) {
Example obj = new Example();
System.out.println(obj.toString()); // Output: Example{value=10}
}
}
- Use: Provides a meaningful string representation of the object's state for debugging and logging purposes.
equals(Object obj)
-
Method Signature:
public boolean equals(Object obj)
-
Description: Indicates whether some other object is "equal to" this one. The default implementation in
Object
class checks if two references point to the same object in memory.
public class Person {
private String name;
// Constructor, getters, setters
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return Objects.equals(name, person.name);
}
public static void main(String[] args) {
Person person1 = new Person("Alice");
Person person2 = new Person("Alice");
System.out.println(person1.equals(person2)); // Output: true
}
}
- Use: Allows custom definition of equality for objects based on specific attributes or criteria.