۲۹ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

وراثت در جاوا، قسمت ۱: کلمه کلیدی extends

از کلمه کلیدی extensions جاوا برای استخراج یک کلاس فرزند از کلاس والد، فراخوانی سازنده‌ها و متدهای کلاس والد، روش‌های نادیده گرفتن و غیره استفاده کنید.

از کلمه کلیدی extensions جاوا برای استخراج یک کلاس فرزند از کلاس والد، فراخوانی سازنده‌ها و متدهای کلاس والد، روش‌های نادیده گرفتن و غیره استفاده کنید.

جاوا از استفاده مجدد از کلاس از طریق وارث و ترکیب پشتیبانی می کند. این آموزش دو قسمتی به شما می آموزد که چگونه از وراثت در برنامه های جاوا خود استفاده کنید.

آنچه در این آموزش جاوا خواهید آموخت

نیمه اول این مقدمه برای وراثت جاوا به شما می آموزد که چگونه از کلمه کلیدی extends برای استخراج یک کلاس فرزند از کلاس والد، فراخوانی سازنده ها و متدهای کلاس والد، و نادیده گرفتن متدها استفاده کنید:

  • ارث در جاوا چیست؟
  • ارث تکی و ارث چندگانه
  • نحوه استفاده از کلمه کلیدی extensions در جاوا
  • درک سلسله مراتب کلاس جاوا
  • زمان استفاده از نادیده گرفتن روش در مقابل بارگذاری بیش از حد روش

ارث در جاوا چیست؟

وارث یک ساختار برنامه نویسی است که توسعه دهندگان نرم افزار از آن برای ایجاد روابط بین دسته ها استفاده می کنند. وراثت ما را قادر می سازد تا دسته بندی های خاص تری را از دسته های عمومی تر استخراج کنیم. دسته بندی خاص تر یک نوع دسته بندی عمومی تر است. به عنوان مثال، حساب جاری نوعی حساب است که می توانید در آن واریز و برداشت انجام دهید. به طور مشابه، کامیون نوعی وسیله نقلیه است که برای حمل اقلام بزرگ استفاده می شود.

وراثت می‌تواند از چندین سطح پایین بیاید که منجر به دسته‌بندی‌های خاص‌تر می‌شود. به عنوان مثال، شکل ۱ ماشین و کامیون را نشان می دهد که از وسیله نقلیه به ارث می رسد. استیشن واگن از خودرو به ارث می برد. و کامیون زباله از کامیون به ارث می برد. پیکان‌ها از دسته‌های خاص «فرزند» (پایین به پایین) به دسته‌های «والد» کمتر خاص (بالاتر) اشاره می‌کنند.

jw inheritance p1 fig1

شکل ۱. یک جفت سلسله مراتب ارثی ریشه در دسته وسایل نقلیه رایج دارند

ارث تکی و ارث چندگانه

مثال در شکل ۱ وراثت منفرد را نشان می‌دهد که در آن یک دسته فرزند حالت و رفتارها را از یک دسته والدین مستقیم به ارث می‌برد. در مقابل، ارث بری چندگانه یک دسته فرزند را قادر می‌سازد تا حالت و رفتار را از دو یا چند دسته والد فوری به ارث ببرد. سلسله مراتب در شکل ۲ وراثت چندگانه را نشان می دهد.

اصلاح جاوا G1 کامپایل JIT را سرعت می بخشد

jw inheritancep1 fig2

شکل ۲. هاورکرافت ارث بری از دسته های وسایل نقلیه زمینی و آبی را ضرب می کند

دسته ها بر اساس کلاس ها توصیف می شوند. جاوا از وراثت منفرد از طریق class extension پشتیبانی می‌کند، که در آن یک کلاس مستقیماً فیلدها و متدهای قابل دسترسی را از کلاس دیگر با گسترش آن کلاس به ارث می‌برد. اما جاوا از وراثت چندگانه از طریق پسوند کلاس پشتیبانی نمی کند.

هنگام مشاهده سلسله مراتب وراثت، می توانید به راحتی با وجود یک الگوی الماس، چندین وراثت را تشخیص دهید. شکل ۲ این الگو را در زمینه وسیله نقلیه، وسیله نقلیه زمینی، وسیله نقلیه آبی و هاورکرافت نشان می دهد.

نحوه استفاده از کلمه کلیدی extensions در جاوا

جاوا از پسوند کلاس از طریق کلمه کلیدی extends پشتیبانی می کند. در صورت وجود، extends یک رابطه والد-فرزند بین دو کلاس را مشخص می کند. در زیر از extends برای ایجاد رابطه بین کلاس‌های Vehicle و Car و سپس بین Account و استفاده می‌کنم. SavingsAccount:

class Vehicle
{
   // member declarations
}
class Car extends Vehicle
{
   // inherit accessible members from Vehicle
   // provide own member declarations
}
class Account
{
   // member declarations
}
class SavingsAccount extends Account
{
   // inherit accessible members from Account
   // provide own member declarations
}

کلمه کلیدی extends بعد از نام کلاس و قبل از نام کلاس دیگر مشخص می شود. نام کلاس قبل از extends فرزند را مشخص می‌کند و نام کلاس بعد از extends والدین را مشخص می‌کند. تعیین نام چند کلاس بعد از extends غیرممکن است زیرا جاوا از وراثت چندگانه مبتنی بر کلاس پشتیبانی نمی‌کند.

این مثال‌ها روابط is-a را کدگذاری می‌کنند: خودرو یک تخصصی خودرو و SavingsAccount است a تخصصی حساب. خودرو و حساب به‌عنوان کلاس‌های پایه، کلاس‌های والد، یا ابر کلاس‌ها شناخته می‌شوند. خودرو و SavingsAccount به‌عنوان کلاس‌های مشتق شده، کلاس‌های کودک، یا زیر کلاس‌ها شناخته می‌شوند.

کلاس های نهایی

شما ممکن است کلاسی را اعلام کنید که نباید تمدید شود. به عنوان مثال به دلایل امنیتی در جاوا از کلمه کلیدی final برای جلوگیری از گسترش برخی کلاس ها استفاده می کنیم. به سادگی یک سرصفحه کلاس را با final پیشوند کنید، مانند final class Password. با توجه به این اعلان، اگر کسی بخواهد Password را گسترش دهد، کامپایلر خطایی را گزارش خواهد کرد.

کلاس‌های فرزند فیلدها و روش‌های قابل دسترسی را از کلاس‌های والد خود و دیگر نیاکان خود به ارث می‌برند. با این حال، آنها هرگز سازنده ها را به ارث نمی برند. در عوض، کلاس های فرزند سازنده های خود را اعلام می کنند. علاوه بر این، آنها می توانند زمینه ها و روش های خود را برای متمایز کردن آنها از والدین خود اعلام کنند. فهرست ۲ را در نظر بگیرید.

class Account
{
   private String name;

   private long amount;

   Account(String name, long amount)
   {
      this.name = name;
      setAmount(amount);
   }

   void deposit(long amount)
   {
      this.amount += amount;
   }

   String getName()
   {
      return name;
   }

   long getAmount()
   {
      return amount;
   }

   void setAmount(long amount)
   {
      this.amount = amount;
   }
}

فهرست ۲ یک کلاس حساب بانکی عمومی را توصیف می کند که دارای نام و مبلغ اولیه است که هر دو در سازنده تنظیم شده اند. همچنین به کاربران امکان سپرده گذاری را می دهد. (شما می توانید با واریز مقادیر منفی پول برداشت کنید، اما ما این امکان را نادیده می گیریم.) توجه داشته باشید که هنگام ایجاد حساب، نام حساب باید تنظیم شود.

روبی به سمت حروف منجمد رشته گام برمی دارد

نماینده مقادیر ارز

برای فهرست ۲، من یک مقدار پولی را به عنوان یک عدد صحیح long نشان دادم، جایی که مقدار به عنوان تعداد پنی ذخیره می شود. ممکن است ترجیح دهید از یک دبل یا یک شناور برای ذخیره مقادیر پولی استفاده کنید، اما انجام این کار می‌تواند منجر به عدم دقت شود. برای راه حل بهتر، BigDecimal را در نظر بگیرید که بخشی از کتابخانه کلاس استاندارد جاوا است.

فهرست ۳ یک کلاس فرزند SavingsAccount ارائه می دهد که کلاس والد حساب آن را گسترش می دهد.

class SavingsAccount extends Account
{
   SavingsAccount(long amount)
   {
      super("savings", amount);
   }
}

کلاس SavingsAccount بی اهمیت است زیرا نیازی به اعلام فیلدها یا روش های اضافی ندارد. با این حال، سازنده ای را اعلام می کند که فیلدها را در سوپرکلاس Account خود مقداردهی اولیه می کند. راه‌اندازی زمانی اتفاق می‌افتد که سازنده حساب از طریق کلمه کلیدی super جاوا و به دنبال آن یک فهرست آرگومان پرانتز شده

فراخوانی شود.

چه زمانی و کجا با super() تماس بگیرید

همانطور که this() باید اولین عنصر سازنده ای باشد که سازنده دیگری را در همان کلاس فراخوانی می کند، super() نیز باید اولین عنصر سازنده باشد. که سازنده ای را در سوپرکلاس خود فراخوانی می کند. اگر این قانون را زیر پا بگذارید، کامپایلر یک خطا را گزارش می کند. کامپایلر همچنین اگر فراخوانی super() را در یک متد تشخیص دهد، خطا را گزارش خواهد کرد. فقط در یک سازنده super() را فراخوانی کنید.

اوبونتو 22.10 بر روی میکروکنترلرهای MicroPython می درخشد

فهرست ۴ حساب را با کلاس CheckingAccount بیشتر گسترش می‌دهد.

class CheckingAccount extends Account
{
   CheckingAccount(long amount)
   {
      super("checking", amount);
   }

   void withdraw(long amount)
   {
      setAmount(getAmount() - amount);
   }
}

CheckingAccount کمی بیشتر از SavingsAccount است زیرا یک روش withdraw() را اعلام می‌کند. به تماس‌های این روش با setAmount() و getAmount() توجه کنید که CheckingAccount از Account به ارث می‌برد. شما نمی توانید مستقیماً به فیلد مقدار در حساب دسترسی داشته باشید زیرا این فیلد خصوصی اعلام شده است (فهرست ۲ را ببینید).

super() و سازنده بدون آرگومان

اگر super() در سازنده زیر کلاس مشخص نشده باشد، و اگر superclass سازنده no-argument را اعلام نکند، کامپایلر یک خطا را گزارش می‌کند. . این به این دلیل است که سازنده کلاس فرعی باید سازنده سوپرکلاس بدون آرگومان را هنگامی که super() وجود ندارد فراخوانی کند.

درک سلسله مراتب کلاس جاوا

من یک کلاس برنامه AccountDemo ایجاد کرده ام که به شما امکان می دهد سلسله مراتب کلاس Account را امتحان کنید. ابتدا نگاهی به کد منبع AccountDemo بیاندازید.

class AccountDemo
{
   public static void main(String[] args)
   {
      SavingsAccount sa = new SavingsAccount(10000);
      System.out.println("account name: " + sa.getName());
      System.out.println("initial amount: " + sa.getAmount());
      sa.deposit(5000);
      System.out.println("new amount after deposit: " + sa.getAmount());

      CheckingAccount ca = new CheckingAccount(20000);
      System.out.println("account name: " + ca.getName());
      System.out.println("initial amount: " + ca.getAmount());
      ca.deposit(6000);
      System.out.println("new amount after deposit: " + ca.getAmount());
      ca.withdraw(3000);
      System.out.println("new amount after withdrawal: " + ca.getAmount());
   }
}

روش main() در فهرست ۵ ابتدا SavingsAccount و سپس CheckingAccount را نشان می‌دهد. با فرض اینکه فایل های منبع Account.java، SavingsAccount.java، CheckingAccount.java و AccountDemo.java در همان دایرکتوری، یکی از دستورات زیر را برای کامپایل همه این فایل های منبع اجرا کنید:

javac AccountDemo.java
javac *.java

برای اجرای برنامه دستور زیر را اجرا کنید:

java AccountDemo

شما باید خروجی زیر را مشاهده کنید:

account name: savings
initial amount: 10000
new amount after deposit: 15000
account name: checking
initial amount: 20000
new amount after deposit: 26000
new amount after withdrawal: 23000

دریافت روش در مقابل بارگذاری بیش از حد روش

یک کلاس فرعی می تواند یک متد ارثی را نسخه کند (جایگزین) کند تا به جای آن نسخه متد زیر کلاس فراخوانی شود. یک متد نادیده گرفته باید همان نام، لیست پارامترها و نوع بازگشتی را به عنوان روشی که لغو می شود مشخص کند. برای نشان دادن، یک روش print() را در کلاس Vehicle که در فهرست ۶ نشان داده شده است، اعلام کرده‌ام.