Lesson ৮ মিনিট পড়া

ক্লাস এবং অবজেক্ট (Classes & Objects)

একেবারে শুরু থেকে আপনার নিজস্ব ডেটা টাইপ তৈরি করুন

ক্লাস = ব্লুপ্রিন্ট, অবজেক্ট = বাড়ি (Classes = Blueprints, Objects = Houses)

কল্পনা করুন আপনি একজন স্থপতি বা আর্কিটেক্ট (architect)। আপনি একটি বাড়ির জন্য ব্লুপ্রিন্ট (blueprint) বা নকশা আঁকলেন — সেখানে বলা আছে "প্রতিটি বাড়ির একটি রং থাকবে, নির্দিষ্ট সংখ্যক ঘর থাকবে এবং একটি দরজা থাকবে যা খোলা বা বন্ধ করা যাবে।" এই ব্লুপ্রিন্টটিই হলো একটি ক্লাস (class)

যখন আপনি সেই নকশা অনুযায়ী সত্যিই একটি বাড়ি তৈরি করেন, তখন আপনি একটি অবজেক্ট (object) পান (যাকে ইনস্ট্যান্স বা instance-ও বলা হয়)। আপনি একই ব্লুপ্রিন্ট ব্যবহার করে অনেকগুলো বাড়ি তৈরি করতে পারেন — একটি লাল রঙের, একটি নীল রঙের, একটি ৩ ঘরের, আবার একটি ৫ ঘরের। প্রতিটি বাড়িই নিজে থেকে একেকটি আলাদা অবজেক্ট, কিন্তু সেগুলো সবই একই নকশা বা কাঠামো মেনে তৈরি।

একটি ক্লাস মূলত দুটি জিনিসকে একসাথে যুক্ত রাখে:

  • ফিল্ড (Fields) (যাকে অনেক সময় ইনস্ট্যান্স ভ্যারিয়েবলও বলা হয়) — অবজেক্টগুলো যে ডেটা বা তথ্য ধারণ করে (যেমন রং, নাম, স্কোর)
  • মেথড (Methods) — অবজেক্টগুলো যেসব কাজ করতে পারে (যেমন দৌড়ানো, লাফ দেওয়া, হিসাব করা)

আপনার প্রথম ক্লাস (Your First Class)

public class Main {
// Define a Dog class inside Main for this example
static class Dog {
String name;
String breed;
int age;
// Constructor — runs when you create a new Dog
Dog(String name, String breed, int age) {
this.name = name; // 'this' means "this object's" field
this.breed = breed;
this.age = age;
}
// Method — something a Dog can do
void bark() {
System.out.println(name + " says: Woof!");
}
void describe() {
System.out.println(name + " is a " + age + "-year-old " + breed + ".");
}
}
public static void main(String[] args) {
// Create objects from the blueprint
Dog rex = new Dog("Rex", "German Shepherd", 5);
Dog luna = new Dog("Laboni", "Golden Retriever", 3);
rex.describe();
rex.bark();
luna.describe();
luna.bark();
}
}
Output
Rex is a 5-year-old German Shepherd.
Rex says: Woof!
Laboni is a 3-year-old Golden Retriever.
Laboni says: Woof!

অ্যাক্সেস মডিফায়ার এবং এনক্যাপসুলেশন (Access Modifiers & Encapsulation)

কোনো ক্লাসের ভেতরের সবকিছুরই যে বাইরে থেকে অ্যাক্সেস বা প্রবেশের অনুমতি থাকতে হবে, এমন কোনো কথা নেই। ধরুন একটি এটিএম (ATM) মেশিনের কথা — আপনি কার্ড ঢোকাতে পারেন এবং পিন দিতে পারেন (এটি হলো পাবলিক ইন্টারফেস বা public interface), কিন্তু আপনি চাইলেও মেশিনের ভেতর হাত ঢুকিয়ে এর টাকার বাক্স বা কলকব্জা নাড়তে পারবেন না (এটি হলো প্রাইভেট ইন্টারনাল বা private internals)।

জাভাতে এই ব্যাপারগুলো নিয়ন্ত্রণ করার জন্য অ্যাক্সেস মডিফায়ার (access modifiers) রয়েছে:

  • public — যে কেউ এতে অ্যাক্সেস করতে পারবে। এটি অনেকটা সদর দরজার মতো।
  • private — এটি কেবল ওই একই ক্লাসের ভেতরের কোড থেকেই অ্যাক্সেস করা যাবে। এটি তালাবদ্ধ সিন্দুকের মতো।
  • protected — এর নিজের ক্লাসের ভেতর থেকে এবং এর সাবক্লাস (subclass) থেকে অ্যাক্সেস করা যাবে।
  • (modifier ছাড়া) — একে "প্যাকেজ-প্রাইভেট (package-private)" বলা হয়, যা কেবল একই প্যাকেজের (package) ভেতর থেকে অ্যাক্সেস করা যায়।

ভেতরের ডেটাকে লুকিয়ে রেখে কেবল প্রয়োজনীয় অংশটুকুই বাইরে প্রকাশ করার এই চর্চাকে বলা হয় এনক্যাপসুলেশন (encapsulation)। আপনি গেটার (getters) এবং সেটার (setters) ব্যবহার করে প্রাইভেট ফিল্ডগুলোর অ্যাক্সেস নিয়ন্ত্রণ করতে পারেন।

গেটার এবং সেটার দিয়ে এনক্যাপসুলেশন (Encapsulation with Getters & Setters)

public class Main {
static class BankAccount {
private String owner;
private double balance;
BankAccount(String owner, double initialBalance) {
this.owner = owner;
this.balance = initialBalance;
}
// Getter — read the balance
public double getBalance() {
return balance;
}
// Getter — read the owner
public String getOwner() {
return owner;
}
// Controlled deposit — no negative deposits!
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited $" + amount);
} else {
System.out.println("Invalid amount!");
}
}
// Controlled withdrawal
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrew $" + amount);
} else {
System.out.println("Can't withdraw $" + amount);
}
}
}
public static void main(String[] args) {
BankAccount acc = new BankAccount("Anika", 100.0);
System.out.println(acc.getOwner() + "'s balance: $" + acc.getBalance());
acc.deposit(50);
acc.withdraw(30);
acc.withdraw(200); // too much!
acc.deposit(-10); // sneaky!
System.out.println("Final balance: $" + acc.getBalance());
}
}
Output
Anika's balance: $100.0
Deposited $50.0
Withdrew $30.0
Can't withdraw $200.0
Invalid amount!
Final balance: $120.0

স্ট্যাটিক বনাম ইনস্ট্যান্স (Static vs Instance)

public class Main {
static class Player {
static int totalPlayers = 0; // shared across ALL players
String name; // unique to each player
int score; // unique to each player
Player(String name) {
this.name = name;
this.score = 0;
totalPlayers++; // every new player increases the count
}
void addScore(int points) {
this.score += points;
}
// Static method — belongs to the class, not any one player
static int getTotalPlayers() {
return totalPlayers;
}
}
public static void main(String[] args) {
System.out.println("Players: " + Player.getTotalPlayers());
Player p1 = new Player("Mario");
Player p2 = new Player("Luigi");
Player p3 = new Player("Peach");
p1.addScore(100);
p2.addScore(80);
System.out.println("Players: " + Player.getTotalPlayers());
System.out.println(p1.name + ": " + p1.score);
System.out.println(p2.name + ": " + p2.score);
}
}
Output
Players: 0
Players: 3
Mario: 100
Luigi: 80
Note: স্ট্যাটিক (static)-কে ক্লাসরুমের দেয়ালে ঝোলানো একটি পোস্টারের মতো ভাবতে পারেন — এর একটি কপিই থাকে, এবং সবাই একই জিনিস দেখতে পায়। অন্যদিকে ইনস্ট্যান্স (Instance) ভ্যারিয়েবলগুলো হলো প্রতিটি শিক্ষার্থীর নিজস্ব খাতার মতো — সবার খাতা আলাদা এবং নিজের মতো। যেসব জিনিস সত্যিকার অর্থেই সম্পূর্ণ ক্লাসের সাথে সম্পর্কিত (যেমন খেলোয়াড়দের মোট সংখ্যা গণনা করা), নির্দিষ্ট কোনো অবজেক্টের সাথে নয় — কেবল সেসব ক্ষেত্রেই স্ট্যাটিক ব্যবহার করুন।
চ্যালেঞ্জ

ছোট কুইজ

'this' কিওয়ার্ডটি কী নির্দেশ করে?
MethodsInheritance & Polymorphism