บทนำ: ปัญหาของ Instance Variables
จนถึงตอนนี้ attributes ที่เราใช้ เป็นของแต่ละ object
java// ❌ ปัญหา: แต่ละ object มีค่าแยกกัน
public class Student {
private String name; // instance variable
private double gpa; // instance variable
}
// สร้าง 3 objects
Student john = new Student("John", 3.75);
Student jane = new Student("Jane", 3.50);
Student bob = new Student("Bob", 3.90);
// แต่ละ object มีข้อมูลของตัวเอง
System.out.println(john.name); // "John"
System.out.println(jane.name); // "Jane"
System.out.println(bob.name); // "Bob"
ปัญหา: บางครั้ง ต้องการข้อมูลที่แชร์กัน ทั้ง class
text❌ ทำไมถึงต้องการ shared data?
มหาวิทยาลัย: "Bangkok University"
- john.university = "Bangkok University"
- jane.university = "Bangkok University"
- bob.university = "Bangkok University"
❓ ทำไมต้องเก็บแบบเดียวกัน 3 ครั้ง?
ยาวไปอยากเลือกอ่าน
- บทนำ: ปัญหาของ Instance Variables
- Static Variable คืออะไร?
- Instance vs Static: ความต่างกัน
- ตัวอย่าง Visual: Instance vs Static
- ประกาศ Static Variable
- Syntax
- ตัวอย่าง: การประกาศ
- Static Shared Counter
- ตัวอย่างที่ 1: นับจำนวน Objects
- ตัวอย่างที่ 2: สกุลเงิน (Currency Conversion)
- Static Accumulator
- ตัวอย่างที่ 3: บันทึกรวมรายการขาย
- Static Constant (Static Final)
- ตัวอย่างที่ 4: Configuration Constants
- Static Method vs Instance Method
- ตัวอย่างที่ 5: Math Utility
- Static Initialization Block
- ตัวอย่างที่ 6: Static Initializer
- ตัวอย่างที่ 7: University System
- Static vs Instance: คำว่า "this"
- ความแตกต่าง
- ตัวอย่างที่ 8: ความเข้าใจถึง Scope
- Best Practices: Static Variable
- 1. Static Final สำหรับ Constants
- 2. Private Static สำหรับ Internal Data
- 3. Static Method สำหรับ Utility
- 4. ระวัง: Static Mutable
- สรุป: Static Variable
- ตัวอย่างสุดท้าย: Real-World Scenario
Static Variable คืออะไร?
Static Variable = ข้อมูลที่เป็นของ Class ทั้งหมด (ไม่ใช่ของแต่ละ object)
javapublic class Student {
// Static variable - เป็นของ Class (shared)
public static String universityName = "Bangkok University";
// Instance variable - เป็นของแต่ละ object
private String name;
}
// ใช้งาน
Student.universityName = "Bangkok University"; // ← เข้าถึงจาก Class
System.out.println(Student.universityName); // "Bangkok University"
Instance vs Static: ความต่างกัน
text┌────────────────┬───────────────────┬──────────────────┐
│ │ Instance Variable │ Static Variable │
├────────────────┼───────────────────┼──────────────────┤
│ เป็นของ │ แต่ละ object │ Class ทั้งหมด │
│ จำนวน │ หนึ่งต่อ object │ หนึ่งต่อ class │
│ ค่า │ อาจต่างกัน │ เดียวกัน │
│ หน่วยความจำ │ ใน heap │ ใน static area │
│ เข้าถึง │ object.var │ ClassName.var │
│ ช่วงชีวิต │ object สร้าง→ลบ │ program start→end│
└────────────────┴───────────────────┴──────────────────┘
ตัวอย่าง Visual: Instance vs Static
text┌─────────────────────────────────────────────┐
│ Heap Memory (Instance Variables) │
│ │
│ john (Student object) │
│ ├─ name = "John" │
│ └─ gpa = 3.75 │
│ │
│ jane (Student object) │
│ ├─ name = "Jane" │
│ └─ gpa = 3.50 │
│ │
│ bob (Student object) │
│ ├─ name = "Bob" │
│ └─ gpa = 3.90 │
│ │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Static Area (Class Variables) │
│ │
│ Student.class │
│ └─ universityName = "Bangkok University" │
│ (shared by all objects) │
│ │
└─────────────────────────────────────────────┘
ประกาศ Static Variable
Syntax
java[access modifier] static [type] [variableName] = [initial value];
ตัวอย่าง:
public static String universityName;
private static int totalStudents;
public static final double PI = 3.14159;
protected static int counter = 0;
ตัวอย่าง: การประกาศ
javapublic class Student {
// STATIC VARIABLES
public static String universityName = "Bangkok University"; // ← public static
private static int totalStudents = 0; // ← private static
public static final int MAX_YEAR = 4; // ← static final (constant)
private static double totalGPA = 0; // ← private static
// INSTANCE VARIABLES
private String name;
private double gpa;
private int year;
}
Static Shared Counter
ตัวอย่างที่ 1: นับจำนวน Objects
javapublic class Student {
// Static variable - นับทั้งหมด
private static int totalStudents = 0;
// Instance variables
private String name;
private double gpa;
// Constructor
public Student(String name, double gpa) {
this.name = name;
this.gpa = gpa;
totalStudents++; // ← เพิ่มนับ
}
// Getter
public static int getTotalStudents() {
return totalStudents;
}
public String getName() {
return name;
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
System.out.println("Total: " + Student.getTotalStudents()); // 0
Student student1 = new Student("John", 3.75);
System.out.println("Total: " + Student.getTotalStudents()); // 1
Student student2 = new Student("Jane", 3.50);
System.out.println("Total: " + Student.getTotalStudents()); // 2
Student student3 = new Student("Bob", 3.90);
System.out.println("Total: " + Student.getTotalStudents()); // 3
}
}
Output:
textTotal: 0
Total: 1
Total: 2
Total: 3
ตัวอย่างที่ 2: สกุลเงิน (Currency Conversion)
javapublic class CurrencyConverter {
// Static variables - อัตราแลกเปลี่ยน (shared)
private static double thbToUSD = 35.5; // 1 USD = 35.5 THB
private static double thbToEUR = 38.0; // 1 EUR = 38.0 THB
private static double thbToJPY = 0.28; // 1 JPY = 0.28 THB
// Static methods - convert
public static double thbToUsdAmount(double thb) {
return thb / thbToUSD;
}
public static double usdToThbAmount(double usd) {
return usd * thbToUSD;
}
// Update rates (global change)
public static void updateUSDRate(double newRate) {
thbToUSD = newRate;
System.out.println("✓ USD rate updated to: " + newRate);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
System.out.println("=== Initial Rates ===");
System.out.println("5000 THB = " + CurrencyConverter.thbToUsdAmount(5000) + " USD");
System.out.println("100 USD = " + CurrencyConverter.usdToThbAmount(100) + " THB");
System.out.println("\n=== Update Rate ===");
CurrencyConverter.updateUSDRate(36.0); // อัตราเปลี่ยน
System.out.println("5000 THB = " + CurrencyConverter.thbToUsdAmount(5000) + " USD");
System.out.println("100 USD = " + CurrencyConverter.usdToThbAmount(100) + " THB");
}
}
Static Accumulator
ตัวอย่างที่ 3: บันทึกรวมรายการขาย
javapublic class Store {
// Static variables - ติดตามรวมทั้ง store
private static double totalRevenue = 0; // รายได้รวม
private static int totalTransactions = 0; // จำนวน transaction
private static int totalItemsSold = 0; // จำนวน items ที่ขาย
// Instance variables - ข้อมูลของแต่ละ store
private String storeName;
private String location;
public Store(String name, String location) {
this.storeName = name;
this.location = location;
}
// Instance method - ขายของ
public void sellItem(String itemName, double price, int quantity) {
double amount = price * quantity;
// Update static variables (shared)
totalRevenue += amount;
totalTransactions++;
totalItemsSold += quantity;
System.out.printf("[%s] Sold %d x %s = %.2f (Total revenue: %.2f)\n",
storeName, quantity, itemName, amount, totalRevenue);
}
// Static method - ดูสรุปทั้งหมด
public static void displayGlobalStats() {
System.out.printf("\n=== Global Store Statistics ===\n");
System.out.printf("Total Revenue: %.2f THB\n", totalRevenue);
System.out.printf("Total Transactions: %d\n", totalTransactions);
System.out.printf("Total Items Sold: %d\n", totalItemsSold);
}
public void displayStoreInfo() {
System.out.printf("Store: %s | Location: %s\n", storeName, location);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
// สร้าง 2 stores
Store store1 = new Store("Store A", "Bangkok");
Store store2 = new Store("Store B", "Chiang Mai");
System.out.println("=== Store A Operations ===");
store1.sellItem("Laptop", 25000, 1);
store1.sellItem("Mouse", 500, 5);
System.out.println("\n=== Store B Operations ===");
store2.sellItem("Keyboard", 1200, 3);
store2.sellItem("Monitor", 8000, 2);
// ดูสรุปที่ share กัน
Store.displayGlobalStats();
}
}
Output:
text=== Store A Operations ===
[Store A] Sold 1 x Laptop = 25000.00 (Total revenue: 25000.00)
[Store A] Sold 5 x Mouse = 2500.00 (Total revenue: 27500.00)
=== Store B Operations ===
[Store B] Sold 3 x Keyboard = 3600.00 (Total revenue: 31100.00)
[Store B] Sold 2 x Monitor = 16000.00 (Total revenue: 47100.00)
=== Global Store Statistics ===
Total Revenue: 47100.00 THB
Total Transactions: 4
Total Items Sold: 10
Static Constant (Static Final)
ตัวอย่างที่ 4: Configuration Constants
javapublic class Configuration {
// Static constants - ค่าที่ไม่เปลี่ยน
public static final String APP_NAME = "Banking System";
public static final String APP_VERSION = "1.0.0";
public static final String DATABASE_URL = "jdbc:mysql://localhost:3306/bank";
public static final int MAX_LOGIN_ATTEMPTS = 3;
public static final double MIN_BALANCE = 100;
public static final int TRANSACTION_TIMEOUT = 30; // seconds
// Static method - display config
public static void displayConfig() {
System.out.println("=== Application Configuration ===");
System.out.println("App: " + APP_NAME);
System.out.println("Version: " + APP_VERSION);
System.out.println("Database: " + DATABASE_URL);
System.out.println("Max Login Attempts: " + MAX_LOGIN_ATTEMPTS);
System.out.println("Min Balance: " + MIN_BALANCE);
}
}
public class BankAccount {
private double balance;
public void withdraw(double amount) {
// ใช้ static constant
if (balance - amount < Configuration.MIN_BALANCE) {
throw new IllegalArgumentException(
"Balance cannot go below " + Configuration.MIN_BALANCE);
}
this.balance -= amount;
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
Configuration.displayConfig();
System.out.println("\n=== Using Constants ===");
System.out.println("App: " + Configuration.APP_NAME);
System.out.println("Version: " + Configuration.APP_VERSION);
}
}
Static Method vs Instance Method
ตัวอย่างที่ 5: Math Utility
javapublic class MathUtil {
// Static method - ไม่ต้องสร้าง object
public static int add(int a, int b) {
return a + b;
}
public static int multiply(int a, int b) {
return a * b;
}
public static double power(double base, int exponent) {
return Math.pow(base, exponent);
}
// Instance method - สำหรับ reference
private int lastResult;
public void calculateAndStore(int a, int b) {
lastResult = add(a, b); // เรียก static method
}
public int getLastResult() {
return lastResult;
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
// Static method - ไม่ต้องสร้าง object
int sum = MathUtil.add(5, 3); // ✓ OK
int product = MathUtil.multiply(4, 6); // ✓ OK
double pow = MathUtil.power(2, 8); // ✓ OK
System.out.println("5 + 3 = " + sum);
System.out.println("4 * 6 = " + product);
System.out.println("2^8 = " + pow);
// Instance method - ต้องสร้าง object
MathUtil util = new MathUtil();
util.calculateAndStore(10, 20);
System.out.println("Stored result: " + util.getLastResult());
}
}
Static Initialization Block
ตัวอย่างที่ 6: Static Initializer
javapublic class Database {
// Static variables
private static String databaseURL;
private static int connectionPoolSize;
private static boolean isInitialized = false;
// Static initialization block
static {
System.out.println("[Static Init] Initializing database...");
databaseURL = "jdbc:mysql://localhost:3306/mydb";
connectionPoolSize = 10;
isInitialized = true;
System.out.println("[Static Init] Database initialized!");
}
// Static method
public static void connect() {
if (isInitialized) {
System.out.println("✓ Connected to: " + databaseURL);
System.out.println("✓ Pool size: " + connectionPoolSize);
} else {
System.out.println("❌ Database not initialized");
}
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
System.out.println("Program started\n");
Database.connect();
Database.connect();
}
}
Output:
text[Static Init] Initializing database...
[Static Init] Database initialized!
Program started
✓ Connected to: jdbc:mysql://localhost:3306/mydb
✓ Pool size: 10
✓ Connected to: jdbc:mysql://localhost:3306/mydb
✓ Pool size: 10
ตัวอย่างที่ 7: University System
javapublic class University {
// Static variables - ข้อมูล university ทั้งหมด
public static String universityName = "Bangkok University";
private static int totalStudents = 0;
private static int totalFaculty = 0;
private static double totalTuitionCollected = 0;
// Static method - สถิติ
public static void displayUniversityStats() {
System.out.printf("\n=== %s Statistics ===\n", universityName);
System.out.printf("Total Students: %d\n", totalStudents);
System.out.printf("Total Faculty: %d\n", totalFaculty);
System.out.printf("Total Tuition: %.2f\n", totalTuitionCollected);
}
}
public class Student {
private String studentID;
private String name;
private double gpa;
private double tuition;
public Student(String id, String name, double gpa, double tuition) {
this.studentID = id;
this.name = name;
this.gpa = gpa;
this.tuition = tuition;
// Update static counter
University.totalStudents++;
University.totalTuitionCollected += tuition;
}
public void displayInfo() {
System.out.printf("[%s] %s | GPA: %.2f | University: %s\n",
studentID, name, gpa, University.universityName);
}
}
public class Faculty {
private String facultyID;
private String name;
private String department;
public Faculty(String id, String name, String dept) {
this.facultyID = id;
this.name = name;
this.department = dept;
// Update static counter
University.totalFaculty++;
}
public void displayInfo() {
System.out.printf("[%s] %s | Dept: %s\n", facultyID, name, department);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
System.out.println("=== Creating Students ===");
Student s1 = new Student("6501001", "John", 3.75, 100000);
Student s2 = new Student("6501002", "Jane", 3.50, 100000);
s1.displayInfo();
s2.displayInfo();
System.out.println("\n=== Creating Faculty ===");
Faculty f1 = new Faculty("F001", "Dr. Smith", "Computer Science");
Faculty f2 = new Faculty("F002", "Prof. Jones", "Engineering");
f1.displayInfo();
f2.displayInfo();
University.displayUniversityStats();
}
}
Output:
text=== Creating Students ===
[6501001] John | GPA: 3.75 | University: Bangkok University
[6501002] Jane | GPA: 3.50 | University: Bangkok University
=== Creating Faculty ===
[F001] Dr. Smith | Dept: Computer Science
[F002] Prof. Jones | Dept: Engineering
=== Bangkok University Statistics ===
Total Students: 2
Total Faculty: 2
Total Tuition: 200000.00
Static vs Instance: คำว่า “this”
ความแตกต่าง
javapublic class Account {
public static String bankName = "National Bank"; // static
private String accountNumber; // instance
public void display() {
// ✓ ใช้ static ได้
System.out.println(Account.bankName);
System.out.println(Account.bankName); // or: Account.bankName
// ✓ ใช้ instance ต้องมี this/object reference
System.out.println(this.accountNumber);
}
}
ตัวอย่างที่ 8: ความเข้าใจถึง Scope
javapublic class Counter {
public static int globalCount = 0; // static - shared
private int instanceCount = 0; // instance - per object
public void increment() {
// ✓ เพิ่ม instance counter
this.instanceCount++;
// ✓ เพิ่ม static counter
Counter.globalCount++;
}
public void displayCounts() {
System.out.printf("Instance: %d | Global: %d\n",
this.instanceCount, Counter.globalCount);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
c1.increment();
c1.increment();
c1.displayCounts(); // Instance: 2 | Global: 2
c2.increment();
c2.displayCounts(); // Instance: 1 | Global: 3
c1.displayCounts(); // Instance: 2 | Global: 3
System.out.println("Static counter: " + Counter.globalCount); // 3
}
}
Output:
textInstance: 2 | Global: 2
Instance: 1 | Global: 3
Instance: 2 | Global: 3
Static counter: 3
Best Practices: Static Variable
1. Static Final สำหรับ Constants
java// ✓ ดี
public class Config {
public static final String APP_NAME = "MyApp";
public static final int MAX_USERS = 100;
public static final double PI = 3.14159;
}
// ❌ ไม่ดี
public class Config {
public static String APP_NAME = "MyApp"; // should be final
}
2. Private Static สำหรับ Internal Data
java// ✓ ดี
public class Student {
private static int totalStudents = 0; // private - ซ่อน
public static int getTotalStudents() {
return totalStudents;
}
}
// ❌ ไม่ดี
public class Student {
public static int totalStudents = 0; // public - เปิดเผย
}
3. Static Method สำหรับ Utility
java// ✓ ดี: Utility class
public class StringUtils {
public static String reverse(String text) {
return new StringBuilder(text).reverse().toString();
}
public static boolean isPalindrome(String text) {
return text.equals(reverse(text));
}
}
// ใช้ - ไม่ต้องสร้าง object
String result = StringUtils.reverse("hello");
4. ระวัง: Static Mutable
java// ⚠️ ระวัง: Static mutable - ทำให้เกิดปัญหา
public class BadExample {
public static List<String> sharedList = new ArrayList<>();
}
// ใครก็แก้ได้
BadExample.sharedList.add("item");
BadExample.sharedList.clear(); // ← ใครก็ลบได้!
// ✓ ดี: Static immutable
public class GoodExample {
public static final List<String> sharedList =
Collections.unmodifiableList(new ArrayList<>());
}
สรุป: Static Variable
text┌─────────────────────────────────────────┐
│ STATIC VARIABLE (Shared Resource) │
├─────────────────────────────────────────┤
│ │
│ ✓ เป็นของ Class (ไม่ใช่ object) │
│ ✓ มีค่าเดียว ทั้ง program │
│ ✓ เข้าถึงจาก: ClassName.variable │
│ ✓ ใช้สำหรับ: │
│ - Counters (นับ) │
│ - Accumulator (รวม) │
│ - Constants (ค่าคงที่) │
│ - Shared configuration │
│ │
│ ⚠️ ระวัง: │
│ - เพิ่มความซับซ้อน │
│ - ทำให้ test ยาก │
│ - Mutable static = ปัญหา │
│ │
└─────────────────────────────────────────┘
ตัวอย่างสุดท้าย: Real-World Scenario
javapublic class OnlineShoppingSystem {
// Static variables - ระบบ-wide data
private static double totalSaleAmount = 0;
private static int totalOrdersProcessed = 0;
private static int activeUsersCount = 0;
public static final String PLATFORM_NAME = "ShopHub";
public static final double TAX_RATE = 0.07; // 7% tax
// Static method
public static void displaySystemStats() {
System.out.printf("\n=== %s System Statistics ===\n", PLATFORM_NAME);
System.out.printf("Total Sales: %.2f\n", totalSaleAmount);
System.out.printf("Total Orders: %d\n", totalOrdersProcessed);
System.out.printf("Active Users: %d\n", activeUsersCount);
}
}
public class Customer {
private String customerID;
private String email;
private double totalSpent = 0;
public Customer(String id, String email) {
this.customerID = id;
this.email = email;
OnlineShoppingSystem.activeUsersCount++;
}
public void placeOrder(double amount) {
double totalWithTax = amount * (1 + OnlineShoppingSystem.TAX_RATE);
this.totalSpent += totalWithTax;
OnlineShoppingSystem.totalSaleAmount += totalWithTax;
OnlineShoppingSystem.totalOrdersProcessed++;
System.out.printf("[%s] Order placed: %.2f (with tax: %.2f)\n",
email, amount, totalWithTax);
}
public void displayInfo() {
System.out.printf("Customer: %s | Total Spent: %.2f\n", email, totalSpent);
}
}
// ใช้งาน
public class Main {
public static void main(String[] args) {
System.out.println("=== Creating Customers ===");
Customer c1 = new Customer("C001", "[email protected]");
Customer c2 = new Customer("C002", "[email protected]");
System.out.println("\n=== Placing Orders ===");
c1.placeOrder(1000);
c1.placeOrder(500);
c2.placeOrder(2000);
c1.displayInfo();
c2.displayInfo();
OnlineShoppingSystem.displaySystemStats();
}
}
Output:
text=== Creating Customers ===
=== Placing Orders ===
[[email protected]] Order placed: 1000.00 (with tax: 1070.00)
[[email protected]] Order placed: 500.00 (with tax: 535.00)
[[email protected]] Order placed: 2000.00 (with tax: 2140.00)
Customer: [email protected] | Total Spent: 1605.00
Customer: [email protected] | Total Spent: 2140.00
=== ShopHub System Statistics ===
Total Sales: 3745.00
Total Orders: 3
Active Users: 2
บทความนี้เป็นส่วนหนึ่งของรายวิชา Object-Oriented Programming with Java สำหรับนักศึกษาวิศวกรรมคอมพิวเตอร์และวิศวกรรมซอฟต์แวร์
