Java-ийн ерөнхий хэллэгийг жишээн дээр богино хэлбэрээр тайлбарлав

Дэлгэрэнгүй мэдээллийг энэ түгээмэл асуултуудыг үзнэ үү:

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

Товчхондоо энэхүү түгээмэл асуултуудын зарим чухал санааг энд оруулав.

Жишээ (ерөнхий төрлийн):

анги Pair<X,Y> { 
  эхлээд хувийн X;
  хувийн Y секунд;   нийтийн хос(X a1, Y a2) {
    эхний = a1;
    секунд = a2;
  }
  public X getFirst() {эхлээд буцах; }
  public Y getSecond() { секунд буцаах; }
  public void setFirst(X arg)  { first = arg; }
  public void setSecond(Y arg) { second = arg; }
}

Анги Хос хоёр төрлийн параметртэй X болон Ю .  Ерөнхий төрөл байх үед тэдгээрийг төрлийн аргументуудаар солино Хос үүсгэгдсэн байна. Тухайлбал, тунхаглалд Pair<String, Date> төрлийн параметр X төрлийн аргументаар солигдоно Мөр болон Ю -ээр солигдоно  Огноо .
Тодорхойлогчдын хамрах хүрээ X болон Ю байна ангийн бүх тодорхойлолт.  Энэ хүрээнд хоёр төрлийн параметрүүд X болон Ю нь төрөл байсан шиг ашиглагддаг (зарим хязгаарлалттай). Дээрх жишээнд төрлийн параметрүүдийг аргумент, буцаах төрөл болон жишээний талбарын төрлүүдэд ашигладаг.
Төрөл бүрийн параметрүүдийг хязгаартай зарлаж болно. Хязгаарлалт нь тухайн төрлийн параметрийг илэрхийлдэг үл мэдэгдэх төрлийн аргуудад хандах боломжийг олгодог. Бидний жишээн дээр бид үл мэдэгдэх төрлийн аргуудыг дууддаггүй X болон Ю . Энэ шалтгааны улмаас хоёр төрлийн параметрүүд нь хязгааргүй байдаг.

Жишээ (бетоныг параметржүүлсэн төрлийн):

нийтийн хүчингүй хэвлэхХос( Хос <String, Long> хос) {
  System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} Хос <String, Long> хязгаар = шинэ Хос <String, Long> ("хамгийн их", 1024л);
хэвлэхХос(хязгаар);

Жишээ нь (оролдуурын параметртэй төрлийн):

нийтийн хүчингүй хэвлэхХос( Pair<?,?> хос) {
  System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} Pair<?,?> хязгаар = шинэ Хос <String, Long> ("хамгийн их", 1024л);
хэвлэхХос(хязгаар);

Ерөнхий төрлийн бүх хувилбарууд нь ижил төрлийн ажиллах үеийн дүрслэл, тухайлбал, түүхий төрлийн дүрслэлийг хуваалцдаг. Жишээлбэл, ерөнхий төрлийн жишээнүүд Жагсаалт гэх мэт Жагсаалт<Date> , Жагсаалт<String> , Жагсаалт<Long> , гэх мэт нь эмхэтгэх үед өөр өөр статик төрлүүдтэй боловч ижил динамик төрөлтэй Жагсаалт ажиллах үед.

Цутгамал нь хоёр хэсгээс бүрдэнэ.

  • хөрвүүлэгчийн хөрвүүлэлтийн үед хийдэг статик төрлийн шалгалт ба
  • Виртуал машин ажиллаж байх үед хийдэг динамик төрлийн шалгалт.

Статик хэсэг нь амжилтанд хүрч чадахгүй утгагүй жүжигчдийг ангилдаг. Мөр тэр Огноо эсвэл -аас Жагсаалт<String> тэр Жагсаалт<Date> .

Динамик хэсэг нь ажиллах үеийн төрлийн мэдээллийг ашигладаг бөгөөд ажиллах үед төрлийг шалгадаг.  Энэ нь өсгөдөг ClassCastException хэрэв объектын динамик төрөл нь дамжуулалтын зорилтот төрөл (эсвэл зорилтот төрлийн дэд төрөл) биш бол. Динамик хэсэгтэй жүжигчдийн жишээ бол Объект тэр Мөр эсвэл -аас Объект тэр Жагсаалт<String> .  Эдгээр нь супер төрлөөс эхлээд дэд төрөл хүртэл доошилсон гэж нэрлэгддэг зүйлүүд юм.

Бетоны параметрийн төрлүүдийн жишээг дурдав Жагсаалт<String> , Map<String,Date> , гэхдээ үгүй List<? Number>-ийг сунгана эсвэл Map<String,?> .

Заримдаа хүлээгдэж буй зүйл бол a Жагсаалт<Object> a-ийн супер төрөл байх болно Жагсаалт<String> , учир нь Объект -ийн супер төрөл юм Мөр .  Энэхүү хүлээлт нь массивуудын хувьд ийм төрлийн харилцаа байдагтай холбоотой юм:  Объект[] -ийн супер төрөл юм Мөр[] , учир нь Объект -ийн супер төрөл юм Мөр . (Энэ төрлийн харилцааг гэж нэрлэдэг ковариац .) Бүрэлдэхүүн хэсгүүдийн төрлүүдийн супер дэд төрөл-холбоо нь харгалзах массивын төрлүүд рүү шилждэг. Ерөнхий төрлүүдийн жишээнүүдэд ийм төрлийн хамаарал байхгүй. (Параметржүүлсэн төрлүүд нь үгүй ковариант.)

Ижил төрлийн жишээнүүдийн хооронд супер дэд төрлийн хамаарал байхгүй байгаа нь янз бүрийн үр дагаварт хүргэдэг.  Энд нэг жишээ байна.

Жишээ:

хүчингүй хэвлэхБүгд(ArrayList<Object> c) {
  төлөө (Объект o : c) 
    System.out.println(o);
} ArrayList<String> жагсаалт = шинэ ArrayList<String>();
... жагсаалтыг бөглөх ...
PrintAll(жагсаалт);   // алдаа

А ArrayList<String> a-г асуудаг аргад объектыг аргумент болгон дамжуулах боломжгүй ArrayList<Object> Учир нь хоёр төрөл нь ижил төрлийн ерөнхий төрлийн жишээнүүд боловч for өөр аргументуудыг бичдэг бөгөөд энэ шалтгааны улмаас тэдгээр нь хоорондоо нийцэхгүй байна.

Бетоны параметржүүлсэн төрлүүд нь ерөнхий төрлийн бетоны жишээ юм.  Тэдгээр нь бараг л төрөл юм; цөөн хэдэн хязгаарлалт байдаг.  Тэдгээрийг дараах зорилгоор ашиглах боломжгүй.

  • массив үүсгэх зориулалттай
  • онцгой тохиолдолд
  • ангид шууд утгаар
  • онд жишээ илэрхийлэл

Төрөл нь бетоны параметржүүлсэн элемент агуулсан массив нь хууль бус байна.

Жишээ (хууль бус массивын төрөл):

статик хүчингүй тест() {
  Хос <Бүхэл тоо,Бүхэл >[] intPairArr = шинэ Pair<Бүхэл тоо,Бүхэл >[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<Бүхэл тоо,Бүхэл > бидний жишээнд.  Хөрвүүлэгч нь яагаад a шалгуурыг хангасан байх нь үндэслэлтэй болохыг бид өмнөх нийтлэлдээ авч үзсэн Хос <Бүхэл тоо,Бүхэл >[] хууль бус гэж.  Гол асуудал бол хөрвүүлэгч болон ажиллах цагийн систем нь массив нь a нэгэн төрлийн ижил төрлийн элементүүдийн дараалал.  Ашиглалтын үед виртуал машинаас гүйцэтгэдэг массив-дэлгүүр шалгах төрлийн шалгалтуудын нэг нь харь элементийн зөрчилтэй оруулгыг илрүүлж чадахгүй. Жишээн дээр хоёр дахь оруулга нэмэлт элементүүд арга нь бүтэлгүйтэх ёстой, учир нь тэд интеграл утгуудын массив дээр хос мөрийг нэмж байсан боловч энэ нь санаснаар бүтэлгүйтсэн. Үүний шалтгааныг өмнөх нийтлэлд хэлэлцсэн.

Хэрэв бид тодорхой параметржүүлсэн төрөл болох элементүүдийг агуулсан массивыг ашиглах боломжгүй бол бид юуг тойрч гарах арга замыг ашиглах вэ?

Боломжтой 3 гарцыг авч үзье:

  • түүхий эдүүдийн массив
  • параметржүүлсэн төрлийн хязгааргүй орлуулагч тэмдэгтийн массив
  • массивын оронд цуглуулга

Бетоны параметржүүлсэн төрлийн массив нь хууль бус боловч бетоны параметржүүлсэн төрлийг цуглуулахыг зөвшөөрдөг.

Оролцогч тэмдэгтийн параметржүүлсэн төрөл нь наад зах нь нэг төрлийн аргумент нь орлуулагдах тэмдэг байх ерөнхий төрлийн жишээ юм.  Оролцогч тэмдэгтийн параметржүүлсэн төрлүүдийн жишээнүүд Цуглуулга<?> , List<? Number>-ийг сунгана , Харьцуулагч<? супер String> болон Pair<String,?> . Оролцогч тэмдэгтийн параметржүүлсэн төрөл нь ерөнхий төрлийн тодорхой жишээнүүдээс бүрдсэн төрлүүдийн бүлгийг илэрхийлдэг.  Ашиглаж буй орлуулалтын тэмдэг нь ямар бетоны параметржүүлсэн төрлүүд гэр бүлд хамаарахыг тодорхойлдог.  Жишээ нь, орлуулагч тэмдэгтийн төрөл Цуглуулга<?> -ийн бүх тохиолдлын гэр бүлийг илэрхийлдэг Цуглуулга төрлийн аргументаас үл хамааран интерфейс.  Оролцогч тэмдэгтийн параметрчилсэн төрөл List<? Number>-ийг сунгана Элементийн төрөл нь дэд төрөл болох жагсаалтын бүх төрлийн гэр бүлийг илэрхийлдэг  Тоо .  Оролцогч тэмдэгтийн параметрчилсэн төрөл Харьцуулагч<? супер String> -ийн бүх хувилбаруудын гэр бүл юм Харьцуулагч supertypes төрлийн аргументын төрлүүдийн интерфейс Мөр.

Оролцогч тэмдэгтийн параметржүүлсэн төрөл нь ердийн утгаараа төрөл биш (параметржүүлээгүй анги/интерфэйс эсвэл түүхий төрлөөс ялгаатай).

Шилдэг тэмдэгтийн параметржүүлсэн төрлүүдийг бичихэд ашиглаж болно (параметргүй ангиуд болон интерфейс гэх мэт):

  • аргумент болон буцаах аргуудын төрөл
  • талбарын төрөл эсвэл орон нутгийн лавлагаа хувьсагчаар
  • бусад параметржүүлсэн төрлүүдийн массив төрлийн аргументуудын бүрэлдэхүүн хэсэг болгон
  • дамжуулалт дахь зорилтот төрөл болгон

Зөвхөн төрлүүд нь ерөнхий байж болохоос гадна аргууд нь ерөнхий байж болно. Статик болон статик бус аргууд, мөн бүтээгчид нь төрлийн параметртэй байж болно. Албан ёсны төрлийн параметрүүдийг зарлах синтакс нь ерөнхий төрлүүдийн синтакстай төстэй. Төрөл параметрийн хэсэг нь өнцгийн хаалтаар тусгаарлагдсан бөгөөд аргын буцах төрлөөс өмнө гарч ирнэ. Үүний синтакс болон утга нь ерөнхий төрлийн төрлийн параметрийн жагсаалттай ижил байна.

Энд ерөнхий жишээ байна хамгийн их үл мэдэгдэх төрлийн элементүүдийн цуглуулгын хамгийн их утгыг тооцоолох арга А .

Жишээ (ерөнхий аргын):

ангийн цуглуулга {
  нийтийн статик <A харьцуулах боломжтой<A>> A өргөтгөл хамгийн их (Цуглуулга< А > xs) {
    Iterator< А > xi = xs.iterator();
    А w = xi.next();
    байхад (xi.hasNext()) {
      А x = xi.next();
      хэрэв (w.compareTo(x) < 0) w = x;
    }
    буцах w;
  }
} 

The хамгийн их арга нь нэртэй нэг төрлийн параметртэй А .  Энэ нь тухайн арга дээр ажилладаг цуглуулгын элементийн төрөлд зориулсан газар эзэмшигч юм. Төрөл параметр нь хязгаартай; дэд төрөл болох төрөл байх ёстой Харьцуулах боломжтой<A>

Жишээ (ижил төрлийн, энэ удаад хамт хязгаар):

нийтийн интерфэйс Comparable<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> root = null;
  ...
  private Entry<Key,Data> getEntry(Түлхүүр түлхүүр) {
     Entry<Key,Data> p = root;
     Түлхүүр k = түлхүүр;
     байхад (p != null) {
       int cmp = k. харьцуулах(p.key) ; 
       хэрэв (cmp == 0)
         буцах p;
       Хэрэв өөр бол (cmp < 0)
         p = p.зүүн;
       өөр 
         p = p.баруун; 
     }
     null буцаах;
  }
  нийтийн логикийн агуулагдах Түлхүүр(Түлхүүр түлхүүр) {
     буцаах getEntry(key) != null;
  }
  ...
}

Дээрх жишээнд төрлийн параметр Түлхүүр хил хязгаартай Харьцуулах боломжтой<Key> .  Хязгаарлалтын тодорхойлолт нь хоёр нөлөөтэй:

  • Энэ нь хязгаарын заасан аргуудад хандах боломжийг олгодог .  Жишээ нь, хязгаар Харьцуулах боломжтой<Key> хандах боломжийг олгодог харьцуулах хэрэгжүүлэхдээ бидний ашиглахыг хүссэн арга TreeMap анги.
  • Ерөнхий төрлийг жишээ болгоход зөвхөн “хязгаарлалт дотор” төрлүүдийг ашиглаж болно.   Жишээн дээр параметржүүлсэн төрөл гэх мэт TreeMap<Number,String> татгалзсан байх болно, учир нь төрөл Тоо дэд төрөл биш юм Харьцуулах боломжтой<Number> .  Параметржүүлсэн төрөл гэх мэт TreeMap<String,String> Мөр нь хязгаарт багтдаг, өөрөөр хэлбэл дэд төрөл учраас хүлээн авах болно Харьцуулах боломжтой<String> .

Бүх анги, интерфэйс болон тооллын төрлүүдийг үүрлэсэн болон дотоод төрлүүдийг багтаасан төрлийн параметрийн дагуу ашиглаж болно.  Анхан шатны төрлүүд болон массивын төрлүүдийг төрлийн параметрийн хязгаар болгон ашиглаж болохгүй.

Жишээ (төрлийн параметрийн хязгаар):

анги X0 <T сунгаж байна int > { ... }      // алдаа
X1 ангиллын <T сунгаж байна Объект[] > { ... } // алдаа
X2 ангиллын <T өргөтгөлтэй Тоо > { ... }
анги X3 <T сунгаж байна Мөр > { ... }
X4 ангиллын <T өргөтгөлтэй Ажиллах боломжтой > { ... }
анги X5 <T сунгаж байна Thread.Төлөв > { ... }
X6 ангиллын <T өргөтгөлтэй Жагсаалт > { ... }
X7 ангиллын <T сунгаж байна Жагсаалт<String> > { ... }
анги X8 <T сунгаж байна List<? Number>-ийг сунгана > { ... }
X9 ангиллын <T сунгаж байна < харьцуулах боломжтой юу? супер дугаар> > { ... }
анги X10<T өргөтгөл Map.Entry<?,?> > { ... }

Кодын дээжээс харахад анхдагч төрлүүд гэх мэт int зэрэг массивын төрлүүд Объект[] төрлийн параметрийг хязгаарлахыг зөвшөөрөхгүй.

зэрэг ангиллын төрлүүд Тоо эсвэл Мөр , болон интерфейсийн төрлүүд гэх мэт Ажиллах боломжтой , төрлийн параметрийг хязгаарлахыг зөвшөөрдөг.

зэрэг тооллын төрлүүд Thread.Төлөв мөн төрлийн параметрийг хязгаарлахыг зөвшөөрдөг. Thread.Төлөв нь төрлийн параметрийг хязгаарласан байдлаар ашигладаг үүрлэсэн төрлийн жишээ юм.  Статик бус дотоод төрлүүдийг мөн зөвшөөрдөг.

Түүхий төрлүүдийг төрлийн параметрээр хязгаарлахыг зөвшөөрдөг; Жагсаалт жишээ юм.

Параметржүүлсэн төрлүүдийг төрлийн параметрийн дагуу зөвшөөрнө, үүнд бетоны параметржүүлсэн төрлүүд орно Жагсаалт<String> , хязгаарлагдмал орлуулагч тэмдэгт параметржүүлсэн төрлүүд гэх мэт List<? Number>-ийг сунгана болон < харьцуулах боломжтой юу? супер Long> , болон хязгааргүй орлуулагдах тэмдэгт параметржүүлсэн төрлүүд гэх мэт Map.Entry<?,?> .  Оролцогч тэмдэгтийн параметржүүлсэн төрөл болох хүрээ нь орлуулагч тэмдэгтээр тэмдэглэгдсэн төрлийн төрөлд хамаарах бүх төрлийг төрлийн аргумент болгон зөвшөөрдөг.  Оролцогч тэмдэгтийн параметржүүлсэн төрлийн хязгаар нь зөвхөн талбарууд болон аргуудад хязгаарлагдмал хандалтыг өгдөг; хязгаарлалт нь орлуулагчийн төрлөөс хамаарна.

Жишээ нь (төрлийн параметрийн хязгаарлагдмал орлуулагч тэмдэглэгдсэн төрлөөр):

X< анги T List<-г сунгах уу? Number>-ийг сунгана > {
  public void someMethod(T t) {
    t.add(шинэ Урт(0л));    // алдаа
    Тоо 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;
  нийтийн < У T сунгаж байна , В T сунгаж байна , В T сунгаж байна > Гурвалсан(U arg1, V arg2, W arg3) {
    fst = arg1;
    snd = arg2;
    trd = arg3;
  }
}

Энэ жишээнд төрлийн параметр Т Параметржүүлсэн ангийнх нь төрлийн параметрийн хязгаарыг ашиглана У ,  В болон В тухайн ангийн параметржүүлсэн жишээний аргын.

Төрөл бүрийн параметрүүдийг бусад төрлийн параметрүүдийн хязгаар болгон ашиглах цаашдын боломжуудад үүрлэсэн төрлийг ерөнхий төрөл дотор тодорхойлсон эсвэл локал классыг ерөнхий аргын дотор тодорхойлсон нөхцөл байдал орно.  Бүр төрлийн параметрийг ижил төрлийн параметрийн хэсэгт өөр төрлийн параметрийн хязгаар болгон ашиглахыг зөвшөөрдөг.

Анги гэсэн холбоос нь нийтийн талбар, арга, үүрлэсэн төрлүүдийн бүх нийтийн гишүүдэд хандах боломжийг олгодог. Зөвхөн бүтээгчид хандах боломжгүй, учир нь хязгаарын дэд анги нь хязгаартай ижил бүтээгчтэй байх баталгаа байхгүй.

Жишээ (төрлийн параметрийн зааг болгон ашигладаг ангийн):

олон нийтийн анги Супер анги {     // статик гишүүд
    нийтийн тоолол EnumType {THIS, THAT}
    нийтийн статик Объект staticField;
    нийтийн статик хүчингүй staticMethod() { ... }

    // статик бус гишүүд
    нийтийн анги InnerClass { ... }
    public Object nonStaticField;
    public void nonStaticMethod() { ... }

    // бүтээгчид
    нийтийн SuperClass() { ... }

    // хувийн гишүүд
    privateField хувийн объект; 

    ...
}

нийтийн эцсийн анги SomeClass<T өргөтгөл Супер анги > {
    хувийн T объект;
    нийтийн SomeClass(T t) {объект = t; } 

    нийтийн мөр toString() {
        буцах
         "статик үүрлэсэн төрөл    : "+T.EnumType.class+"\n" 
        +"статик талбар          : "+T.staticField+"\n"
        +"статик арга         : "+T.staticMethod()+"\n"
        +"статик бус үүрлэсэн төрөл: "+T.InnerClass.class+"\n"
        +"статик бус талбар      : "+object.nonStaticField+"\n"
        +"статик бус арга     : "+object.nonStaticMethod()+"\n"
        +"байгуулагч           : "+(шинэ T())+"\n"                    // алдаа
        +"хувийн гишүүн        : "+object.privateField+"\n"          // алдаа 
        ;
    }
}

Хязгаарлалт Супер анги нь үүрлэсэн төрлүүд, статик талбарууд болон аргууд болон статик бус талбарууд болон аргуудад хандах боломжийг олгодог.  Зөвхөн бүтээгч рүү хандах боломжгүй.  Учир нь бүтээгчид өвлөгддөггүй. Дэд анги бүр өөрийн бүтээгчийг тодорхойлдог бөгөөд супер ангийн бүтээгчийг дэмжих шаардлагагүй.  Тиймээс дэд ангилалд хамаарах баталгаа байхгүй Супер анги нь супер ангитайгаа ижил бүтээгчтэй байх болно.

Тухайн нөхцөл байдал Enum<E Enum<E>> өргөтгөл ” гэсэн мэдэгдэл гарч байна Enum багц дахь анги java.lang :

нийтийн хийсвэр анги Enum<E Enum<E>> өргөтгөл {
  ...
}

Төрөл Enum бүх төрлийн тооллогын нийтлэг суурь анги юм.  Java-д тооллогын төрөл, тухайлбал Өнгө анги болгон орчуулж байна Өнгө энэ нь үргэлжилдэг Enum<Color> . Супер ангийн зорилго Enum бүх төрлийн тооллогын нийтлэг үйл ажиллагааг хангах явдал юм.

Энд ангийн ноорог байна Enum :

нийтийн хийсвэр анги Enum< Э Enum<E>> өргөтгөл Comparable< хэрэгжүүлдэг Э >, Цуваалах боломжтой {
  хувийн эцсийн String нэр;
  нийтийн эцсийн мөрийн нэр() { ... }   private final int ordinal;
  public final int ordinal() { ... }

  хамгаалагдсан Enum(Мөрийн нэр, int дараалал) { ... }

  нийтийн мөр           toString() { ... }
  нийтийн эцсийн логик тэнцүү(Бусад объект) { ... }
  нийтийн эцсийн int hashCode() { ... }
  хамгаалагдсан эцсийн Object clone() нь CloneNotSupportedException-г шиддэг { ... }
  нийтийн эцсийн int харьцуулах( Э о) {...}

  нийтийн эцсийн Class< Э > getDeclaringClass() { ... }
  нийтийн статик <T өргөтгөл Enum<T>> T valueOf(Class<T> enumType, String name) { ... }
}

Тунхаглал дахь гайхмаар зүйл “ Enum<E Enum<E>> өргөтгөл “гэж шинээр тодорхойлсон анги нь баримт юм Enum болон түүний шинээр тодорхойлсон төрлийн параметр Э ижил төрлийн параметрийн хязгаарт гарч ирнэ.  Энэ нь гэсэн үг Enum төрөл нь түүний дэд төрлүүдийн аль нэгэнд нь үүсгэгдсэн байх ёстой.  Энэ нь яагаад утга учиртай болохыг ойлгохын тулд тооллын төрөл бүрийг дэд төрөл болгон хөрвүүлдэг гэдгийг анхаарч үзээрэй Enum .

Энэ бол зохиомол тооллын төрөл юм Өнгө :

тоо Өнгө {УЛААН, ЦЭНХЭР, НОГООН}

Хөрвүүлэгч үүнийг дараах ангилалд хөрвүүлдэг.

нийтийн эцсийн анги Өнгө сунгадаг Enum<Color> {
  нийтийн статик эцсийн Өнгө[] утгууд() { буцах (Өнгө[])$VALUES.clone(); }
  нийтийн статик Өнгөний утгаOf(Мөрийн нэр) { ... }   private Color(String s, int i) { super(s, i); }

  нийтийн статик эцсийн Өнгө RED;
  нийтийн статик эцсийн Өнгө ЦЭНХЭР;
  нийтийн статик эцсийн Өнгө НОГООН;

  хувийн статик эцсийн Өнгө $VALUES[];

  статик {
    RED = шинэ өнгө("RED", 0);
    ЦЭНХЭР = шинэ өнгө("ХӨХ", 1);
    НОГООН = шинэ өнгө("НОГООН", 2);
    $VALUES = (шинэ Өнгө[] { УЛААН, ЦЭНХЭР, НОГООН });
  }
}

Өв залгамжлал нь ийм нөлөө үзүүлдэг Өнгө төрөл нь хэрэгжсэн бүх аргыг өвлөн авдаг Enum<Color> .  Тэдгээрийн дотор харьцуулах арга.  The Өнгө. харьцуулах арга нь магадгүй авах ёстой Өнгө аргумент болгон.  Үүнийг хийхийн тулд анги Enum ерөнхий бөгөөд Enum.compareTo арга авдаг Enum -ийн төрлийн параметр Э аргумент болгон.  Үүний үр дүнд бичнэ үү Өнгө -аас гаралтай Enum<Color> өвлөн авдаг а харьцуулах шаардлагатай арга Өнгө болон аргумент, яг байх ёстой шигээ.
Хэрэв бид тунхаглалыг задлан үзвэл “ Enum<E Enum<E>> өргөтгөл “Энэ загвар нь хэд хэдэн талтай гэдгийг бид харж байна.

Нэгдүгээрт, төрлийн параметр нь төрөл өөрөө байна гэсэн баримт байдаг: “ Enum <E сунгаж байна Enum <E>> “. Энэ нь зөвхөн төрөл зүйлийн дэд төрлийг баталгаажуулдаг Enum төрлийн аргумент болгон зөвшөөрнө. (Онолын хувьд төрөл Enum гэх мэт өөр дээрээ үүсгэж болно Enum<Enum> , гэхдээ энэ нь мэдээж зориулагдаагүй бөгөөд ийм жишээ нь ашигтай байх нөхцөл байдлыг төсөөлөхөд хэцүү байдаг.)

Хоёрдугаарт, параметрт хамаарах төрөл нь параметржүүлсэн төрөл байдаг Enum <E> , төрөл параметрийг ашигладаг Э хязгаарын төрлийн аргумент болгон. Энэ мэдэгдэл нь дэд төрөл болон instanation хоорондын удамшлын хамаарлыг баталгаажуулдаг Enum хэлбэртэй байна X Enum<X> өргөтгөл “. ” гэх мэт дэд төрөл X Enum<Y> өргөтгөл ” төрлийн аргументын улмаас зарлах боломжгүй Ю хязгаарт багтахгүй байх; зөвхөн дэд төрлүүд Enum<X> хязгаар дотор байна.

Гуравдугаарт, ийм баримт бий Enum эхний ээлжинд ерөнхий шинж чанартай байдаг.  Энэ нь ангийн зарим аргууд гэсэн үг юм Enum аргумент авах эсвэл үл мэдэгдэх төрлийн утгыг буцаана (эсвэл үл мэдэгдэх төрлөөс хамаарна). Бидний мэдэж байгаагаар энэ үл мэдэгдэх төрөл нь хожим нь дэд төрөл болно X -ийн Enum<X> .  Тиймээс параметржүүлсэн төрөлд Enum<X> , эдгээр аргууд нь дэд төрлийг агуулдаг X , мөн тэдгээр нь дэд төрөлд өвлөгдөнө X .  The харьцуулах арга нь ийм аргын жишээ юм; Энэ нь дээд ангиас дэд анги болгонд өвлөгддөг бөгөөд тохиолдол бүрт дэд ангиллын тусгай гарын үсэгтэй байдаг.

Дүгнэж хэлэхэд тунхаглал “ Enum<E Enum<E>> өргөтгөл “-г дараах байдлаар тайлж болно. Enum нь зөвхөн дэд төрлүүдэд нь зориулж үүсгэж болох ерөнхий төрөл бөгөөд тэдгээр дэд төрлүүд нь зарим ашигтай аргуудыг өвлөн авах бөгөөд зарим нь дэд төрлөөс тодорхой аргументуудыг авдаг (эсвэл дэд төрлөөс хамаарна).

Ангиудын доод хязгаарын төрлийн параметрүүд

Төрөл бүрийн параметрүүд нь хэд хэдэн хязгаартай байж болно анги Box<T өргөтгөл Number> {...} . Гэхдээ төрлийн параметр нь доод хязгааргүй байж болно, тухайлбал бүтэц анги Box<T гайхалтай Number> {...} зөвшөөрөгдөөгүй.  Яагаад болохгүй гэж?  Хариулт нь: хэрэв зөвшөөрвөл энэ нь танд юу ч худалдаж авахгүй тул утгагүй юм.  Төрөл бүрийн параметрийн дээд хязгаар нь юу гэсэн үг болохыг судалснаар ангиудын доод хязгаарын төрлийн параметрүүд яагаад будлиантай байдгийг харцгаая.

Төрөл параметрийн дээд хязгаар нь гурван нөлөөтэй:

    1. Хязгаарлагдмал хувилбар. Дээд хязгаар нь ерөнхий төрлийг жишээ болгоход ашиглаж болох төрлүүдийн багцыг хязгаарладаг.  Хэрэв бид зарлавал a анги Box<T өргөтгөл Number> {...} дараа нь хөрвүүлэгч зөвхөн дэд төрлүүдийг баталгаажуулна Тоо төрлийн аргумент болгон ашиглаж болно.  Энэ нь, а Box<Number> эсвэл a Box<Long> зөвшөөрөгдсөн боловч a Box<Object> эсвэл Box<String> татгалзах байсан

Жишээ (төрлийн параметрийн дээд хязгаарын улмаас хязгаарлагдмал үүслийн):
анги Box<T өргөтгөл Number> { 
   хувийн T утга; 
   нийтийн хайрцаг(T t) { утга = t; } 
   ...
}  ангийн тест { 
   public static void main(String[] args) { 
       Box<Long> boxOfLong = шинэ Box<Long>(0L);   // зүгээр
       Box<String>  boxOfString = шинэ Box<String>(""); // алдаа: Мөр хязгаар дотор биш байна
   }
}

  1. Статик бус гишүүдэд хандах. Дээд хязгаар нь бүх нийтийн статик бус аргууд болон дээд хязгаарын талбарт хандах боломжийг олгодог.  хэрэгжүүлэхдээ манай анги Box<T өргөтгөл Number> {...} бид ангид тодорхойлсон бүх нийтийн статик бус аргуудыг дуудаж болно Тоо гэх мэт intValue() жишээ нь.  Дээд хязгааргүй бол хөрвүүлэгч ийм дуудлагаас татгалзах болно. Жишээ (төрлийн параметрийн дээд хязгаарын улмаас статик бус гишүүдэд хандах хандалт):

анги Box<T өргөтгөл Number> { 
   хувийн T утга; 
   нийтийн хайрцаг(T t) { утга = t; } 
   public increment() { буцаах утга.intValue()+1; } // <= нь Тоо хязгааргүй алдаа болно
   ...
} 

    1. Устгах гэж бичнэ үү. Хамгийн зүүн талын дээд хязгаарыг төрөл арилгахад ашигладаг бөгөөд байт кодын төрлийн параметрийг орлоно.  Манайд анги Box<T өргөтгөл Number> {...} бүх тохиолдлууд Т дээд хязгаараар солигдоно Тоо .  Жишээлбэл, хэрэв анги Хайрцаг төрлийн хувийн талбартай Т ба арга хүчингүй багц(T контент) Энэ хувийн талбарыг тохируулахын тулд талбар нь төрөл байх болно Тоо төрөл арилгасны дараа арга нь арга руу хөрвүүлэгдэх болно хүчингүй багц(Тооны агуулга) .

Жишээ (төрөл арилгахад төрлийн параметрийн дээд хязгаарыг ашиглах – өмнө төрөл арилгах):
анги Box< T дугаарыг сунгана > { 
   хувийн Т үнэ цэнэ; 
   нийтийн хайрцаг( Т t) {утга = t; } 
   ...
} 

      Жишээ (төрөл арилгахад төрлийн параметрийн дээд хязгаарыг ашиглах –

дараа

      төрөл арилгах):

 

анги хайрцаг { 
   хувийн Тоо үнэ цэнэ; 
   нийтийн хайрцаг( Тоо t) {утга = t; } 
   ...
}

    Нэмж дурдахад, хамгийн зүүн дээд хязгаар нь автоматаар оруулсан цутгамал болон гүүрний аргууд гэх мэт өөр байршилд харагдана.

Хэрэв төрлийн параметрүүд дээр доод хязгаарыг зөвшөөрвөл ямар гаж нөлөө үзүүлэх вэ? гэх мэт бүтээн байгуулалт бол анги Box<T гайхалтай Number> {...} зөвшөөрсөн, энэ нь юу гэсэн үг вэ?  Дээд төрлийн параметрийн хязгаарлалтын 3 гаж нөлөө – хязгаарлагдмал үүсгэлт, статик бус гишүүнд хандах хандалт, төрөл устгах – доод хязгаарын хувьд юу гэсэн үг вэ?

Хязгаарлагдмал хувилбарууд. Хөрвүүлэгч нь доод хязгаартай төрлийн параметр бүхий ерөнхий төрлийг жишээ болгоход ашиглаж болох төрлүүдийн багцыг хязгаарлаж болно.  Жишээ нь, хөрвүүлэгч нь инстанцуудыг зөвшөөрөх боломжтой Box<Number> болон Box<Object> -аас а Box<T гайхалтай Тоо > гэх мэт тохиолдлуудыг үгүйсгэх Box<Long> эсвэл Box<Short> .  Энэ нь дээд төрлийн параметрийн хязгаарт тодорхойлсон хязгаарлагдмал гаж нөлөөний дагуу нөлөөлнө.

Статик бус гишүүдэд хандах. Доод төрлийн параметрийн хязгаар нь ангиас удамшсан аргуудаас бусад тодорхой аргуудад хандах боломжийг олгодоггүй Объект . -ийн жишээнд Box<T гайхалтай Тоо > супер төрлүүд Тоо Эдгээр нь лавлагааны төрөл, тиймээс дэд төрлөөс бусад нийтлэг зүйлгүй Объект .  Хөрвүүлэгч нь тухайн төрлийн талбар гэж үзэж болохгүй Т төрлийн байна Тоо эсвэл түүний дэд төрөл.  Оронд нь төрлийн талбар Т ямар ч супер төрлийн байж болно Тоо гэх мэт Цувралдах боломжтой эсвэл Объект .  гэх мэт аргын дуудлага intValue() нь төрөлд аюулгүй байхаа больсон бөгөөд хөрвүүлэгч үүнийг татгалзах шаардлагатай болно. Үүний үр дүнд доод төрлийн параметрийн хязгаар нь ангид тодорхойлсоноос илүү статик бус гишүүдэд хандах эрхгүй болно. Объект улмаар “хязгааргүй”-тэй ижил нөлөө үзүүлдэг.

Устгах гэж бичнэ үү .  Энэ логик шугамын дагуу төрлийн параметрийн тохиолдлуудыг зүүн доод хязгаараар солих нь утгагүй юм.  Бүтээгч шиг аргыг зарлаж байна Хайрцаг( Т т) бүтээгчийн хувьд Хайрцаг( Тоо т) үүнийг бодоход утгагүй юм Т -ийн супер төрлөөр солигдоно Тоо .  Ан Объект instantiation-д байгуулагч руу зөв дамжуулж болно Box<Object> мөн бүтээгч үүнийг үгүйсгэх болно.  Энэ бол үхлийн буруу байх болно.   Тиймээс type erasure нь төрлийн хувьсагчийн бүх тохиолдлыг орлуулах болно Т төрлөөр Объект , мөн доод хязгаараар нь биш.  Дахин хэлэхэд доод хязгаар нь “хязгааргүй”-тэй ижил нөлөө үзүүлэх болно.

Хэрэв хоёулаа доогуур байвал энэ нь юу гэсэн үг болохыг олж мэдмээр байна уу _болон_ дээд хязгаарыг зөвшөөрсөн үү?   Би хувьдаа энэ тухай бодохыг ч хүсэхгүй байгаа бөгөөд хэрэв та зөвшөөрвөл “удирдах боломжгүй” гэсэн хэсэгт оруулахыг илүүд үздэг.

Хамгийн гол нь: энэ бүхэн “ гайхалтай ” Бонд чамайг худалдаж авна гэдэг нь зөвхөн супер төрлийн хязгаарлалт юм Тоо төрлийн аргумент болгон ашиглаж болно.  Тэр ч байтугай энэ нь ихэвчлэн буруугаар ойлгогддог.  Энэ нь тийм биш гэсэн үг анги Box<T супер Number> {...} зөвхөн супер төрлийн тохиолдлуудыг агуулдаг Тоо .  Доорх жишээнээс харахад яг эсрэгээрээ!

Жишээ (төрөл арилгахад төрлийн параметрийн дээд хязгаарыг ашиглах – өмнө төрөл арилгах):

анги Box< T супер тоо > {
   хувийн Т үнэ цэнэ;
   нийтийн хайрцаг( Т t) {утга = t; }
   ...
}

Жишээ (төрөл арилгахад төрлийн параметрийн дээд хязгаарыг ашиглах – дараа төрөл арилгах):

анги хайрцаг {
   хувийн Объект үнэ цэнэ;
   нийтийн хайрцаг( Объект t) {утга = t; }
   ...
}

А анги Box<T гайхалтай Number> {...} erasure төрлөөр a гэж орчуулагдах болно Хайрцаг агуулсан Объект талбар болон түүний байгуулагчийг орчуулах болно Хайрцаг(Объект t) . Энэ нь үндсээрээ ялгаатай анги Box<T сунгадаг Number> {...} , үүнийг а руу орчуулах болно Хайрцаг агуулсан а Тоо талбар болон түүний байгуулагчийг орчуулах болно Хайрцаг(тоо t) . Үүний үр дүнд, А Box<Number> а-аас үүсгэсэн анги Box<T өргөтгөл Number> {...} а-аас ялгаатай байх болно Box<Number> жишээ нь a анги Box<T супер Number> {...} , энэ нь төөрөгдөл үүсгэх магадлалтай.  Ийм учраас доод хязгаар нь ангиудын төрлийн параметрүүдэд утгагүй болно.

 


 

Аргын доод хязгаарын төрлийн параметрүүд

Аргууд болон тэдгээрийн аргументуудын төрлүүдийн хамт доод хязгаартай төрлийн параметр заримдаа хэрэг болдог.

Жишээ (доод хязгаартай төрлийн параметрээс ашиг тустай аргын):

анги Pair<X,Y> {
   эхлээд хувийн X;
   хувийн Y секунд;
   ...
   нийтийн < Супер X , B супер Ү > B addToMap(Map<A,B> газрын зураг) { // алдаа: төрлийн параметр нь доод хязгаартай байж болохгүй.
      map.put(эхний, хоёр дахь);
   }
}
ангийн тест { 
   public static void main(String[] args) { 
     Pair<String,Long> хос = шинэ Pair<>("ABC",42L);
     Map<CharSequence, Number> газрын зураг = HashMap<CharSequence, Number>();
     Тооны дугаар = pair.addToMap(газрын зураг);
   }
}

The AddToMap() арга нь газрын зураг дээр хосын агуулгыг нэмдэг.  -ийн супер төрлийг багтаах боломжтой аливаа газрын зураг X болон Ю хийх байсан.  Газрын зураг нь тавих() арга нь газрын зураг дээр түлхүүрийн утгын оруулга аль хэдийн байгаа бол тухайн түлхүүрийн газрын зураг дээрх утгыг буцаана.  Газрын зургийн буцах утга тавих() аргаас буцаана AddToMap() арга.  Ийм нөхцөлд дээр дурдсанчлан аргыг зарлахыг хүсч байна: Газрын зураг нь хосын төрлийн параметрүүдийн супер төрлүүдээр параметрлэгдсэн. AddToMap() аргын буцах төрөл нь газрын зургийн утгын төрөл юм.

Хөрвүүлэгч нь төрлийн параметрийн доод хязгаарыг зөвшөөрдөггүй тул бид үүнийг тойрон гарах шаардлагатай байна.

Оролцох тэмдэгтүүд нь доод хязгаартай байж болох тул орлуулагдах тэмдэг ашиглах нь санаанд орж ирдэг.  Энд орлуулагдах тэмдэг ашиглан тойрон гарах арга зам байна.

Жишээ (орчуулагч тэмдэгтүүдийг ашиглан өмнөх жишээг тойрч гарах арга зам):

анги Pair<X,Y> {
   эхлээд хувийн X;
   хувийн Y секунд;
   ...
   олон нийтийн Объект AddToMap(Map< ? Супер X , ? супер Ю > газрын зураг) { 
      map.put(эхний, хоёр дахь);
   }
}
ангийн тест { 
   public static void main(String[] args) { 
     Pair<String,Long> хос = шинэ Pair<>("ABC",42L);
     Map<CharSequence, Number> газрын зураг = HashMap<CharSequence, Number>();
     Тооны дугаар = (Тоо) pair.addToMap(газрын зураг);
   }
}

Буцах төрлийг хүссэнээр зарлах арга байхгүйгээс бусад тохиолдолд энэ нь ажилладаг.  Энэ нь супер төрөл байх болно Ю хөрвүүлэгч газрын зургийн төрлөөс авдаг боловч үүнийг зааж өгөх синтакс байхгүй байна.  Бид буцах төрлийг “a” гэж зарлах ёсгүй. ? супер Ю “, учир нь” ? супер Ю ” нь орлуулагч тэмдэг бөгөөд төрөл биш, тиймээс буцаах төрлийг зөвшөөрөхгүй. Бидэнд ямар ч сонголт байхгүй, ашиглах ёстой Объект оронд нь манай аргын буцах төрөл.  Энэ нь тодорхой бус буцах төрөл нь эргээд дуудагчдыг албаддаг AddToMap() -аас буцах утгыг доош буулгах арга Объект түүний бодит төрөлд.  Энэ нь яг бидний бодож байсан зүйл биш юм.

Өөр нэг шийдвэрлэх арга бол статик аргыг ашиглах явдал юм.  Энд статик бус аргын оронд статик ашиглан тойрон гарах арга зам байна.

Жишээ (статик аргыг ашиглан өмнөх жишээг тойрч гарах арга зам):

анги Pair<X,Y> {
   эхлээд хувийн X;
   хувийн Y секунд;
   ...
   олон нийтийн статик < А , Б , X сунгаж А ,Y B сунгадаг > B addToMap(Pair<X,Y> хос, Map< А , Б > газрын зураг) {
      буцах газрын зураг.put(хос.эхний,хоёр.хоёр дахь);
   }
}
ангийн тест { 
   public static void main(String[] args) { 
     Pair<String,Long> хос = шинэ Pair<>("ABC",42L);
     Map<CharSequence, Number> газрын зураг = HashMap<CharSequence, Number>();
     Тооны дугаар = Хос .addToMap( хос ,газрын зураг);
   }
}

Ерөнхий AddToMap() арга нь дөрвөн төрлийн параметртэй: хоёр орлуулагч X болон Ю хосын төрөл болон хоёр орлуулагчийн хувьд А болон Б газрын зургийн төрөл. А болон Б -ийн супер төрлүүд юм X болон Ю , учир нь X болон Ю   -тай тунхаглаж байна А болон Б тэдний дээд хязгаар гэж. (Ерөнхий аргын төрлийн параметрүүдийг анхаарна уу X болон Ю -тай ямар ч холбоогүй Хос ангийн X болон Ю параметрүүд.  Нэрс X болон Ю Эдгээрийг хосын төрлийн параметр болгон хялбархан танихын тулд ерөнхий аргад дахин ашигладаг. Дөрвөн төрлийн параметрийг ашигласнаар бид тодорхой буцаах төрлийг хүссэнээр зарлаж болно: энэ нь газрын зургийн утгын төрөлтэй ижил төрөл юм.

Жишээ (ерөнхий ангийн статик контекст дахь төрлийн параметрийг хууль бусаар ашиглах):

Зарим анги <T> {
  // статик эхлүүлэгч, статик талбар, статик арга
  статик {
    ЗаримClass< Т > тест = шинэ SomeClass< Т >(); // алдаа
  }
  хувийн статик Т globalInfo;          // алдаа
  олон нийтийн  статик Т getGlobalInfo() {        // алдаа
    globalInfo-г буцаах;
  }
  // статик бус эхлүүлэгч, статик бус талбар, статик бус арга
  { 
    ЗаримClass< Т > тест = шинэ SomeClass< Т >();
  }
  хувийн        Т localInfo;
  олон нийтийн         Т getLocalInfo() { 
    localInfo-г буцаах;
  }
  // статик үүрлэсэн төрлүүд
  олон нийтийн статик анги Амжилтгүй бол онцгой тохиолдлыг сунгана {
    хувийн финал Т мэдээлэл;           // алдаа
    нийтийн бүтэлгүйтэл( Т t) { мэдээлэл = t; }      // алдаа
    олон нийтийн Т getInfo() { мэдээлэл буцаах; }    // алдаа
   }
  хувийн интерфейс Хуулбарлах боломжтой {
    Т хуулбар ();                       // алдаа
  }
  хувийн тоо муж {
    ХҮЧИН, ХҮЧИНГҮЙ;
    хувийн Т мэдээлэл; // алдаа
    нийтийн хүчингүй багц мэдээлэл( Т t) { мэдээлэл = t; } // алдаа
    олон нийтийн Т getInfo() { мэдээлэл буцаах; }    // алдаа
  }
  // статик бус үүрлэсэн төрлүүд
  олон нийтийн анги Дагалдах хэрэгсэл {
    олон нийтийн Т getInfo() {localInfo буцаана; }
  }
}

Жишээ нь төрлийн параметрийг ерөнхий ангийн статик контекстэд ашиглах боломжгүйг харуулж байна.  Энэ нь мөн үүрлэсэн интерфэйсүүд болон тооллын төрлүүдийг тухайн ангийн статик төрлийн гишүүд гэж үздэгийг харуулж байна.  Зөвхөн дотоод ангиуд, өөрөөр хэлбэл статик бус үүрлэсэн ангиуд хавсаргасан ерөнхий ангийн төрлийн параметрийг ашиглаж болно.

Интерфейсийн төрлийн параметрийн хамрах хүрээ нь талбар эсвэл үүрлэсэн төрлөөс бусад интерфейсийн бүхэл бүтэн тодорхойлолт юм.  Учир нь интерфейс дээр тодорхойлсон талбарууд болон үүрлэсэн төрлүүд нь далд статик байдаг.

Жишээ (ерөнхий интерфейс дэх төрлийн параметрийг хууль бусаар ашиглах):

Зарим интерфэйс <T> {
  // талбар
  ЗаримClass< Т > утга = шинэ SomeClass< Т >();  // алдаа
  // үүрлэсэн төрөл
  анги Дагалдах хэрэгсэл {
    олон нийтийн Т getInfo() {            // алдаа
      буцаах утга.getGlobalInfo();
    }
  }
  // аргууд
  Т getValue();
}

Жишээ нь интерфэйсийн талбарууд нь далд статик байдгийг харуулж байгаа тул төрлийн параметрийг ерөнхий интерфейсийн талбарын мэдэгдлийн хаана ч ашиглах боломжгүй.  Үүний нэгэн адил, үүрлэсэн анги нь дотоод анги биш, статик үүрлэсэн анги гэж тооцогддог ба ийм шалтгаанаар төрөл параметрийг үүрлэсэн ангийн аль ч хэсэгт ашиглах нь хууль бус юм.

Суурилуулсан статик ангиуд болон интерфэйсийг шийдвэрлэх арга зам:

Статик үүрлэсэн ангиуд болон интерфейсийн хувьд энэ нь томоохон гамшиг биш юм.  Үүнийг шийдвэрлэхийн тулд бид статик класс эсвэл интерфейсийг өөрөө үүсгэж болно.

Жишээ (зайлах арга – үүрлэсэн статик төрлийг үүсгэх):

ангийн боодол <T> {
  хувийн финал Т theObject;

  нийтийн боодол( Т t) { theObject = t; }
  олон нийтийн Т getWrapper() {объектыг буцаана; }   нийтийн хувиршгүй <T> makeImmutable() {
        шинэ хувиршгүй буцаах <T> (TheObject);
  }
  нийтийн Хувиргах <T> makeMutable() {
        шинэ Хувиргагчийг буцаана <T> (TheObject);
  }
  хувийн статик <A> makeClone(A theObject) { ... }

  public static final class Immutable <A> { // нь одоо ерөнхий анги юм
        хувийн финал А theObject;

        нийтийн хувиршгүй( А arg) {
            theObject = makeClone(arg);
        }
        олон нийтийн А getWrappedItem() {
            makeClone(TheObject) буцаах;
        }
  }
  нийтийн статик анги Хувиргах <A> {
        ... төстэй ...
  }
}

Үүрлэсэн тооллын төрлүүд ерөнхий байж болохгүй тул ийм тойрон гарах арга зам байхгүй.

Суурилуулсан статик ангиудыг шийдвэрлэх арга зам:

Хэрэв үүрлэсэн статик төрөл нь анги бол статик ангийг статик бус дотоод анги болгон хувиргах өөр нэг арга зам болно.

Жишээ (тайлагдах арга – дотоод анги ашиглах):

ангийн боодол <T> {
  хувийн финал Т theObject;

  нийтийн боодол( Т t) { theObject = t; }
  олон нийтийн Т getWrapper() {объектыг буцаана; }   нийтийн Хувиргах боломжтой makeMutable() {
      буцах энэ. шинэ Хувиргах(TheObject);
  }
  public Immutable makeImmutable() {
      буцах энэ. new Immutable(theObject);
  }
  хувийн статик <A> makeClone(A theObject) { ... }

  нийтийн эцсийн анги өөрчлөгддөггүй {  // статик анги байхаа больсон
      хувийн финал Т theObject;

      нийтийн хувиршгүй( Т arg) {
          theObject = makeClone(arg);
      }
      олон нийтийн Т getWrappedItem() {
          makeClone(TheObject) буцаах;
      }
  }
  нийтийн анги Хувиргах 
        ... төстэй ...
  }
}

Бүх дотоод ангиудад гаднах төрлийн жишээний далд лавлагаа байдаг бөгөөд энэ жишээнд тэдэнд шаардлагагүй, давуу тал ч байхгүй; далд лавлагаа нь зүгээр л ачаа юм.  Ихэнхдээ дотоод ангиудыг хавсаргасан ангийн хувийн хэрэгжилтийн дэлгэрэнгүй мэдээлэл байлгахын тулд дотоод ангиудыг интерфейстэй хослуулдаг.  Бид энд ч мөн адил хийж чадна.

Жишээ (өмнөх арга замыг боловсронгуй болгосон):

ангийн боодол <T> {
  хувийн финал Т theObject;

  нийтийн боодол( Т t) { theObject = t; }
  олон нийтийн Т getWrapper() {объектыг буцаана; }   нийтийн Хувиргах <T> makeMutable() {
      буцаах this.new Mutable(theObject);
  }
  нийтийн хувиршгүй <T> makeImmutable() {
      буцаах this.new Immutable(theObject);
  }
  хувийн статик <A> makeClone(A theObject) { ... }

  нийтийн интерфейс хувиршгүй<S> {
      S getWrappedItem();
  }
  нийтийн интерфейс Mutable<S> {
      S getWrappedItem();
      хүчингүй болсон setWrappedItem(S arg);
  }
  хувийн эцсийн анги ImmutableImplementation Immutable<T> хэрэгжүүлдэг { 

      хувийн эцсийн T theObject;

      public ImmutableImplementation(T arg) {
          theObject = makeClone(arg);
      }
      нийтийн T getWrappedItem() {
          makeClone(TheObject) буцаах;
      }
  }
  хувийн анги MutableImplementation Mutable<T> хэрэгжүүлдэг { 
        ... төстэй ...
  }
}

Таны харж байгаагаар, үүрлэсэн нийтийн интерфэйсүүд нь ерөнхий байх ёстой бол дотоод хувийн ангиуд нь хавсаргасан ангийн төрлийн параметрийг ашиглаж болно.

 

 

 

 

 

Хариулт үлдээнэ үү