A class definition serves as a blueprint for creating objects. It consists of:
{}
, contains member definitions.static
, shared by all objects).Methods and fields can technically be arranged in any order within the class body, but common practice often lists methods before fields or groups related members together.
(Based on Slides 3, 5)
Access-modifier class ClassName /* Often same as filename if public */ {
// Field (Attribute) declarations
dataType fieldName1;
dataType fieldName2;
// ...
// Constructor declaration(s)
ClassName(parameters) {
// Initialization code
}
// Method declarations
returnType methodName1(parameters) {
// Method body
}
// ...
}
The order of attributes, constructors, and methods can vary, but the structure remains consistent. (Slide 4)
// Example based on Slide 6
class First {
// --- Fields (Instance Variables) ---
int x, y; // Properties representing integer coordinates or values
String ch; // Property representing a String
// --- Constructor ---
// (Implicit default constructor is used if none is defined,
// or we can define one explicitly like this to set initial values)
public First() {
x = 2;
y = 3;
ch = " "; // Initialize String to a space
}
// --- Methods ---
// Mutator (Setter) method to change x and y
void setXY(int a, int b) {
x = a;
y = b;
}
// Accessor (Getter) method to retrieve the value of x
int getX() {
return x;
}
// Accessor (Getter) method to retrieve the value of y
int getY() {
return y;
}
}
new
keyword..
) is used to access an object's instance variables and call its methods.(Based on Slides 7, 12)
Example: Multiple Objects (Slide 8)
public class Main {
int x = 5; // Instance variable
public static void main(String[] args) {
Main myObj1 = new Main(); // Create Object 1
Main myObj2 = new Main(); // Create Object 2
// Modify the instance variable 'x' for myObj2
myObj2.x = 25;
// Print the value of 'x' for each object
System.out.println(myObj1.x); // Access x of myObj1
System.out.println(myObj2.x); // Access x of myObj2
}
}
Output:
5 25
Shows that changing `myObj2.x` did not affect `myObj1.x`.
Example: Class with Multiple Attributes (Slide 9)
public class Main {
// Instance variables
String fname = "John";
String lname = "Doe"; // Corrected variable name from 'Iname' to 'lname'
int age = 24;
public static void main(String[] args) {
Main myObj = new Main(); // Create an object
// Access the object's attributes
System.out.println("Name: " + myObj.fname + " " + myObj.lname);
System.out.println("Age: " + myObj.age);
}
}
Output:
Name: John Doe Age: 24
It's common practice to define different classes in separate .java
files for better organization. Typically:
FirstFile.java
).main
method, which creates objects of the first class and uses them (e.g., SecondFile.java
).public
class within that file. If there's no public
class, the filename can match any class in the file..java
files first (e.g., javac FirstFile.java SecondFile.java
) and then run the class containing the main
method (e.g., java SecondFile
).(Based on Slides 10, 11)
Example: Two Files (Slide 11)
File 1: `FirstFile.java`
public class FirstFile {
int x = 5; // Instance variable (default access)
}
File 2: `SecondFile.java` (Must be in the same directory/package)
class SecondFile { // Not public, so filename doesn't *have* to be SecondFile.java, but good practice
public static void main(String[] args) {
// Create an object of the FirstFile class
FirstFile myObj = new FirstFile();
// Access the 'x' variable of the myObj instance
System.out.println(myObj.x); // Access is allowed because they are in the same package (default access)
}
}
Compilation and Execution:
javac FirstFile.java SecondFile.java
java SecondFile
Output:
5
You must compile `FirstFile.java` first (or simultaneously) because `SecondFile.java` depends on the `FirstFile` class definition.
Methods define the behavior or actions associated with a class.
myObj.myMethod();
).ClassName.myStaticMethod();
). They cannot directly access instance variables or instance methods (unless they are given an object reference). The main
method is always static.To call an instance method from a static context (like `main`), you first need to create an object of the class.
(Based on Slides 12, 13, 29)
Example: Calling Instance vs. Static Methods (Slide 13, 29)
public class MethodDemo {
// Instance method (needs an object to be called)
public void myInstanceMethod() {
System.out.println("Instance method called.");
}
// Static method (can be called using the class name)
static void myStaticMethod() {
System.out.println("Static method called.");
}
public static void main(String[] args) {
// Calling the static method using the class name
MethodDemo.myStaticMethod();
// Or just myStaticMethod(); if called from within the same class
// Cannot call instance method directly from static context:
// myInstanceMethod(); // This would cause a compilation error
// Must create an object first to call instance methods
MethodDemo myObj = new MethodDemo();
myObj.myInstanceMethod(); // Correct way to call instance method
}
}
Output:
Static method called. Instance method called.
Class Scope: Fields (instance variables and static variables) declared directly within the class body (outside any method) have class scope. This means they are generally accessible from anywhere *within* that class (e.g., from any instance method or static method of that class, respecting static/instance rules).
However, good practice (Encapsulation) often dictates using private
access for fields and manipulating them only through methods (like accessors and mutators).
(Based on Slide 14)
These are common types of methods used to control access to an object's (usually private) fields, supporting the principle of Encapsulation.
getFieldName()
(or isFieldName()
for booleans).return
statement. (Slide 15, 16)public String getName() { return this.name; }
setFieldName(DataType newValue)
.void
return type, takes one argument whose type matches the field's type. Can include validation logic before assigning the value. (Slide 15, 19)public void setName(String name) { this.name = name; }
private
and providing public getters/setters, the class controls how its internal state is accessed and modified. This prevents direct, uncontrolled external modification. (Slide 17)(Based on Slides 15-20)
General Form of Getters/Setters (Slide 20)
public class MyData {
private type field; // Private instance variable
// Public Getter for 'field'
public type getField() {
return field;
}
// Public Setter for 'field'
public void setField(type f) {
// Optional: Add validation logic here
field = f;
}
// Constructor, other methods...
}
Access modifiers control the visibility (accessibility) of classes, fields, methods, and constructors.
(Based on Slides 21, 22, 24, 25)
public
: The class is accessible from any other class, anywhere.public
: Accessible from any other class.private
: Accessible only from within the declared class itself. This is key for encapsulation.protected
: Accessible within the declared class, within other classes in the same package, and within subclasses (even if they are in different packages).Modifier | Same Class | Same Package | Subclass (Different Pkg) | Different Package (Non-Subclass) |
---|---|---|---|---|
public | ✔ | ✔ | ✔ | ✔ |
protected | ✔ | ✔ | ✔ | ✘ |
(default) | ✔ | ✔ | ✘ | ✘ |
private | ✔ | ✘ | ✘ | ✘ |
This table summarizes where a member declared with a given modifier can be accessed from. (Based on Slide 25 structure).
Example: Public Members (Slide 23)
File 1: `Main.java`
// Assume this is in package 'com.example.data'
package com.example.data;
public class Main {
public String fname = "Mohamed";
public String lname = "Ali"; // Corrected name
public String email = "MA@hotmail.com";
public int age = 24;
}
File 2: `Second.java` (Can be in a different package)
// Assume this is in package 'com.example.app'
package com.example.app;
// Import the Main class from the other package
import com.example.data.Main;
public class Second {
public static void main(String[] args) {
Main myObj = new Main(); // Create object of Main
// Access public members from a different package
System.out.println("Name: " + myObj.fname + " " + myObj.lname);
System.out.println("Email: " + myObj.email);
System.out.println("Age: " + myObj.age);
}
}
Output:
Name: Mohamed Ali Email: MA@hotmail.com Age: 24
Example: Private Members & Need for Getters (Slides 34, 35)
File: `Account.java`
public class Account {
private int balance = 1000; // Private instance variable
// Public getter method for balance
public int getBalance() {
return balance;
}
// Maybe add a deposit method (setter concept)
public void deposit(int amount) {
if (amount > 0) {
balance += amount;
}
}
}
File: `BankApp.java`
public class BankApp {
public static void main(String[] args) {
Account myAccount = new Account();
// Cannot access private member directly:
// System.out.println(myAccount.balance); // ERROR: balance has private access in Account
// Must use the public getter method:
System.out.println("Current balance: " + myAccount.getBalance()); // Works! Output: 1000
myAccount.deposit(500);
System.out.println("New balance: " + myAccount.getBalance()); // Output: 1500
}
}
This illustrates why `private` is used (hides internal data) and how getters provide controlled access.
These modifiers provide additional information about the characteristics of classes, methods, and variables, affecting their behavior beyond just visibility.
(Based on Slides 26, 27, 30, 31)
final
: The class cannot be subclassed (inherited from). Useful for creating immutable classes or preventing extension.abstract
: The class cannot be used to create objects (cannot be instantiated). It must be subclassed, and typically contains one or more abstract
methods (methods without a body) that subclasses must implement.final
:
static
:
abstract
:
abstract
class. Subclasses (non-abstract ones) are required to provide an implementation (override the method).Note: abstract
cannot be used with final
(an abstract class must be subclassed, a final class cannot be; an abstract method must be overridden, a final method cannot be). abstract
cannot be used with private
(an abstract method needs to be overridden by a subclass, which wouldn't be possible if it were private).
public
, private
, protected
, default) determine *who* can access a class or member (scope restriction).final
, static
, abstract
, etc.) define *characteristics* or *behavior* of the class or member (immutability, class-level association, requirement for implementation).Example: `final` variable (Slide 28)
public class Constants {
final int MAX_USERS = 100; // A final instance variable (constant for this object)
final double PI = 3.14159; // Another final instance variable
static final String DEFAULT_GREETING = "Hello"; // A static final variable (class constant)
public static void main(String[] args) {
Constants c = new Constants();
// c.MAX_USERS = 200; // ERROR: cannot assign a value to final variable MAX_USERS
// c.PI = 3.0; // ERROR: cannot assign a value to final variable PI
System.out.println("Max Users: " + c.MAX_USERS); // Output: 100
System.out.println("Default Greeting: " + Constants.DEFAULT_GREETING); // Output: Hello
// Constants.DEFAULT_GREETING = "Hi"; // ERROR: cannot assign a value to final variable
}
}
Example: `static` members (Slides 29, 36-39)
File: `Counter.java`
public class Counter {
private static int instanceCount = 0; // Static variable: shared by all objects
private int id; // Instance variable: unique to each object
public Counter() {
instanceCount++; // Increment shared counter whenever a new object is created
this.id = instanceCount; // Assign unique ID based on the count
}
// Static method to get the shared count
public static int getInstanceCount() {
// Cannot access 'this.id' here because it's an instance variable
return instanceCount;
}
// Instance method to get the object's unique ID
public int getId() {
return this.id;
}
}
File: `TestCounters.java`
public class TestCounters {
public static void main(String[] args) {
System.out.println("Initial count: " + Counter.getInstanceCount()); // Access static method via class name
Counter c1 = new Counter();
System.out.println("Count after c1: " + Counter.getInstanceCount()); // Output: 1
System.out.println("c1 ID: " + c1.getId()); // Output: 1
Counter c2 = new Counter();
System.out.println("Count after c2: " + Counter.getInstanceCount()); // Output: 2
System.out.println("c2 ID: " + c2.getId()); // Output: 2
// Accessing static member via object reference works but is discouraged:
// System.out.println(c1.getInstanceCount()); // Still outputs 2
// Example of accessing static variable directly (if it were public)
// Assume 'public static int a = 12;' in class StaticVariables (Slide 37)
// System.out.println(StaticVariables.a); // Output: 12
// Example of accessing private static variable via static getter (Slide 39)
// Assume 'private static int a = 12;' and 'public static int getA()' in StaticVariables
// System.out.println(StaticVariables.getA()); // Output: 12
}
}
Output:
Initial count: 0 Count after c1: 1 c1 ID: 1 Count after c2: 2 c2 ID: 2
Example: `abstract` class and method (Slides 40, 41)
File 1: `Animal.java`
// Abstract class - cannot be instantiated directly
abstract class Animal {
// Instance variable
public String name;
// Abstract method - no implementation, must be overridden by non-abstract subclasses
public abstract void makeSound();
// Concrete method (regular method with implementation)
public void sleep() {
System.out.println("Zzz...");
}
}
File 2: `Dog.java` (Subclass)
// Concrete subclass extending the abstract class
class Dog extends Animal {
// Provides implementation for the abstract method
@Override
public void makeSound() {
System.out.println("Woof Woof");
}
}
File 3: `TestAbstract.java`
public class TestAbstract {
public static void main(String[] args) {
// Cannot create an object of the abstract class Animal:
// Animal myAnimal = new Animal(); // ERROR: Animal is abstract; cannot be instantiated
// Create an object of the concrete subclass Dog
Dog myDog = new Dog();
myDog.name = "Buddy";
myDog.makeSound(); // Calls the implemented method in Dog
myDog.sleep(); // Calls the concrete method inherited from Animal
}
}
Output:
Woof Woof Zzz...