Classes and Objects

● Attributes and methods

● Object (instance)

● Information hiding

● Encapsulation

● Constructors

● Packages




Class:

A class is a type that is defined by the user in a programming language. It serves as a blueprint or template that describes both the data (attributes) and the behaviour (methods) that objects of that class will possess.

In object-oriented programming, objects are instances of a class. When a class is instantiated, an object of that class is created, which has its own set of attributes and can perform actions based on the methods defined in the class.

To understand it better, you can think of a class as a blueprint for a specific type of object. It defines the properties or characteristics (attributes) that an object of that class will have, such as its name, size, colour, etc. Additionally, it also defines the actions or operations (methods) that the object can perform, such as calculating a value, displaying information, or interacting with other objects.

By using classes, developers can organize and structure their code more efficiently. They can create multiple objects of the same class, each with its own unique set of attribute values, while still sharing the same behaviour defined by the class's methods.






Class declaration in Java follows a specific syntax. Here is the syntax for declaring classes in Java:

<modifier>* class <class_name> {
    <attribute_declaration>*
    <constructor_declaration>*
    <method_declaration>*
}

Let's break down the different components of the class declaration syntax:

<modifier>: This refers to an optional modifier that specifies the access level of the class, such as public, private, or protected. It determines the visibility and accessibility of the class to other classes.
class: The keyword class is used to declare that we are defining a new class.
<class_name>: This is the name given to the class. It should follow the naming conventions, such as starting with a capital letter and using a camel case.
<attribute_declaration>*: This represents the declaration of attributes or instance variables of the class. Attributes define the data associated with objects of the class.
<constructor_declaration>*: This denotes the declaration of constructors for the class. Constructors are special methods that are called when an object is created from the class. They are used to initialize the object's state.
<method_declaration>*: This indicates the declaration of methods within the class. Methods define the behaviour or actions that objects of the class can perform. They can be called to manipulate the object's data or perform specific tasks.


Following the syntax, here's an example of a class declaration in Java:

java:

public class Counter {
    private int value;

    public void inc() {
        ++value;
    }

    public int getValue() {
        return value;
    }
}

In this example, we define a class called Counter with a private attribute value, a method inc() to increment the value and a method getValue() to retrieve the current value. The class is declared as public, which means it can be accessed from other classes. The attribute is private, limiting its access to only the class itself.





Attributes and methods:

Attributes in OOP represent the data or properties of an object, while methods define the actions or behaviours that an object can perform. Attributes store information, and methods perform operations on that information. They work together to define the structure and behaviour of objects in object-oriented programming.


When declaring attributes in Java, you can use the following syntax:

<modifier>* <type> <attribute_name>[= <initial_value>];



Let's break down the different parts of the attribute declaration syntax:

<modifier>: This represents an optional modifier that specifies the access level or other properties of the attribute. It can be public, private, protected, or no modifier (default access).
<type>: This specifies the data type of the attribute, such as int, float, String, or any other valid Java data type.
<attribute_name>: This is the name given to the attribute. It should follow the naming conventions, such as starting with a letter and using a camel case.
= <initial_value>: This is an optional part that allows you to initialize the attribute with a default value. The initial value is assigned to the attribute when an object of the class is created.


Here are some examples of attribute declarations in Java:

java:

public class Foo {
    private int x;
    private float f = 0.0f;
    private String name = "Anonymous";
}


In the above example, the class Foo declares three attributes: x, f, and name. The x attribute is declared without an initial value, so it will be assigned the default value for its data type (0 for int). The f attribute is declared with an initial value of 0.0f, indicating a floating-point value. The name attribute is declared with an initial value of "Anonymous", specifying a string value.


Remember to specify the appropriate data type for each attribute and provide an optional initial value if necessary.





When declaring methods in Java, you can use the following syntax:

<modifier>* <return_type> <method_name>(<argument>*){ <statement>* }


Let's break down the different parts of the method declaration syntax:

<modifier>: This represents an optional modifier that specifies the access level or other properties of the method. It can be public, private, protected, or no modifier (default access).
<return_type>: This specifies the data type of the value that the method returns. It can be a primitive type (e.g., int, float) or a reference type (e.g., String, Object) or void if the method does not return any value.
<method_name>: This is the name given to the method. It should follow the naming conventions, such as starting with a letter and using a camel case.
<argument>*: This represents zero or more arguments or parameters that the method accepts. Each argument is specified with a data type and a name. Multiple arguments are separated by commas.
<statement>*: This includes the statements or code that define the functionality of the method. It represents the logic or operations that the method performs.



Here are some examples of attribute declarations in Java:

java:

public class Counter {
    public static final int MAX = 100;
    private int value;

    public void inc() {
        if (value < MAX) {
            ++value;
        }
    }

    public int getValue() {
        return value;
    }
}


In the above example, the class Counter declares two methods: inc() and getValue(). The inc() the method does not have a return type (void) and does not accept any arguments. It increments the value of the Counter object if it is less than the maximum value. The getValue() method returns a int value and does not require any arguments. It retrieves the current value of the Counter object.

By declaring methods within a class, you define the behaviour or actions that objects of the class can perform. These methods can access the class's attributes and manipulate them as needed. Methods are invoked on an object using dot notation, where the object reference is followed by the method name and any required arguments.

Remember to specify the correct return type, method name, and argument list for each method, and include the necessary statements to define the functionality of the method.





Object (instance):

An object in object-oriented programming (OOP) is a specific instance of a class that combines attributes (data) and methods (behaviours) defined by its class, representing a real-world entity.

To access members (attributes and methods) of an object in Java, you use the following syntax:

<object>.<member>


For example, consider the following class "Counter" with attributes and methods:

public class Counter {
    public static final int MAX = 100;
    private int value = 0;

    public void inc() {
        if (value < MAX) {
            ++value;
        }
    }

    public int getValue() {
        return value;
    }
}


To access the members of an object of the "Counter" class, you first create an instance of the class using the `new` keyword:

Counter c = new Counter();

Then, you can access the members of the object `c` using the dot operator (`.`). For example:

c.inc(); // Accesses the method 'inc()' of the 'Counter' object 'c'
int i = c.getValue(); // Accesses the method 'getValue()' of the 'Counter' object 'c'


In the above code, `c.inc()` calls the `inc()` method of the `Counter` object `c`, and `c.getValue()` retrieves the value of the `value` attribute of the `Counter` object `c`.

This way, you can access and manipulate the members of an object to perform various operations or retrieve information as needed.








Information hiding:


let us see a code in c language:(problem)

/* C language */

struct Date {
 int year, month, day;
};


/* C language */

Date d;
 d.day = 37; //invalid day
 d.month = 2;
 d.day = 30; 
// invalid data
 d.day = d.day + 1; //No check


In the above code, the client code has direct access to the internal data of the Date structure. This means that the client code can manipulate the data directly without any validation or checks.

In the given code snippet, the client code is accessing the 'day' field of the Date structure and assigning invalid values to it. For example, the code assigns 37 to 'day' which is an invalid day value since days range from 1 to 31. Similarly, it assigns 30 to 'day' after setting 'month' to 2, which is also invalid since February has a maximum of 29 days (in a leap year) or 28 days (in a non-leap year).

Furthermore, there are no checks or validations in place to ensure that the data remains valid. For instance, there is no check to prevent the 'day' value from exceeding the maximum number of days for a given month.

This lack of information hiding and data validation can lead to inconsistent or incorrect data being stored and processed.


To enforce information hiding, you should modify the access modifiers of the internal data fields to private. Here's an updated version of the solution in Java:(solution)

/* Java language */
public class Date { private int year, month, day; public void setDay(int day) { // Add validation logic here this.day = day; } public void setMonth(int month) { // Add validation logic here this.month = month; } public void setYear(int year) { // Add validation logic here this.year = year; } public int getDay() { return day; } public int getMonth() { return month; } public int getYear() { return year; } }

In this updated code, the year, month, and day fields are declared as private, ensuring that they cannot be accessed directly from the client code. The setter methods (setDay(), setMonth(), setYear()) allow controlled access to modify the internal data, and the getter methods (getDay(), getMonth(), getYear()) allow retrieval of the data.

Here's an example usage of the Date class:

/* Java language */

Date d = new Date();
d.setDay(37); // Invalid day, validation can be added in the setter method
d.setMonth(2);
d.setDay(30); // Invalid day, validation can be added in the setter method


By making the internal data private and providing controlled access through public methods, you can enforce data validation and ensure that the client code interacts with the data in a controlled manner, preventing the assignment of invalid values directly.










Encapsulation is a fundamental principle of object-oriented programming that involves bundling data and methods together within a class, providing a way to restrict direct access to certain components of an object. This bundling ensures that the internal representation and operations on the data are hidden from external code.

Encapsulation hides the implementation details of a class, allowing it to change without affecting external code.
It enforces the use of an interface to access data and functionality.
Encapsulation improves code maintainability by organizing code, isolating changes, and promoting modularity.

Here's a simple example of encapsulation in Java:
/* Java language */

public class Person {
    private String name;
    private int age;
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void setAge(int age) {
        if (age >= 0) {
            this.age = age;
        } else {
            System.out.println("Invalid age value");
        }
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
}


In this example, the Person class encapsulates the data related to a person's name and age. The data fields (name and age) are declared as private, preventing direct access from external code.

The class provides public setter methods (setName() and setAge()) to modify the name and age values. These methods allow validation or additional logic to be applied before updating the internal data. For example, the setAge() method checks if the age value is non-negative before updating the internal age field.

The class also provides public getter methods (getName() and getAge()) to retrieve the name and age values. These methods provide controlled access to the internal data.

Here's an example usage of the Person class:
/* Java language */

Person person = new Person();
person.setName("John Doe");
person.setAge(25);

System.out.println("Name: " + person.getName()); // Output: Name: John Doe
System.out.println("Age: " + person.getAge()); // Output: Age: 25


In this example, the external code interacts with the Person object using the public setter and getter methods. The internal data (name and age) remains encapsulated and can only be accessed and modified through the defined interface, ensuring controlled and validated access to the data.














Constructors:

Constructors are special member functions in a class that are responsible for initializing the objects of that class.


Declaring Constructors Syntax:

[<modifier>] <class_name>(<argument>){
    <statement>*
}


Here's an example demonstrating constructor overloading:

/* Java language */

class Codemummy {
private int myInt;
private double myDouble;
  
 //constructor 
public Codemummy() {
        myInt = 5;
        myDouble = 5.0;
    }
}



Constructors have the following characteristics:

  1. Role: The main role of a constructor is to initialize the object's data members and set up its initial state.

  2. Name: The name of the constructor must be the same as the name of the class. This is how the compiler identifies the constructor when it is called.

  3. Return type: Constructors do not have a return type, not even void. They are automatically called when an object is created and cannot be explicitly called like regular member functions.

  4. Default constructor: If you don't explicitly define a constructor for a class, the compiler will generate a default constructor for you. The default constructor takes no arguments and initializes the object's data members to their default values (e.g., 0 for numeric types, null for pointers, etc.).

  5. Accessibility: Constructors are usually declared as public so that they can be called from anywhere in the program. However, constructors can also be declared private, making them accessible only within the class itself. Private constructors are often used in design patterns like the singleton pattern.

  6. Multiple constructors: A class can have more than one constructor, and they can be overloaded with different parameter lists. This allows for creating objects with different initializations or providing flexibility when creating objects.






Default Constructor:

Every class has at least one constructor: Constructors are special methods used to initialize objects. It is a requirement for every class to have at least one constructor.

The default constructor is generated by the compiler: If the programmer does not provide any constructors in a class, the compiler automatically generates a default constructor. This ensures that objects can still be created and initialized.

Default constructor takes no arguments: The default constructor, generated by the compiler, does not accept any arguments or parameters. It is a constructor without any inputs.

Default constructor's body is empty: The body of the default constructor, by default, is empty. It does not contain any code or instructions. It does not perform any specific actions or initialization tasks unless the programmer adds code to it.

To summarize, the default constructor is automatically generated by the compiler if no constructors are explicitly provided in a class. It takes no arguments and has an empty body. Its purpose is to allow object creation and provide a basic initialization mechanism when no custom constructor is defined.






Constructor overloading:


Constructor overloading refers to defining multiple constructors in a class with different parameter lists. This allows objects to be created with different sets of arguments. The compiler determines which constructor to call based on the arguments passed during object creation.

Here's an example demonstrating constructor overloading:

/* Java language */

class Codemummy {
private:
    int myInt;
    double myDouble;
    
public:
    // Default constructor
    Codemummy() {
    }
    
    // Constructor with one parameter
    Codemummy(int intValue) {
        myInt = intValue;
        myDouble = 0.0;
    }
    
    // Constructor with two parameters
    Codemummy(int intValue, double doubleValue) {
        myInt = intValue;
        myDouble = doubleValue;
    }
};

int main() {
    Codemummy obj1;                 // Calls the default constructor
    Codemummy obj2(5);              // Calls the constructor with one parameter
    Codemummy obj3(10, 3.14);       // Calls the constructor with two parameters
    
    return 0;
}



In the above example, the Codemummy Class has three constructors: a default constructor, a constructor with one parameter, and a constructor with two parameters. Depending on how the objects obj1, obj2, and obj3 are created, the appropriate constructor is called to initialize the object accordingly.

Constructor overloading provides flexibility in creating objects with different initializations based on the available constructors.




points:
Objects in Java are allocated on the heap memory using the "new" operator.
The "new" operator dynamically allocates memory for an object and returns a reference to that object.
When an object is created using "new", the constructor of its class is automatically invoked.












Packages:

Packages are used to manage large software systems in Java. They provide a way to organize classes and sub-packages within a project, making it easier to manage and locate them.

A package contains related classes and can also include sub-packages, forming a hierarchical structure. This helps in organizing classes based on their functionality or purpose.

Some commonly used packages in Java java.lang, java.util, java.io, java.awt, java.math




Package statement:
The package statement is used to define the package of a Java class.
It is placed at the beginning of the source file before any class declarations.
There can only be one package declaration per source file.
If no package name is declared, the class is placed into the default package.
The package name follows a hierarchical structure with periods (.) separating the levels.
Packages help organize and manage large software systems by grouping related classes together.
Sub-packages can be created within a package to further organize classes.
The package statement provides a namespace for the classes, preventing naming conflicts.
It allows for better code organization, reusability, and maintainability.



The package statement in Java has the following syntax:

package <top_pkg_name>[.<sub_pkg_name>]*;


Example:
/* Java language */

package java.lang;
public class String {
  // ...
}





Import statement:
The import statement is used in Java to specify the classes or packages that need to be used in a source file.

The import statement in Java has the following syntax:

import <pkg_name>[.<sub_pkg_name>]*.*; 
or
import <pkg_name>[.<sub_pkg_name>]*.<class_name>;


It is placed before any class declarations in the source file.
The import statement tells the compiler where to find the classes or packages that are referenced in the code.
It allows for the use of short class names instead of fully qualified names in the code.
The asterisk (*) in the import statement imports all classes within a package while specifying a specific class name imports only that class.
Multiple import statements can be used in a source file to import classes from different packages.
The import statement helps to avoid naming conflicts and improves code readability by providing a shorter and more concise syntax for class references.
It is essential when using classes from external libraries or packages in Java programs.














No comments

darkmode