در این آموزش با رابط های جاوا آشنا می شویم و یاد خواهیم گرفت که چگونه واسط ها را پیاده سازی کنیم و چه زمانی از آن ها استفاده کنیم.
در جاوا ، یک رابط مجموعه ای از خصوصیات را که سایر کلاس ها باید پیاده سازی کنند ، تعریف می کند. مثلا،
interface Polygon {
public void getArea();
}
در اینجا ، Polygon یک رابط است. از کلید واژه interface برای تعریف واسط استفاده کرده ایم.
متد ()getArea خصوصیت تعیین شده در رابط Polygon است. کلیه کلاس هایی که از این رابط استفاده می کنند باید متد ()getArea را پیاده سازی کنند.
رابط می تواند شامل متد abstract و ثابت باشد. مثلا،
interface Polygon {
public static final String color = “blue”;
public void getArea();
}
در مثال بالا ، ما یک رابط Polygon ایجاد کرده ایم که شامل متغیر ثابت color و متد انتزاعی ()getArea است.
توجه به این نکته حائز اهمیت است که ، تمام متد های داخل یک رابط بطور پیش فرض public هستند و همه فیلد ها بطور پیش فرض public static هستند. از این رو ، مشخص کردن سطح دسترسی در داخل رابط ها ضروری نیست. به عنوان مثال ، می توانیم کد فوق را به صورت زیر بنویسیم :
interface Polygon {
String color = “blue”;
void getArea();
}
کلمه کلیدی implements در رابط
مانند کلاس های انتزاعی ، نمی توانیم از رابط شی ایجاد کنیم. با این حال ، می توانیم رابط ها را در کلاس های دیگر پیاده سازی کنیم. در جاوا ، از کلید واژه implements برای پیاده سازی رابط ها استفاده می کنیم. مثلا،
interface Polygon {
void getArea();
}
class Rectangle implements Polygon {
public void getArea(int length 5, int breadth = 6) {
int length = 5;
int breadth = 6;
System.out.println(“The area of the rectangle is ” + (length * breadth));
}
}
class Main {
public static void main(String[] args) {
Rectangle r1= new Rectangle();
r1.getArea(5, 6);
}
}
خروجی
The area of the rectangle is 30
در برنامه بالا ، یک رابط Polygon ایجاد کرده ایم. رابط Polygon دارای متد انتزاعی ()getArea است.
این بدان معناست که هر کلاس که Polygon را پیاده سازی می کند ، باید یک اجرا برای متد ()getArea ارائه دهد.
توجه داشته باشید که کلاس Rectangle (که رابط Polygon را پیاده سازی می کند) متد ()getArea را با پیاده سازی دارد.
چرا از رابط ها استفاده می کنیم؟
اکنون که می دانیم رابط ها چه هستند ، بیاموزیم که چرا از رابط ها در جاوا استفاده می شود.
رابط ها خصوصیاتی را ارائه می دهند که یک کلاس (که از آن استفاده می کند) باید از آن پیروی کند.
در مثال بالا ، از ()getArea به عنوان خصوصیت درون رابط Polygon استفاده کرده ایم. این کار مانند تنظیم یک قانون است که باید بتوانیم مساحت هر چند ضلعی را بدست آوریم. بنابراین هر کلاس که رابط Polygon را پیاده سازی کند ، باید یک اجرا برای متد ()getArea ارائه دهد.
مشابه کلاسهای انتزاعی ، رابط ها کمک می کنند تا در جاوا به انتزاع سازی برسیم. در اینجا می دانیم ()getArea مساحت چند ضلعی ها را محاسبه می کند اما نحوه محاسبه مساحت برای چند ضلعی های مختلف متفاوت است. از این رو ، اجرای ()getArea مستقل از یکدیگر است.
رابط ها همچنین برای دستیابی به ارث بری چندگانه در جاوا استفاده می شوند. اگر یک زیر کلاس از دو یا چند کلاس ارث بری کند ، ارث بری چندگانه است.
در جاوا ، ارث بری چندگانه امکان پذیر نیست. با این حال ، یک کلاس می تواند چندین رابط را پیاده سازی کند که امکان می دهد تا عملکرد وراثت چندگانه را در جاوا بدست آوریم. مثلا،
interface Line {
…
}
interface Polygon {
…
}
class Rectangle implements Line, Polygon{
…
}
در اینجا ، Rectangle باید همه متد های Line و Polygon را پیاده سازی کند.
متد های خصوصی و استاتیک در رابط
با انتشار جاوا ۸ ، رابط ها اکنون می توانند شامل متد های استاتیک باشند.
مانند کلاس، می توانیم با استفاده از ارجاع به متد های استاتیک یک رابط دسترسی داشته باشیم. مثلا،
- Polygon.staticMethod();
همچنین رابط ها با انتشار جاوا ۹ از متد های خصوصی پشتیبانی می کنند. اکنون می توانید از متد های خصوصی و متد های استاتیک خصوصی در رابط ها استفاده کنید.
از آنجا که نمی توانید واسط ها را تعریف کنید ، از متد های خصوصی به عنوان متد های کمکی استفاده می شود که پشتیبانی از متد های دیگر رابط ها را فراهم می کند.
متد های پیش فرض در رابط ها
با انتشار جاوا ۸ ، متد هایی با پیاده سازی (متد های پیش فرض) در داخل یک رابط معرفی شدند. قبل از آن ، تمام متد ها در جاوا انتزاعی بودند.
برای تعریف متد های پیش فرض در واسط ها ، از کلمه کلیدی default استفاده می کنیم. مثلا،
public default void getSides() {
// body of getSides()
}
چرا متد های پیش فرض؟
بیایید با یک سناریو بفهمیم که چرا متد های پیش فرض در جاوا معرفی می شوند.
فرض کنید ، ما باید یک متد جدید را در یک رابط اضافه کنیم.
می توانیم به راحتی متد را در رابط کاربری، بدون اجرا اضافه کنیم. با این حال ، این پایان داستان نیست. تمام کلاس ها که آن رابط را پیاده سازی می کنند باید پیاده سازی متد را ارائه دهند.
اگر تعداد زیادی کلاس در حال اجرای این رابط بودند ، باید همه این کلاس ها را دنبال کنیم و در آنها تغییراتی ایجاد کنیم. این نه تنها خسته کننده بلکه مستعد خطا هم هست.
برای رفع این مشکل ، Java متد های پیش فرض را معرفی کرد. متد های پیش فرض مانند متد های معمولی به ارث می رسد.
بیایید یک مثال بزنیم تا درک بهتری از متد های پیش فرض داشته باشیم.
مثال ۲ : متد پیش فرض
interface Polygon {
void getArea();
default void getSides() {
System.out.println(“I can get sides of polygon.”);
}
}
class Rectangle implements Polygon {
public void getArea() {
int length = 6;
int breadth = 5;
int area = length * breadth;
System.out.println(“The area of the rectangle is “+area);
}
public void getSides() {
System.out.println(“I have 4 sides.”);
}
}
class Square implements Polygon {
public void getArea() {
int length = 5;
int area = length * length;
System.out.println(“The area of the square is “+area);
}
}
class Main {
public static void main(String[] args) {
Rectangle r1 = new Rectangle();
r1.getArea();
r1.getSides();
Square s1 = new Square();
s1.getArea();
}
}
خروجی
The area of the rectangle is 30
I have 4 sides
The area of the square is 25
در مثال بالا ، رابط ()Polygon را ایجاد کرده ایم. Polygon یک متد پیش فرض ()getSides و یک متد انتزاعی ()getArea دارد.
کلاس Rectangle سپس Polygon را پیاده سازی می کند. Rectangle یک پیاده سازی را برای متد انتزاعی ()getArea فراهم می کند و متد پیش فرض ()getSides را نادیده می گیرد.
ما یک کلاس دیگر Square ایجاد کرده ایم که Polygon را نیز پیاده سازی می کند. در اینجا ، Square فقط اجرای متد انتزاعی ()getArea را ارائه می دهد.
مثال عملی رابط
بیایید نمونه عملی تر از رابط جاوا را ببینیم.
// To use the sqrt function
import java.lang.Math;
interface Polygon {
void getArea();
// calculate the perimeter of a Polygon
default void getPerimeter(int… sides) {
int perimeter = 0;
for (int side: sides) {
perimeter += side;
}
System.out.println(“Perimeter: ” + perimeter);
}
}
class Triangle implements Polygon {
private int a, b, c;
private double s, area;
// initializing sides of a triangle
Triangle(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
s = 0;
}
// calculate the area of a triangle
public void getArea() {
s = (double) (a + b + c)/2;
area = Math.sqrt(s*(s-a)*(s-b)*(s-c));
System.out.println(“Area: ” + area);
}
}
class Main {
public static void main(String[] args) {
Triangle t1 = new Triangle(2, 3, 4);
// calls the method of the Triangle class
t1.getArea();
// calls the method of Polygon
t1.getPerimeter(2, 3, 4);
}
}
خروجی
Area: 2.9047375096555625
Perimeter: 9
در برنامه بالا، رابط Polygon را ایجاد کرده ایم که شامل یک متد پیش فرض ()getParameter و یک متد انتزاعی ()getArea است.
می توانیم محیط همه چند ضلعی ها را به همان شیوه محاسبه کنیم بنابراین بدنه ی ()getPerimeter را در Polygon پیاده سازی کردیم. اکنون ، تمام چند ضلعی هایی که Polygon را پیاده سازی می کنند می توانند از ()getPerimeter برای محاسبه محیط استفاده کنند.
با این حال، محیط برای چند ضلعی های مختلف به طور متفاوتی محاسبه می شود زیرا قاعده محاسبه محیط برای چند ضلعی های مختلف متفاوت است. از این رو ، ()getArea بدون اجرا در Polygon گنجانده شده است. و هر کلاس که رابط Polygon را پیاده سازی کند باید اجرای ()getArea را پیاده سازی کند.
کلمه کلیدی extends در اینترفیس
مانند کلاس ها ، رابط ها می توانند رابط های دیگر را توسعه دهند. کلمه کلیدی extends برای گسترش رابط ها استفاده می شود. مثلا،
interface Line {
//members of Line interface
}
interface Polygon extends Line {
//members of Polygon interface and Line interface
}
در مثال بالا ، رابط Polygon رابط Line را گسترش می دهد. حال اگر یک کلاس Polygon را پیاده سازی کند ، باید اجرای کلیه کلاس های انتزاعی Line و Polygon را فراهم کند.
توجه داشته باشید که یک رابط می تواند چندین رابط شبیه به یک کلاس که چندین رابط را اجرا می کند ، گسترش دهد. مثلا،
interface A {
…
}
interface B {
…
}
Interface C extends A, B {
…
}