ژنریک های جاوا به صورت کوتاه همراه با مثال توضیح داده شده است

لطفا برای اطلاعات بیشتر به این سوالات متداول مراجعه کنید:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#SECTION1

در اینجا به تور کیپنته از نکتا محمول از این کوکو و پیپر.

مثال (از نوع جمیلة):

کلاس Pair<X،Y> { 
  اول X خصوصی
  خصوصی Y ثانیه;   جفت عمومی (X a1، Y a2) {
    اول = a1;
    دوم = a2;
  }
  public X getFirst() { return first; }
  public Y getSecond() { return second; }
  public void setFirst(X arg)  { first = arg; }
  public void setSecond(Y arg) { second = arg; }
}

کلاس جفت کردن دارای دو نوع پارامتر X و Y .  آنها با آرگومان های نوع جایگزین می شوند که نوع عمومی هستند جفت کردن نمونه سازی شده است. به عنوان مثال، در اعلامیه Pair<String، Date> پارامتر نوع X با آرگومان type جایگزین می شود رشته و Y جایگزین می شود  تاریخ .
سردی شینسه ها X و Y است کل تعریف کلاس  در این محدوده دو نوع پارامتر X و Y מאנד אנה אוחרים מי שוד (בא בא בא שריטים הא). در مثال بالا، پارامترهای نوع به عنوان نوع آرگومان و از روش‌های بازگشت نمونه و انواع فیلد نمونه استفاده می‌شود.
parametres نور را می توان با کران کرد کرد کرد. کرانه ها به روش های نوف مجهول ای که پرامتر نوع محقوب آن است، می دهد. در آما، ما از هیک روشی از کیں کے کے ہے ہے ہے کے نیم کینیم X و Y . به همین دلیل، دو نوع پارامتر نامحدود هستند.

مثال (از ووت پارتمری بتن):

public void printPair( Pair<String، Long> جفت) {
  System.out.println("("+pair.getFirst()+""+pair.getSecond()+")");
} Pair<String، Long> حد = جدید Pair<String، Long> ("حداکثر"، 1024 لیتر)؛
printPair(Limit);

مثال (از نوع پارامتری با حروف عام):

public void printPair( Pair<؟،?> جفت) {
  System.out.println("("+pair.getFirst()+""+pair.getSecond()+")");
} Pair<؟،?> حد = جدید Pair<String، Long> ("حداکثر"، 1024 لیتر)؛
printPair(Limit);

همه نمونه‌های یک نوع عمومی، نمایش نوع زمان اجرا یکسانی دارند، یعنی نمایش نوع خام. به عنوان مثال، نمونه های یک نوع عمومی فهرست کنید ، مانند List<Date> , List<String> , List<Long> و غیره در زمان کامپایل انواع استاتیک متفاوتی دارند اما نوع پویا یکسانی دارند فهرست کنید در زمان اجرا

يك بازياز از دو بخس تشريح شده است:

  • بررسی نوع ایستا که توسط کامپایلر در زمان کامپایل انجام می شود
  • یک بررسی نوع پویا که توسط ماشین مجازی در زمان اجرا انجام می شود.

بخش استاتیک، بازیگران غیرمعنی را که نمی توانند موفق شوند، مانند بازیگران از رشته که تاریخ یا از List<String> که List<Date> .

کسمت بویا از تعریف نور عجرا می کند می کند می کند می کند و در زمان عچرا یک کریمی نور می دهده  الفرا بالا می برد. ClassCastException اگر نوع دینامیک شی، نوع هدف (یا زیرنوع نوع هدف) بازیگران نباشد. نمونه هایی از بازیگران با بخش پویا، بازیگران از شیء که رشته یا از شیء که List<String> .  انها به تحمیل downcasts ستید، از یک سوپرتایپ باین به یک زیرگروه.

نمونه هایی از انواع پارامترهای betton me bet List<String> , Map<String,Date> ، اما نه List<؟ Number> را گسترش می دهد یا Map<String,?> .

گاهی تیزر می رود که الفہ List<Object> یک ابرنوع از a خواهد بود List<String> ، زیرا شیء یک ابرنوع از رشته .  این انتظار از این واقعیت ناشی می شود که چنین نوع رابطه ای برای آرایه ها وجود دارد:  شیء[] یک ابرنوع از رشته[] ، زیرا شیء یک ابرنوع از رشته . (به این نوع رابطه معروف است کوواریانس .) رابطه فوق نوع فرعی انواع مؤلفه به انواع آرایه مربوطه گسترش می یابد. چنین رابطه ای برای نمونه هایی از انواع عمومی وجود ندارد. (انواع پارامتر شده هستند نه متغیر کمکی.)

فقدان یک رابطه خاص پیامدهای متفاوتی دارد.  در اینجا یک مثال است.

مثال:

void printAll(ArrayList<Object> c) {
  برای (شیء o : ج) 
    System.out.println(o);
} لیست ArrayList<String> = جدید ArrayList<String>();
... پر کردن لیست ...
printAll(list);   // خطا

الف ArrayList<String> شی را نمی توان به عنوان آرگومان به متدی ارسال کرد که a را درخواست می کند ArrayList<Object> زیرا این دو نوع نمونه هایی از یک نوع عمومی هستند، اما برای متفاوت است آرگومان ها را تایپ کنید و با یکدیگر سازگاری ندارند.

انواع پارامترهای بتن نمونه هایی از بتن هستند.  آنها تقریباً شبیه یکدیگر هستند. فقط چند محدودیت وجود دارد.

  • برای ایجاد آرایه ها
  • در رسیدگی به استثنا
  • در یک کلاس به معنای واقعی کلمه
  • در یک نمونه از بیان

ارائه های نگهدارنده علیمیری که نووت آن ها از نووت پامارتری بتن غیر قانونی است.

مثال

آزمون خلأ استاتیک() {
  Pair<Integer،Integer>[] intPairArr = جدید Pair<Integer،Integer>[10] ; // خطا
  addElements(intPairArr)؛ 
  Pair<Integer،Integer> زوج = intPairArr[1];
  عدد صحیح i = pair.getFirst();
  pair.setSecond(i);
}
افزودن عناصر خالی استاتیک( شیء[] objArr) {
  objArr[0] = جدید Pair<Integer,Integer>(0,0);
  objArr[1] = جدید Pair<String,String>("""");      // باید با ArrayStoreException شکست بخورد
}

کامپایلر ایجاد آرایه هایی را که نوع مؤلفه آنها یک نوع پارامتری بتن است، مانند Pair<Integer،Integer> در مثال ما  ما در مدخل قبلی بحث کردیم که چرا منطقی است که کامپایلر واجد شرایط a باشد Pair<Integer،Integer>[] به عنوان غیرقانونی  مشکل اصلی این است که کامپایلر و سیستم زمان اجرا باید مطمئن شوند که یک آرایه a است همگن دنباله ای از عناصر از همان نوع  یکی از بررسی‌های نوع، یعنی بررسی فروشگاه آرایه‌ای که توسط ماشین مجازی در زمان اجرا انجام می‌شود، نمی‌تواند درج متخلف عنصر بیگانه را تشخیص دهد. در مثال درج دوم در افزودن عناصر متد باید سکبت بھورد زیرا انها یک جفت است را به ارائه ای از میں انتگرال می کرد می کرد ام کہ آیت زیر می رفت نیم کابت هورد. در مدخل قبلی مورد بحث قرار گرفت.

اگر بتوانیم از آرایه های عناصر نگهداری استفاده کنیم، از چه نوع پارامترهایی استفاده می کنیم؟

اجازه دهید 3 راه حل قابل تصور را در نظر بگیریم:

  • مجموعه ای از انواع خام
  • آرایه ای از نوع پارامتری حروف نامحدود
  • مجموعه به جای آرایه

در حالی که ارائه‌های اینون بتن پرامتر غیرقانونی است، سلمه‌ای از اینونی پارتم بتن مجازی است.

1 مثال از یک پارامتر wildcard 1 مثال از یک آرگومان عمومی، 1 مثال از یک آرگومان عمومی است.  نمونه هایی از انواع پارامترها عمومی هستند مجموعه<?> , List<؟ Number> را گسترش می دهد , مقایسه کننده<؟ فوق العاده String> و Pair<String,?> . یک نوع پارامتری با حروف عام نشان‌دهنده خانواده‌ای از انواع است که شامل نمونه‌های بتنی از یک نوع عمومی است.  نوع عام مورد استفاده تعیین می کند که کدام نوع پارامتر بتن متعلق به خانواده است.  به عنوان مثال، نوع پارامتری wildcard مجموعه<?> نشان دهنده خانواده همه نمونه های از مجموعه رابط بدون توجه به نوع آرگومان.  نوع پارامتری wildcard List<؟ Number> را گسترش می دهد نشان دهنده خانواده همه انواع لیست است که در آن نوع عنصر زیرنوعی از آن است  شماره .  نوع پارامتری wildcard مقایسه کننده<؟ فوق العاده String> خانواده همه نمونه های از است مقایسه کننده رابط برای انواع آرگومان نوع که سوپرتایپ از رشته

یک نوع پارامتری با حروف عام یک نوع به معنای معمولی (متفاوت از کلاس/رابط غیر پارامتری یا نوع خام) نیست.

انواع پارامترهای Wildcard را می توان برای تایپ استفاده کرد (مانند کلاس ها و رابط های غیر پارامتری):

  • به عنوان انواع متدهای آرگومان و بازگشت
  • به عنوان نوع فیلد یا متغیر مرجع محلی
  • به عنوان نوع مؤلفه آرگومان نوع آرایه از سایر انواع پارامتر شده
  • به عنوان نوع هدف در قالب ها

نه تنا تنه استون مي تعلين علي بعليم بشدن، بها روش هم مي تلعدة بلامي باشد. روش ها ثابت و غیر استاتیک هستند و سازنده پارامترهای نوع را دارد. נחו בריים אנגלטים פראטראטים נופו רשמים אנשות נחו בריים עבור עבור עאע. نوع پارامتر با براکت های زاویه ای مشخص می شود و قبل از نوع، روش بازگشت ظاهر می شود. نگو و منتشی آن با LISTE PARAMETER نوف یک نوف جمیلة جمیع است.

در انجاء از يك جنريك بريده شده است حداکثر روشی که بیشترین مقدار را در مجموعه ای از عناصر از نوع ناشناخته محاسبه می کند الف .

مثال (رویه عمومی):

مجموعه های کلاس {
  استاتیک عمومی <A گسترش می یابد Comparable<A>> A حداکثر (مجموعه< الف > xs) {
    Iterator< الف > xi = xs.iterator();
    الف w = xi.next();
    while (xi.hasNext()) {
      الف x = xi.next();
      اگر (w.compareTo(x) < 0) w = x;
    }
    بازگشت w;
  }
} 

را حداکثر متد یک نوع پارامتر به نام دارد الف .  این یک مکان نگهدارنده برای نوع عنصر مجموعه است که روش روی آن کار می کند. پارامتر type یک کران دارد. باید نوعی باشد که زیرگروهی از آن باشد قابل مقایسه<A>

مثال (از همان نوع عمومی، این بار با محدوده):

رابط عمومی قابل مقایسه<T> {
  public int compareTo(T arg);
}
کلاس عمومی TreeMap<Key Comparable<Key> را گسترش می دهد ,Data>{
  کلاس استاتیک خصوصی Entry<K,V> {
     کلید K؛
     مقدار V;
     Entry<K,V> سمت چپ = null;
     Entry<K,V> سمت راست = null;
     Entry<K، V> والدین؛
  }
  خصوصی گذرا Entry<Key,Data> ریشه = null;
  ...
  خصوصی Entry<Key,Data> getEntry(کلید کلید) {
     Entry<Key,Data> p = root;
     کلید k = کلید;
     while (p != null) {
       int cmp = k. مقایسه با (p.key) ; 
       اگر (cmp == 0)
         بازگشت p;
       else if (cmp < 0)
         p = p.left;
       دیگر 
         p = p.right; 
     }
     بازگشت تهی
  }
  بولی عمومی containKey (کلید کلید) {
     بازگشت getEntry(key) != null;
  }
  ...
}

در مثال بالا، پارامتر type کلید محدود است قابل مقایسه<Key> .  تعیین یک حد دو اثر دارد:

  • به متدهایی که باند مشخص می کند دسترسی می دهد .  در مثال، محدود قابل مقایسه<Key> دسترسی به مقایسه با روشی که می خواهیم در پیاده سازی خود از آن استفاده کنیم نقشه درختی کلاس
  • فقط انواع “ در محدوده ” را می توان برای نمونه برداری عمومی استفاده کرد.   در مثال، یک نوع پارامتری مانند TreeMap<Number,String> رد خواهد شد، زیرا نوع شماره زیرگروهی نیست قابل مقایسه<Number> .  یک نوع پارامتری مانند TreeMap<String,String> پذیرفته می شود، زیرا نوع String در محدوده است، یعنی یک نوع فرعی از است قابل مقایسه<String> .

همه کلاس‌ها، پیوندها و انواع enum را می‌توان به‌عنوان پارامتر نوع حد استفاده کرد، از جمله انواع تودرتو و تودرتو.  نه انواع اولیه و نه انواع آرایه استفاده نمی شود.

نمونه ها (از نوع کرانه ای پرامتر):

کلاس X0 <T گسترش می یابد بین المللی > { ... }      // خطا
کلاس X1 <T گسترش می یابد شیء[] > { ... } // خطا
کلاس X2 <T گسترش می یابد شماره > { ... }
کلاس X3 <T گسترش می یابد رشته > { ... }
کلاس X4 <T گسترش می یابد قابل اجرا > { ... }
کلاس X5 <T گسترش می یابد موضوع. حالت > { ... }
کلاس X6 <T گسترش می یابد فهرست کنید > { ... }
کلاس X7 <T گسترش می یابد List<String> > { ... }
کلاس X8 <T گسترش می یابد List<؟ Number> را گسترش می دهد > { ... }
کلاس X9 <T گسترش می یابد قابل مقایسه <؟ Super Number> > { ... }
کلاس X10<T گسترش می یابد Map.Entry<?,?> > { ... }

نمونه کد نشان می دهد که انواع اولیه مانند بین المللی و انواع آرایه مانند شیء[] نوع پارامتر محدود به تطبیق مجاز نیست.

انواع کلاس ها مانند شماره یا رشته و انواع رابط، مانند قابل اجرا ، به تطبیق نوع پارامتر محدود مجاز است.

انواع Enum، مانند موضوع. حالت همچنین به عنوان محدود پارامتر نوع مجاز هستند. موضوع. حالت نمونه ای از این نوع در زمینه نوع پارامتر استفاده می شود.  انواع داخلی غیر استاتیک نیز مجاز است.

انواع مواد خام توسط نوع پارامتر محدود مجاز محدود شده است. فهرست کنید یک مثال

همه انواع پارامترها به نوع محدود پارامترها، از جمله همه انواع پارامترها، محدود می شوند List<String> , حروف محدود انواع پارامتری مانند List<؟ Number> را گسترش می دهد و قابل مقایسه <؟ فوق العاده Long> ، و انواع پارامترهای عام بی کران مانند Map.Entry<?,?> .  قاعده ای که دارای یک نوع پارامتر با کاراکترهای مشترک است، با نوع آرگومان عنوان، تمام انواعی را که به نوع خانواده تعلق دارند، اجازه می دهد.  کران نوف پامتری شده با wildcard کے کران کران کران کران کران کران نوف پرامتری شده با wildcard کا کے کران کران کران کران نوف پرامتری شده با wildcard کا کران کران کران محدودیت ها بستگی به نوع کلی دارد.

نمونه (از نوع پامرتری با حروب عام به تطبیق کران پامارت نوع):

کلاس X< T List< را گسترش می دهد؟ Number> را گسترش می دهد > {
  public void someMethod(T t) {
    t.add(new Long(0L));    // خطا
    شماره n = t.remove(0);
  }
}
آزمون کلاس {
  public static void main(string[] args) {
     X<ArrayList< طولانی >> x1 = جدید X<ArrayList<Long>>(); 
     X<ArrayList< رشته >> x2 = جدید X<ArrayList<String>>(); // خطا
  }
}

متغیرهای مرجع از نوع تی (نوع پارامتر) मुद्वार्टाही मेर्जे आज जोड अमार परमेत्र वूद) मे शुद्वार  در مثال، نتیجه این است که کامپایلر متدهایی را فراخوانی می‌کند که آرگومان‌های نوع “ را رد می‌کند، به‌عنوان پارامتر “، که با پارامتر “ شناسایی می‌شود. List.add ، زیرا کران یک نوع پامارتری با حروف اعم است که کران بایتی دارد.
در همان زمان زمان است List<؟ Number> را گسترش می دهد انواعی را که می توان به عنوان آرگومان نوع استفاده کرد را تعیین می کند. کامپایلر همه آرگومان های نوع را که به خانواده نوع تعلق دارند می پذیرد List<؟ Number> را گسترش می دهد ، یعنی تمام انواع فرعی از فهرست کنید با آرگومان نوع که زیرنوعی از است شماره .

يك پرامتر ووت را مي توابن به تطبيق كران پرامتر ووت عدي كرد

مثال (نوع پارامتر अग्या शुद्ध बह त्यूत्र करन परमेटत्):

کلاس سه گانه <T> {
  خصوصی T fst, snd, trd;
  عمومی < U T را گسترش می دهد , V T را گسترش می دهد , دبلیو T را گسترش می دهد > سه گانه (U arg1، V arg2، W arg3) {
    fst = arg1;
    snd = arg2;
    trd = arg3;
  }
}

در این مثال پارامتر type تی از کلاس پارامتری شده به عنوان کران پارامترهای نوع استفاده می شود U ,  V و دبلیو یک روش منتوه پامارتری از آن کلاس.

مهم‌ترین فرصت‌ها برای استفاده از پارامترهای نوع، انتهای سایر پارامترهای نوع هستند، از جمله موقعیت‌هایی که یک نوع تودرتو در یک نوع عمومی یا یک کلاس محلی را به صورت کلی تعریف می‌کنند.  हैत्म मजाज बह उज़ाई अज प्रामेटर वृस ‏‏ वॉट्य आस्त

يك كران كه يك كلاس است به همه چيز المعلومي خود مي دهد هودا هودها فيلدهاي فلدهاي المعلومي، متدها و زينه تودرتو. فقط سازندگان قابل دسترسی نیستند زیرا هیچ تضمینی وجود ندارد که زیر کلاس جرثقیل سازنده هایی مشابه جرثقیل داشته باشد.

مثال (کلاس هایی با عنوان نوع پارامتر پارامتر استفاده شده):

کلاس عمومی سوپرکلاس {     // اعضای ثابت
    enum عمومی EnumType {THIS, THAT}
    عمومی static Object staticField;
    public static void staticMethod() { ... }

    // اعضای غیر ایستا
    کلاس عمومی InnerClass { ... }
    شیء عمومی nonStaticField.
    public void nonStaticMethod() { ... }

    // سازنده ها
    عمومی SuperClass() { ... }

    // اعضای خصوصی
    Private Object privateField; 

    ...
}

کلاس نهایی عمومی SomeClass<T گسترش می یابد سوپرکلاس > {
    شی T خصوصی;
    public SomeClass(T t) { object = t; } 

    رشته عمومی toString() {
        بازگشت
         "نوع تودرتو ایستا    : "+T.EnumType.class+"\n" 
        +"فیلد ثابت          : "+T.staticField+"\n"
        +" روش استاتیک         : "+T.staticMethod()+"\n"
        +"نوع تو در تو غیر ایستا: "+T.InnerClass.class+"\n"
        +"فیلد غیر استاتیک      : "+object.nonStaticField+"\n"
        +"روش غیر استاتیک     : "+object.nonStaticMethod()+"\n"
        +"constructor           : "+(new T())+"\n"                    // خطا
        +"private Member        : "+object.privateField+"\n"          // خطا 
        ;
    }
}

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

திர் இக்கு க்கு அனை Enum<E Enum<E>> را گسترش می دهد “ به نصر می راسید داکیں است Enum کلاس در بسته java.lang :

کلاس انتزاعی عمومی Enum<E Enum<E>> را گسترش می دهد {
  ...
}

نوع Enum کلاس پایه مشترک همه انواع شمارش است.  در جاوا یک نوع شمارش مانند رنگ به کلاس ترجمه می شود رنگ که گسترش می یابد Enum<Color> . هدف سوپرکلاس Enum عملکرد ارائه برای همه انواع یکسان است.

در اینجا ترکی از کلاس است Enum :

کلاس انتزاعی عمومی Enum< E Enum<E>> را گسترش می دهد Comparable< را پیاده سازی می کند E >، قابل سریال سازی {
  خصوصی نام رشته نهایی;
  نام رشته نهایی عمومی () { ... }   خصوصی نهایی int ordinal;
  public final int ordinal() { ... }

  Enum محافظت شده (نام رشته، بین ترتیبی) { ... }

  رشته عمومی          toString() { ... }
  بولین نهایی عمومی برابر است (شیء دیگر) { ... }
  public final int hashCode() { ... }
  محافظت شده نهایی Object clone() CloneNotSupportedException { ... }
  عمومی نهایی int compareTo( E o) {...}

  عمومی نهایی Class< E > getDeclaringClass() { ... }
  عمومی static <T مقدار Enum<T>> T را گسترش می دهد(Class<T> enumType، نام رشته) { ... }
}

یک ویژگی شگفت انگیز در اعلامیه “ Enum<E Enum<E>> را گسترش می دهد “אין אפיטים אסט קה קלעס זידיפי פשפרים שדע אסט Enum و پارامتر نوع تازه تعریف شده آن E در کران همان پارامتر نوع ظاهر می شود.  به این معنی است که Enum نوع باید برای یکی از زیرگروه های آن نمونه سازی شود.  برای اینکه بفهمید چرا این منطقی است، در نظر بگیرید که هر نوع enum به یک زیرگروه ترجمه می شود Enum .

در انجاز نوع enum شهد شده است رنگ :

enum رنگ {قرمز، آبی، سبز}

کامپایلر آن را به کلاس زیر ترجمه می کند:

کلاس نهایی عمومی رنگ گسترش می یابد Enum<Color> {
  public static final Color[] values() { return (Color[])$VALUES.clone(); }
  public static Color valueOf (نام رشته) { ... }   private Color(string s, int i) { super(s, i); }

  عمومی استاتیک نهایی رنگ قرمز.
  عمومی استاتیک نهایی رنگ آبی.
  عمومی استاتیک نهایی رنگ سبز;

  رنگ نهایی ثابت خصوصی $VALUES[];

  استاتیک {
    قرمز = رنگ جدید ("قرمز"، 0)؛
    آبی = رنگ جدید ("آبی"، 1);
    سبز = رنگ جدید ("سبز"، 2);
    $VALUES = (رنگ جدید[] { قرمز، آبی، سبز })؛
  }
}

وراثت این اثر را دارد که رنگ type تمام متدهای پیاده سازی شده در را به ارث می برد Enum<Color> .  از جمله آنها است مقایسه با روش  را رنگ. مقایسه با روش احتمالا باید a رنگ به عنوان یک استدلال  به منظور تحقق این امر کلاس Enum عمومی است و Enum.compareTo روش می گیرد Enum نوع پارامتر ‘s E به عنوان یک استدلال  در نتیجه تایپ کنید رنگ مشتق شده از Enum<Color> ارث می برد a مقایسه با روشی که الف رنگ অন্য ক্য ক্য ক্র্ত্যান্যান্য ক্র্যযযন্যান্য ক্র্যয .
अग्र मा देखाय रा अस्टिक किनिम “ Enum<E Enum<E>> را گسترش می دهد می بینیم که این الگوریتم چندین جنبه دارد.

اول، واقعیتی وجود دارد که نوع پارامتر را محدود می کند، نوع: “ Enum <E گسترش می یابد Enum <E>> مطمئن می شود که فقط انواع فرعی از نوع Enum به عنوان آرگومان های نوع مجاز هستند. (از لحاظ نظری تایپ کنید Enum می تواند بر روی خود نمونه سازی شود، مانند در Enum<Enum> ، اما هدف این نیست و تصور موقعیتی که در چنین نمونه ای مفید باشد دشوار است.)

دوم، ان تعلیق عجود دارد که نووت فرامتری شده است Enum <E> ، که از پارامتر type استفاده می کند E به عنوان آرگومان نوع کران. این اعلان اطمینان می دهد که رابطه وراثت بین یک نوع فرعی و یک نمونه از Enum از فرم است X Enum<X> را گسترش می دهد “. 1 نوع مانند “ X Enum<Y> را گسترش می دهد ” به دلیل ارغومان نوت قبل دیلاین نیست Y در محدوده نخواهد بود فقط انواع فرعی از Enum<X> در محدوده هستند.

سوم، در تعليقة وجود دارد كه Enum در وهله اول عمومی است.  یعنی برخی از متدهای کلاس Enum یک آرگومان بگیرید یا مقداری از نوع ناشناخته را برگردانید (یا به یک نوع ناشناخته بستگی داشته باشید). همانطور که می دانیم، این نوع ناشناخته بعداً یک نوع فرعی خواهد بود X از Enum<X> .  از این رو، در نوع پارامتری Enum<X> ، این روش ها شامل زیرگروه می شوند X ، و در زیرگروه به ارث می رسند X .  را مقایسه با רוש משון אי אז קונין רושי אסט. از superclass به هر زیر کلاس به ارث می راسید و در هر مورد درای یک signature special زیر کلاس است.

به تور كلمة، عبارت “ Enum<E Enum<E>> را گسترش می دهد ” را می توان به روش زیر رمزگشایی کرد: Enum یک نوع عمومی است که فقط می‌تواند برای زیرگروه‌های آن نمونه‌سازی شود، و آن زیرگروه‌ها برخی از روش‌های مفید را به ارث می‌برند، که برخی از آن‌ها آرگومان‌های خاص فرعی را می‌گیرند (یا به نوع دیگر بستگی دارند).

پارامترهای نوع کران پایین کلاس ها

پارامترهای نوع می توانند چندین کران داشته باشند، مانند in کلاس Box<T تعداد> را گسترش می دهد {...} . اما یک پارامتر نوع نمی تواند کران پایینی داشته باشد، یعنی ساختاری مانند کلاس Box<T عالی Number> {...} مجاز نیست چرا که نه؟  عن است: بیهوده است زیرا اگر مجازی بود کیزی بری شما نمی خرید  بیایید ببینیم که چرا پارامترهای نوع محدودیت کلاس با توجه به اینکه محدودیت نوع به چه معناست گیج کننده است.

کران بالای یک پرامتر نوع درای سه آرت است:

    1. نمونه سازی محدود. کران بالایی مجموعه انواعی را که می توان برای نمونه سازی از نوع عمومی استفاده کرد محدود می کند.  اگر اعلام کنیم الف کلاس Box<T تعداد> را گسترش می دهد {...} سپس کامپایلر اطمینان حاصل می کند که فقط زیر انواع از شماره می تواند به عنوان آرگومان نوع استفاده شود.  یعنی الف Box<Number> یا الف Box<Long> مجاز است، اما الف Box<Object> یا Box<String> رد خواهد شد

مثال (نمونه سازی محدود به دلیل کران بالای یک پارامتر نوع):
کلاس Box<T Number> را گسترش می دهد { 
   ارزش T خصوصی؛ 
   public Box(T t) { value = t; } 
   ...
}  آزمون کلاس { 
   public static void main(string[] args) { 
       Box<Long> boxOfLong = جدید Box<Long>(0L);   // خوبه
       Box<String> boxOfString = جدید Box<String>(""); // خطا: رشته در محدوده نیست
   }
}

  1. دسترسی به اعضای غیر ایستا کران بالا به تمام روش ها و فیلدهای عمومی غیر استاتیک کران بالایی دسترسی می دهد.  در اجرای ما کلاس Box<T تعداد> را گسترش می دهد {...} ما می توانیم تمام متدهای عمومی غیر استاتیک تعریف شده در کلاس را فراخوانی کنیم شماره ، مانند intValue() به عنوان مثال  بدون کران بالا، کامپایلر هر گونه فراخوانی را رد می کند. مثال (دسترسی به اعضای غیر استاتیک به دلیل کران بالایی در پارامتر نوع):

کلاس Box<T Number> را گسترش می دهد { 
   ارزش T خصوصی؛ 
   public Box(T t) { value = t; } 
   public int increment() { return value.intValue()+1; } // <= بدون کران شماره یک خطا خواهد بود
   ...
} 

    1. پاک کردن را تایپ کنید. سمت چپ ترین کران بالا برای پاک کردن نوع استفاده می شود و جایگزین پارامتر نوع در کد بایت می شود.  در ما کلاس Box<T تعداد> را گسترش می دهد {...} همه اتفاقات تی با کران بالا جایگزین می شود شماره .  به عنوان مثال، اگر کلاس جعبه دارای یک فیلد خصوصی از نوع تی و یک روش مجموعه خالی (محتوای T) برای تنظیم این فیلد خصوصی، فیلد از نوع خواهد بود شماره پس از پاک کردن نوع و متد به یک متد ترجمه می شود مجموعه خالی (محتوای شماره) .

مثال (از کران بالا در پرامتر نوف در پاکردن نوف – استفاده کنید قبل از پاک کردن نوع):
کلاس Box< T شماره را گسترش می دهد > { 
   خصوصی تی ارزش؛ 
   جعبه عمومی( تی t) { value = t; } 
   ...
} 

      مثال (از کران بالا در پرامتر نوف در پاکردن نوف – استفاده کنید

بعد از

      پاک کردن نوع):

 

جعبه کلاس { 
   خصوصی شماره ارزش؛ 
   جعبه عمومی( شماره t) { value = t; } 
   ...
}

    علاوه بر این، کران بالا سمت چپ در مکان‌های بعدی مانند قالب‌های درج خودکار و روش‌های پل ظاهر می‌شود.

اگر کران های پایینی روی پارامترهای نوع مجاز باشد، چه عوارض جانبی می تواند داشته باشد یا باید داشته باشد؟ اگر سازه ای مانند کلاس Box<T عالی Number> {...} مجازی بودود معنی ان چیست؟  3 نمای جانبی 1 نوع پارامتر حاشیه نمونه برداری – بالا، دسترسی به عضو غیر استاتیک، پاک کردن نوع – برای 1 حاشیه पाइन चे अंगणी डार्ड؟

نمونه های محدود شده کامپایلر می‌تواند مجموعه‌ای از انواعی را که می‌توانند برای نمونه‌سازی از نوع عمومی با پارامتر نوع کران پایین‌تر استفاده شوند، محدود کند.  به عنوان مثال، کامپایلر می تواند نمونه هایی مانند Box<Number> و Box<Object> از یک Box<T عالی شماره> و مصداق هایی مانند رد Box<Long> یا Box<Short> .  این یک اثر در راستای اثر جانبی محدود کننده توصیف شده برای مرزهای پارامتر نوع بالایی خواهد بود.

دسترسی به اعضای غیر ایستا یک کران پارامتر نوع پایین‌تر به هیچ روش خاصی فراتر از روش‌های به ارث رسیده از کلاس دسترسی نمی‌دهد شیء . در مثال از Box<T عالی شماره> سوپر انواع شماره هیچ وجه اشتراکی ندارند، به جز اینکه آنها انواع مرجع و در نتیجه زیرگروه هستند شیء .  کامپایلر نمی تواند فیلد نوع را فرض کند تی از نوع است شماره یا زیرشاخه ای از آن  در عوض، زمینه نوع تی می تواند از هر نوع فوق العاده ای باشد شماره ، مانند قابل سریال سازی یا شیء .  فراخوانی روشی مانند intValue() دیگر از نظر نوع ایمن نیست و کامپایلر باید آن را رد کند. در نتیجه، کران پارامتر نوع پایین به اعضای غیر ایستا فراتر از آنهایی که در کلاس تعریف شده است دسترسی نمی دهد. شیء و همان همان ثلر “ بدون محدودیت” را دارد.

پاک کردن را تایپ کنید .  با پیروی از این خط منطق، جایگزین کردن رخدادهای پارامتر نوع با کران پایین سمت چپ آن، منطقی نیست.  اعلان متدی مانند سازنده جعبه( تی ت) به عنوان سازنده جعبه( شماره ت) با توجه به اینکه منطقی نیست تی با سوپر نوع جایگزین می شود شماره .  یک شیء ممکن است به درستی در یک نمونه به سازنده منتقل شود Box<Object> و سازنده آن را رد می کند.  این کار اشتباه خواهد بود.   بنابراین، پاک کردن نوع جایگزین تمام رخدادهای متغیر نوع خواهد شد تی بر اساس نوع شیء و نه با کران باین آن.  باز هم، کران باین همان اثر “bdon کران” را برای داشت.

איא מי מעצים בעשריד קה אגר הר דו פאין ביאינד קה משחשי דארד؟ _و_ حد بالا مجاز است؟   من شخصاً اصلاً به آن فکر نمی کنم و ترجیح می دهم آن را با عنوان “ ثبت کنم.

نکته واقعی این است: همه آن کیزی که “ عالی محدود به شما می‌خرد محدودیتی است که فقط انواع فوق‌العاده است شماره می تواند به عنوان آرگومان نوع استفاده شود.  و حتی این اغلب اشتباه درک می شود.  این به این معنی نیست کلاس Box<T super Number> {...} فقط شامل نمونه هایی از سوپرتیپ های است شماره .  کاملاً بر خلاف – به عنوان مثال زیر نشم می دهد!

مثال (از کران بالا در پرامتر نوف در پاکردن نوف – استفاده کنید قبل از پاک کردن نوع):

کلاس Box< T فوق العاده شماره > {
   خصوصی تی ارزش؛
   جعبه عمومی( تی t) { value = t; }
   ...
}

مثال (از کران بالا در پرامتر نوف در پاکردن نوف – استفاده کنید بعد از پاک کردن نوع):

جعبه کلاس {
   خصوصی شیء ارزش؛
   جعبه عمومی( شیء t) { value = t; }
   ...
}

الف کلاس Box<T عالی Number> {...} با نوع پاک کردن به a ترجمه می شود جعبه حاوی یک شیء فیلد و سازنده آن به ترجمه می شود جعبه (شیء t) . که اساسا با a متفاوت است کلاس Box<T گسترش می یابد Number> {...} ، که به a ترجمه می شود جعبه حاوی الف شماره فیلد و سازنده آن به ترجمه می شود جعبه (شماره t) . در نتیجه، الف Box<Number> نمونه از a کلاس Box<T تعداد> را گسترش می دهد {...} با a متفاوت خواهد بود Box<Number> نمونه از a کلاس Box<T super Number> {...} , के पोस्बाया मैस्तर सर्दर्गमी मी शतर सर्दर्गमी मी शतर सर्दर्गमी मी शुब درید درید.

 


 

پارامترهای نوع کران پایین روش ها

در رابطه با روش ها و انواع آرگومان های آن، گاهی اوقات یک نوع پارامتر با محدودیت می تواند مفید باشد.

مثال:

کلاس Pair<X،Y> {
   اول X خصوصی
   خصوصی Y ثانیه;
   ...
   عمومی < یک سوپر ایکس , B فوق العاده Y > B addToMap(Map<A,B> map) { // خطا: پارامتر نوع نمی تواند کران پایینی داشته باشد
      بازگشت map.put(اول، دوم);
   }
}
آزمون کلاس { 
   public static void main(string[] args) { 
     Pair<String,Long> جفت = جدید Pair<>("ABC",42L);
     Map<CharSequence، Number> map = HashMap<CharSequence، Number>();
     شماره شماره = pair.addToMap(map);
   }
}

را addToMap() متد محتوای جفت را به نقشه اضافه می کند.  هر نقشه ای که بتواند سوپرتایپ ها را در خود جای دهد X و Y انجام خواهد داد.  نقشه قرار دادن () متد مقدار یافت شده در نقشه را برای کلید داده شده برمی گرداند، اگر از قبل یک ورودی کلید-مقدار برای کلید در نقشه وجود داشته باشد.  مقدار بازگشتی نقشه قرار دادن () روش باید از addToMap() روش  در این شرایط، می‌خواهیم روشی را که در بالا نشان داده شده است، اعلام کنیم: نقشه با سوپرتایپ‌های پارامترهای نوع جفت و addToMap() متدوZYX0ZS نوف برکسی نوف قمت نککی است.

از آنجایی که کامپایلر محدودیت های کمتری را برای پارامترهای نوع اجازه نمی دهد، ما به یک راه حل نیاز داریم.

يكي از راه حلاي كه به ميند مي راسيد از امك عمي است آزي از امين كے لے كران پييني لہيں باشند بشدان.  در اینجا یک راه هل با وازید از ایمک اعم عود عود دارد.

مثال

کلاس Pair<X،Y> {
   اول X خصوصی
   خصوصی Y ثانیه;
   ...
   عمومی شیء addToMap(Map< ? سوپر ایکس , ? فوق العاده Y نقشه >) { 
      بازگشت map.put(اول، دوم);
   }
}
آزمون کلاس { 
   public static void main(string[] args) { 
     Pair<String,Long> جفت = جدید Pair<>("ABC",42L);
     Map<CharSequence، Number> map = HashMap<CharSequence، Number>();
     شماره شماره = (شماره) pair.addToMap(map);
   }
}

کار می کند، با این تفاوت که هیچ راهی برای اعلام نوع بازگشت به صورت دلخواه وجود ندارد.  این می تواند فوق نوع از Y که کامبایلر از نووت نکک می کیدر اما سنتکسی بری زکتین آن هدید دهرد  We should not declare the return type “” ? فوق العاده Y “، zira” ? فوق العاده Y ” یک علامت شایع است و یک نوع نیست، بنابراین بازگشت به عنوان یک نوع مجاز نیست. چاره ای نداریم و باید از آن استفاده کنیم شیء در عوض به عنوان نوع برگشتی روش ما.  این نوع بازگشت نامشخص به نوبه خود تماس گیرندگان را مجبور می کند addToMap() روش برای ریختن مقدار بازگشتی به پایین از شیء به نوف تعريف الان  آن إن تقديمً آن كيزي نيست ك ما در منند دستيم.

راه حل دیگر از روش های استاتیکی است.  در اینجا یک راح حل با روش آستا به جای روش غیر استاتیکی وجود دارد

مثال

کلاس Pair<X،Y> {
   اول X خصوصی
   خصوصی Y ثانیه;
   ...
   عمومی ایستا < الف , ب ، X A را گسترش می دهد ، ی B را گسترش می دهد > B addToMap(Pair<X,Y>, Map< الف , ب نقشه >) {
      بازگشت map.put(pair.first,pair.second);
   }
}
آزمون کلاس { 
   public static void main(string[] args) { 
     Pair<String,Long> جفت = جدید Pair<>("ABC",42L);
     Map<CharSequence، Number> map = HashMap<CharSequence، Number>();
     شماره شماره = جفت کردن .addToMap( جفت ، نقشه)؛
   }
}

عمومی addToMap() روش دارای چهار پارامتر نوع است: دو متغیر X و Y برای نوع جفت و دو مکان نگهدار الف و ب برای نوع نقشه الف و ب فوق انواع هستند X و Y ، زیرا X و Y   با اعلام می شوند الف و ب به عنوان مرزهای بالایی آنها. (توجه داشته باشید که پارامترهای نوع روش عمومی X و Y کاری به جفت کردن کلاس X و Y پارامترها  نام ها X و Y برای روش کے کے کے کے کہہے ہے ہے ہے ہے ہے کے ہے با از نوع کار برامتر، می توانیم نوع دقیق بازگشت را به دلخواه اعلام کنیم: إن نوف از نووت قمت آنکی است.

مثال (استفاده غیرقانونی از نوع پارامتر در زمینه این کلاس عمومی است):

کلاس SomeClass <T> {
  // اولیه ساز استاتیک، میدان استاتیک، روش استاتیک
  ایستا {
    SomeClass< تی تست > = SomeClass< جدید تی >(); // خطا
  }
  خصوصی ایستا تی globalInfo;          // خطا
  عمومی  ایستا تی getGlobalInfo() {        // خطا
    بازگشت globalInfo;
  }
  // مقداردهی اولیه غیر استاتیک، میدان غیر استاتیک، روش غیر استاتیک
  { 
    SomeClass< تی تست > = SomeClass< جدید تی >();
  }
  خصوصی        تی localInfo;
  عمومی         تی getLocalInfo() { 
    بازگشت localInfo.
  }
  // انواع تو در تو استاتیک
  عمومی ایستا کلاس عدم تمدید استثنا {
    فینال خصوصی تی اطلاعات           // خطا
    شکست عمومی ( تی t) { info = t; }      // خطا
    عمومی تی getInfo() { بازگشت اطلاعات; }    // خطا
   }
  خصوصی رابط کاربری قابل کپی {
    تی copy();                       // خطا
  }
  خصوصی enum حالت {
    معتبر، نامعتبر؛
    خصوصی تی اطلاعات // خطا
    public void setInfo( تی t) { info = t; } // خطا
    عمومی تی getInfo() { بازگشت اطلاعات; }    // خطا
  }
  // انواع تو در تو غیر استاتیک
  عمومی کلاس دستیار {
    عمومی تی getInfo() { return localInfo; }
  }
}

به عنوان مثال، نشان می دهد که پارامتر type را نمی توان در زمینه این کلاس عمومی استفاده کرد.  همچنین نشان می دهد که لینک های این کلاس و انواع اعضای enum در این کلاس در نظر گرفته شده اند.  فقط کلاس های داخلی، یعنی کلاس های تو در تو و غیر ایستا، می توانند از نوع کلاس پارامتر کلی کپسوله استفاده کنند.

سرادی پرامتر نوت یک لیکنگ، کل تفرینی لیکن است، به جز هر فیلد یا سیرون تودرتو.  دیلیش این است که فیلدها و سیرون تودرتو در یک لیکن به تور استیبیت ستیبت تفریق شده است.

مثال (استفاده غیرقانونی از پارامترها در یک پیوند کلی):

رابط SomeInterface <T> {
  // زمینه
  SomeClass< تی مقدار > = SomeClass< جدید تی >();  // خطا
  // نوع تو در تو
  کلاس دستیار {
    عمومی تی getInfo() {            // خطا
      بازگشت value.getGlobalInfo();
    }
  }
  // روش ها
  تی getValue();
}

مثال نشان می دهد که فیلدهای یک رابط به طور ضمنی ثابت هستند، به طوری که پارامتر نوع را نمی توان در هر جایی در اعلان یک فیلد یک رابط عمومی استفاده کرد.  به طور مشابه، کلاس تودرتو یک کلاس تودرتو ایستا در نظر گرفته می شود، نه یک کلاس داخلی، و به همین دلیل استفاده از پارامتر type در هر جایی از کلاس تودرتو غیرقانونی است.

راه‌حل برای کلاس‌ها و رابط‌های استاتیک تودرتو:

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

مثال (راح حل – ایندوت نوع استاتیک تودرتو):

بسته بندی کلاس <T> {
  فینال خصوصی تی شی

  لفاف عمومی ( تی t) { theObject = t; }
  عمومی تی getWrapper() { return theObject; }   عمومی غیر قابل تغییر <T> makeImmutable() {
        بازگشت ناپذیر جدید <T> (The Object)؛
  }
  عمومی قابل تغییر <T> makeMutable() {
        قابل تغییر جدید را برگردانید <T> (The Object)؛
  }
  خصوصی استاتیک <A> A makeClone(A theObject) { ... }

  عمومی استاتیک کلاس نهایی Immutable <A> { // اکنون یک کلاس عمومی است
        فینال خصوصی الف شی

        عمومی غیر قابل تغییر( الف ارگ) {
            theObject = makeClone(arg);
        }
        عمومی الف getWrappedItem() {
            بازگشت makeClone(theObject);
        }
  }
  عمومی استاتیک کلاس قابل تغییر <A> {
        ... مشابه ...
  }
}

چنین راه حلی برای انواع enum تودرتو وجود ندارد زیرا آنها نمی توانند عمومی باشند.

راه حل برای کلاس های استاتیک تو در تو:

اغر نوف استاتيك تودرتو يك كلاس بهذا، يك راح حل التحميل تعليقة كلاس استاتيك به يك كلاس نتيني غيراستيك است.

مثال (از محلول – به عنوان یک کلاس داخلی استفاده کنید):

بسته بندی کلاس <T> {
  فینال خصوصی تی شی

  لفاف عمومی ( تی t) { theObject = t; }
  عمومی تی getWrapper() { return theObject; }   public Mutable makeMutable() {
      بازگشت این جدید Mutable(theObject);
  }
  public Immutable makeImmutable() {
      بازگشت این new Immutable(theObject);
  }
  خصوصی استاتیک <A> A makeClone(A theObject) { ... }

  کلاس نهایی عمومی غیرقابل تغییر {  // دیگر یک کلاس ثابت نیست
      فینال خصوصی تی شی

      عمومی غیر قابل تغییر( تی ارگ) {
          theObject = makeClone(arg);
      }
      عمومی تی getWrappedItem() {
          بازگشت makeClone(theObject);
      }
  }
  کلاس عمومی قابل تغییر 
        ... مشابه ...
  }
}

این روش با مقدار مشخصی سربار سازگار است، زیرا تمامی کلاس های داخلی دارای یک مرجع مخفی در نمونه از نوع خارجی هستند که در این مثال نیازی به استفاده از آن نیست. مرجع سنون قاطع كمدان است.  اغلب، کلاس‌های داخلی با رابط‌ها ترکیب می‌شوند تا جزئیات پیاده‌سازی کلاس داخلی کلاس خصوصی محصور شود.  मा मी कार्ण हमीन कर रा दर इन्जा नमेंे.

مثال:

بسته بندی کلاس <T> {
  فینال خصوصی تی شی

  لفاف عمومی ( تی t) { theObject = t; }
  عمومی تی getWrapper() { return theObject; }   عمومی قابل تغییر <T> makeMutable() {
      بازگشت this.new Mutable(theObject);
  }
  عمومی غیر قابل تغییر <T> makeImmutable() {
      بازگشت this.new Immutable(theObject);
  }
  خصوصی استاتیک <A> A makeClone(A theObject) { ... }

  رابط عمومی Immutable<S> {
      S getWrappedItem();
  }
  رابط عمومی قابل تغییر<S> {
      S getWrappedItem();
      void setWrappedItem(S arg);
  }
  خصوصی کلاس نهایی ImmutableImplementation Immutable<T> را پیاده سازی می کند { 

      خصوصی نهایی T theObject;

      عمومی ImmutableImplementation(T arg) {
          theObject = makeClone(arg);
      }
      عمومی T getWrappedItem() {
          بازگشت makeClone(theObject);
      }
  }
  خصوصی کلاس MutableImplementation Mutable<T> را پیاده سازی می کند { 
        ... مشابه ...
  }
}

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

 

 

 

 

 

یک پاسخ بگذارید

از وبلاگ Velislav Krastev بیشتر بیاموزید

برای ادامه خواندن و دسترسی به آرشیو کامل، اکنون مشترک شوید.

به خواندن ادامه دهید