تفاوت اصلی این دو نوع متد در نحوهی فراخوانی آنهاست:
متد استاتیک: این نوع متد متعلق به خود کلاس است و بدون نیاز به ایجاد شیء (Object) از کلاس میتوان آن را فراخوانی کرد.
متد نمونه: این متد متعلق به شیء است و برای استفاده از آن، ابتدا باید یک شیء از کلاس ساخته شود.
برای درک بهتر مفاهیم مربوط به متدهای نمونه و استاتیک و تفاوتهای آنها، ابتدا به بررسی مفهوم Override میپردازیم و سپس به صورت دقیق، تفاوتهای میان متدهای استاتیک و نمونه را همراه با مثال بررسی خواهیم کرد.
Override در جاوا
Override در جاوا به معنای بازنویسی یک متد از کلاس والد در کلاس فرزند است، به طوری که کلاس فرزند بتواند رفتار مخصوص به خود را برای آن متد تعریف کند. وقتی یک متد در کلاس فرزند با همان نام، همان نوع خروجی و همان پارامترهای متد کلاس والد نوشته شود، گفته میشود که آن متد Override شده است. هدف از Override این است که بتوانیم رفتار متدها را براساس نیاز کلاسهای فرزند تغییر دهیم.برای مثال فرض کنید کلاس Shape یک متد draw داشته باشد:
class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
}
حالا کلاس Circle که از Shape ارثبری کرده، میتواند این متد را بازنویسی کند:
class Circle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
مقایسه Static Method و Instance Method
نحوه تعریف متد
متد استاتیک: این متد با کلمه کلیدی static ساخته میشود و متعلق به کلاس است. برای فراخوانی آن نیازی به ساخت شیء نداریم و میتوانیم مستقیماً با نام کلاس، متد را صدا بزنیم.متد نمونه: این متد به یک شیء خاص از کلاس وابسته است. برای فراخوانی آن باید ابتدا یک شیء از کلاس بسازیم و متد را روی آن شیء صدا بزنیم.
نحوه ساخت و فراخوانی متد استاتیک:
class MathUtils {
public static int square(int n) {
return n * n;
}
public static void main(String[] args) {
int result = MathUtils.square(5);
System.out.println("Square: " + result);
}
}
class Person {
String name;
public void sayHello() {
System.out.println("Hello, my name is " + name);
}
public static void main(String[] args) {
Person p = new Person();
p.name = "Ali";
p.sayHello();
}
}
نحوه دسترسی
متدهای استاتیک فقط به متغیرها و متدهای استاتیک دسترسی دارند. برای دسترسی به متغیرها و متدهای نمونه، باید ابتدا یک شیء از کلاس ساخته شود. اما متدهای نمونه میتوانند به هر دو، یعنی متغیرها و متدهای استاتیک و نمونه، دسترسی داشته باشند. دلیل این تفاوت این است که متدهای استاتیک به کلاس تعلق دارند و مستقل از شیء خاص هستند، در حالی که اعضای نمونه به شیء خاص وابستهاند.
class MyClass {
static int staticVar = 10; // متغیر استاتیک
int instanceVar = 20; // متغیر نمونه
static void staticMethod() {
System.out.println(staticVar); // میتواند به متغیر استاتیک دسترسی داشته باشد
// System.out.println(instanceVar); // خطا: به متغیر نمونه نمیتواند دسترسی پیدا کند
}
void instanceMethod() {
System.out.println(staticVar); // به متغیر استاتیک دسترسی دارد
System.out.println(instanceVar); // به متغیر نمونه هم دسترسی دارد
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.instanceMethod(); // فراخوانی متد نمونه
staticMethod(); // فراخوانی متد استاتیک
}
}
کلمه کلیدی this
در متدهای استاتیک نمیتوان از کلمه کلیدی this استفاده کرد؛ زیرا متد استاتیک به شیء خاصی تعلق ندارد و مستقل از هر شیء است. در متدهای نمونه میتوان از کلمه کلیدی this برای ارجاع به شیء جاری استفاده کرد.
class MyClass {
int num = 10;
// متد استاتیک
static void staticMethod() {
// System.out.println(this.num); // خطا: نمیتوان از `this` در متد استاتیک استفاده کرد
}
// متد نمونه
void instanceMethod() {
System.out.println(this.num); // میتواند از `this` برای دسترسی به اعضای شیء استفاده کند
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.instanceMethod(); // فراخوانی متد نمونه
}
}
تخصیص حافظه
از نظر تخصیص حافظه، تفاوت زیادی بین متدهای استاتیک و نمونه وجود ندارد. هر دو در فضای Permanent Generation در حافظه هیپ (یا Metaspace از Java 8 به بعد) ذخیره میشوند و متغیرهای محلی و آرگومانها در حافظه استک قرار میگیرند. تفاوت اصلی در نحوه فراخوانی آنهاست؛ متدهای استاتیک بدون نیاز به شیء و از طریق نام کلاس فراخوانی میشوند، در حالی که متدهای نمونه نیاز به شیء دارند تا فراخوانی شوند.امکان Override
برای درک اینکه در کدام متد امکان Override وجود دارد، ابتدا باید Static Binding و Dynamic Binding را مقایسه کنیم.متصل کردن اسم و فراخوانی متد به بدنه و پیاده سازی آن تحت عنوان اتصال کد (binding) شناخته می شود. به طور کلی دو نوع اتصال وجود دارد:
Static Binding: این نوع اتصال در زمان کامپایل انجام میشود. در این حالت، تصمیمگیری در مورد اینکه کدام متد باید فراخوانی شود، در زمان کامپایل انجام میشود. این نوع اتصال برای متدهای استاتیک که نمیتوانند override شوند، استفاده میشود. علت این است که متدهای استاتیک به کلاس تعلق دارند و نه به شیء خاص، بنابراین امکان تغییر آنها توسط کلاسهای فرزند وجود ندارد.
Dynamic Binding: این اتصال در زمان اجرا انجام میشود. تصمیمگیری در مورد فراخوانی متد، بر اساس نوع واقعی شیء در زمان اجرا انجام میشود. این نوع اتصال به خصوص برای متدهای نمونه که میتوانند override شوند، به کار میرود. در این حالت، متدهای نمونه در زمان اجرا بر اساس نوع واقعی شیء انتخاب میشوند.
برای درک بهتر این مفاهیم به مثالهای زیر توجه کنید.
در این مثال از متدهای استاتیک استفاده میکنیم.
class Shape {
static void draw() {
System.out.println("Drawing a shape");
}
}
class Circle extends Shape {
static void draw() {
System.out.println("Drawing a circle");
}
}
public class Main {
public static void main(String[] args) {
Shape.draw(); // "Drawing a shape"
Circle.draw(); // "Drawing a circle"
Shape s = new Circle();
s.draw(); // "Drawing a shape"
}
}
در اینجا، متد draw در کلاس Shape و Circle به صورت static تعریف شده است.
وقتی متدهای draw فراخوانی میشوند، انتخاب متدها در زمان کامپایل انجام میشود، نه در زمان اجرا.
حتی اگر یک شیء از نوع Circle ایجاد کنیم، چون متد draw استاتیک است، نوع متغیر (که Shape است) اهمیت دارد و متد Shape.draw() فراخوانی میشود.
در این مثال بعدی از متدهای نمونه استفاده میکنیم.
class Shape {
void draw() {
System.out.println("Drawing a shape");
}
}
class Circle extends Shape {
void draw() {
System.out.println("Drawing a circle");
}
}
public class Main {
public static void main(String[] args) {
Shape s = new Circle();
s.draw(); // "Drawing a circle"
}
}
در اینجا، متد draw به صورت نمونه در کلاسهای Shape و Circle تعریف شده است.
وقتی متد draw فراخوانی میشود، انتخاب متد در زمان اجرا و بر اساس نوع واقعی شیء (که در اینجا Circle است.) انجام میشود.
بنابراین حتی اگر متغیر s از نوع Shape باشد، چون شیء واقعی که در s ذخیره شده از نوع Circle است، متد Circle.draw() فراخوانی میشود.
ورود و ثبت نام برای ارسال نظر وارد شوید