กลับไปหน้าบทความ

อ่าน 6 นาที

ไวลด์การ์ด (Java)

ใน ภาษาการเขียนโปรแกรม Java ตัวอักษร ตัวแทน (wildcard ) ? เป็นอาร์กิวเมนต์ประเภทพิเศษ [ 1 ] ที่ควบคุม ความปลอดภัยของประเภท ในการใช้ ประเภท ทั่วไป (แบบมีพารามิเตอร์) [ 2 ]...

ไวลด์การ์ด (Java)

ในภาษาการเขียนโปรแกรม Java ตัวอักษร ตัวแทน (wildcard ) ?เป็นอาร์กิวเมนต์ประเภทพิเศษ[ 1 ]ที่ควบคุมความปลอดภัยของประเภทในการใช้ ประเภท ทั่วไป (แบบมีพารามิเตอร์) [ 2 ]สามารถใช้ในการประกาศตัวแปรและการสร้างอินสแตนซ์ รวมถึงในคำจำกัดความของเมธอด แต่ไม่สามารถใช้ในคำจำกัดความของประเภททั่วไปได้[ 3 ] [ 4 ]นี่เป็นรูปแบบหนึ่งของคำอธิบายประกอบความแปรผัน ณตำแหน่งการใช้งาน ซึ่งแตกต่างจาก คำอธิบายประกอบความแปรผัน ณ ตำแหน่งคำจำกัดความที่ พบในC#และScala

ความแปรปรวนร่วมสำหรับประเภททั่วไป

ต่างจากอาร์เรย์ (ซึ่งเป็นโคเวเรียนต์ใน Java [ 2 ] ) การสร้างอินสแตนซ์ที่แตกต่างกันของประเภททั่วไปจะไม่เข้ากันได้ แม้จะระบุไว้อย่างชัดเจนก็ตาม[ 2 ]ตัวอย่างเช่น การประกาศ

ทั่วไป< ซูเปอร์ไทป์> ซูเปอร์เจเนริก; ทั่วไป< ซับไทป์> ซับเจเนริก;

จะทำให้คอมไพเลอร์รายงานข้อผิดพลาดในการแปลงสำหรับทั้งการแคสติ้ง(Generic<Subtype>)superGenericและ(Generic<Supertype>)subGeneric.

ความไม่เข้ากันนี้สามารถบรรเทาลงได้ด้วยไวด์การ์ดหาก?ใช้เป็นพารามิเตอร์ประเภทจริง[ 2 ]Generic<?>เป็นซูเปอร์ไทป์ของพารามิเตอร์ทั้งหมดของประเภททั่วไปGenericซึ่งช่วยให้วัตถุประเภทGeneric<Supertype>และGeneric<Subtype>สามารถกำหนดให้กับตัวแปรหรือพารามิเตอร์เมธอดประเภท ได้อย่างปลอดภัยGeneric<?>[ 2 ] การใช้ช่วยให้ทำเช่นเดียวกัน โดยจำกัดความเข้ากันได้กับและลูกๆ ของมัน[ 5 ]อีกความเป็นไปได้หนึ่งคือซึ่งยอมรับทั้งวัตถุ และจำกัดความเข้ากันได้กับและผู้ปกครองทั้งหมดของมัน[ 5 ]Generic<?extendsSupertype>SupertypeGeneric<?superSubtype>Subtype

ไวลด์การ์ดเป็นประเภทพารามิเตอร์

ในตัวหน่วยทั่วไป พารามิเตอร์ประเภท (อย่างเป็นทางการ) จะถูกจัดการเหมือนกับขอบเขตบน (แสดงด้วยextends; java.lang.Objectหากไม่ถูกจำกัด) [ 5 ]หากประเภทการส่งคืนของเมธอดเป็นพารามิเตอร์ประเภท ผลลัพธ์ (เช่น ประเภท?) สามารถอ้างอิงได้โดยตัวแปรของประเภทขอบเขตบน (หรือjava.lang.Object) ในทางกลับกัน ตัวอักษรตัวแทนไม่เหมาะกับประเภทอื่น แม้แต่java.lang.Object: หาก?ถูกนำไปใช้เป็นพารามิเตอร์ประเภทอย่างเป็นทางการของเมธอด จะไม่สามารถส่งพารามิเตอร์จริงไปยังเมธอดได้ อย่างไรก็ตาม วัตถุของประเภทที่ไม่รู้จักสามารถอ่านได้จากวัตถุทั่วไปและกำหนดให้กับตัวแปรของซูเปอร์ไทป์ของขอบเขตบน

ตัวอย่างโค้ดสำหรับคลาสนี้: Generic<TextendsUpperBound>

class Generic < T extends UpperBound > { private T t ;public Generic ( T t ) { this . t = t ; }public void set ( T t ) { this . t = t ; }public T get () { return t ; } }

ตัวอย่างโค้ดที่ใช้คลาสนี้: Generic<TextendsUpperBound>

Generic < UpperBound > concreteTypeReference = new Generic <> (); Generic <?> wildcardReference = concreteTypeReference ; UpperBound ub = wildcardReference . get (); // Object ก็ใช้ได้เช่นกันwildcardReference.set ( new Object ( )); // ข้อผิดพลาดประเภทwildcardReference.set ( new UpperBound ()); // ข้อผิดพลาดประเภทconcreteTypeReference.set ( new UpperBound ( )); // ถูกต้อง

ไวลด์การ์ดแบบจำกัดขอบเขต

ไวลด์การ์ดแบบมีขอบเขต คือ ไวลด์การ์ดที่มีข้อจำกัด การสืบทอดแบบบนหรือล่างขอบเขตของไวลด์การ์ดอาจเป็นประเภทคลาส ประเภทอินเทอร์เฟซ ประเภทอาร์เรย์ หรือตัวแปรประเภทextends ขอบเขตบนแสดงโดยใช้ คำหลัก `upper` และขอบเขตล่างแสดง โดยใช้ superคำหลัก `lower` ไวลด์การ์ดสามารถมีขอบเขตได้มากที่สุดหนึ่งขอบเขตเท่านั้น คือ ขอบเขตบนหรือขอบเขตล่าง แต่ไม่ใช่ทั้งสองอย่างพร้อมกัน

ขอบเขตบน

ขอบเขตบนของไวลด์การ์ดจะต้องเป็นชนิดย่อยของขอบเขตบนของพารามิเตอร์ประเภทที่สอดคล้องกันซึ่งประกาศไว้ในประเภททั่วไปที่สอดคล้องกัน[ 5 ]ตัวอย่างของไวลด์การ์ดที่ระบุขอบเขตบนอย่างชัดเจนคือGeneric<?extendsSubtypeOfUpperBound>referenceConstrainedFromAbove;

การอ้างอิงนี้สามารถเก็บค่าพารามิเตอร์ใดๆ ก็ได้ โดยที่Genericอาร์กิวเมนต์ประเภทเป็นชนิดย่อยของSubtypeOfUpperBoundไวลด์การ์ดที่ไม่ได้ระบุขอบเขตบนอย่างชัดเจนนั้นมีผลเหมือนกับไวลด์การ์ดที่มีข้อจำกัดเนื่องจากประเภทอ้างอิงทั้งหมดใน Java เป็นชนิดย่อยของ extendsObjectjava.lang.Object

ขอบเขตล่าง

ตัวอักษรแทนค่าที่มีขอบเขตล่าง เช่นGeneric<?superSubtypeOfUpperBound>referenceConstrainedFromBelow;

สามารถเก็บพารามิเตอร์ใดๆ ก็ได้ซึ่งGenericอาร์กิวเมนต์ประเภทใดๆ ก็ตามเป็นทั้งซับไทป์ของขอบเขตบนของพารามิเตอร์ประเภทที่สอดคล้องกันและเป็นซูเปอร์ไทป์SubtypeOfUpperBoundของ[ 5 ]

การสร้างวัตถุด้วยสัญลักษณ์ตัวแทน (wildcard)

ไม่สามารถสร้างอ็อบเจ็กต์โดยใช้ประเภทตัวแทน (wildcard) ได้ เช่น เป็นสิ่งต้องห้าม ในทางปฏิบัติแล้ว สิ่งนี้ไม่จำเป็น เพราะหากต้องการสร้างอ็อบเจ็กต์ที่สามารถกำหนดให้กับตัวแปรประเภทก็สามารถใช้ประเภทใดก็ได้ (ที่อยู่ภายใต้ข้อจำกัดของตัวแทน หากมี) เป็นประเภทอ้างอิงได้ newGeneric<?>()Generic<?>

อย่างไรก็ตามสามารถทำได้ เนื่องจากสัญลักษณ์ตัวแทน (wildcard) ไม่ใช่พารามิเตอร์ของประเภทที่สร้างขึ้นหลักการเดียวกันนี้ใช้ได้กับเช่นกัน newArrayList<Generic<?>>()java.lang.ArrayList<E>newArrayList<List<?>>()

ในนิพจน์การสร้างอาร์เรย์ ประเภทส่วนประกอบของอาร์เรย์จะต้องสามารถระบุได้ตามที่กำหนดไว้ในข้อกำหนดภาษาจาวา ส่วนที่ 4.7 ซึ่งหมายความว่า หากประเภทส่วนประกอบของอาร์เรย์มีอาร์กิวเมนต์ประเภทใด ๆ อาร์กิวเมนต์เหล่านั้นจะต้องเป็นไวด์การ์ดที่ไม่จำกัดขอบเขตทั้งหมด (ไวด์การ์ดที่ประกอบด้วยเพียงค่าว่าง?) ตัวอย่างเช่น นั้นถูกต้อง ในขณะที่ นั้นไม่ถูกต้อง newGeneric<?>[20]newGeneric<SomeType>[20]

สำหรับทั้งสองกรณี การไม่ใช้พารามิเตอร์ก็เป็นอีกทางเลือกหนึ่ง วิธีนี้จะทำให้เกิดคำเตือน เนื่องจากมีความปลอดภัยด้านประเภทข้อมูลน้อยกว่า (ดูที่ประเภทข้อมูลดิบ )

ตัวอย่าง

ในJava Collections Frameworkคลาสjava.util.List<E>จะแทนคอลเลกชันของวัตถุประเภทที่มีการเรียงEลำดับ ขอบเขตบนจะถูกระบุโดยใช้extends: A คือรายการของวัตถุของคลาสย่อยบางคลาสของ กล่าวคือ วัตถุใดๆ ในรายการจะรับประกันได้ว่าเป็นประเภทดังนั้นจึงสามารถวนซ้ำได้โดยใช้ตัวแปรประเภท[ 6 ]List<?extendsMyClass>MyClassMyClassMyClass

import java.util.List ;public void doSomething ( List <? extends MyClass > list ) { for ( MyClass object : list ) { // ตกลง// ทำอะไรบางอย่าง} }

อย่างไรก็ตาม ไม่รับประกันว่าจะสามารถเพิ่มวัตถุประเภทใดก็ได้MyClassลงในรายการนั้นได้:

import java.util.List ;public void doSomething ( List <? extends MyClass > list ) { MyClass m = new MyClass (); list.add ( m ); // เกิดข้อผิดพลาดในการคอมไพล์}

ในทางกลับกัน ข้อความนี้เป็นจริงสำหรับขอบเขตล่าง ซึ่งระบุโดยใช้super: A คือรายการของวัตถุของคลาสแม่บางคลาสของกล่าวคือ รายการนั้นรับประกันได้ว่าจะสามารถบรรจุวัตถุใดๆ ก็ได้ของประเภทดังนั้นจึงสามารถเพิ่มวัตถุใดๆ ก็ได้ของประเภท: List<?superMyClass>MyClassMyClassMyClass

import java.util.List ;public void doSomething ( List <? super MyClass > list ) { MyClass m = new MyClass ( ); list.add ( m ); // OK }

อย่างไรก็ตาม ไม่รับประกันว่าจะสามารถวนซ้ำรายการนั้นโดยใช้ตัวแปรประเภทMyClass:

import java.util.List ;public void doSomething ( List <? super MyClass > list ) { for ( MyClass object : list ) { // เกิดข้อผิดพลาดในการคอม ไพล์ // ทำบางอย่าง} }

เพื่อให้สามารถเพิ่มอ็อบเจ็กต์ประเภท `in` MyClassลงในลิสต์และวนซ้ำลิสต์โดยใช้ตัวแปรประเภท `in` ได้ จึงจำเป็นต้องใช้ MyClass`a` List<MyClass>ซึ่งเป็นประเภทเดียวของ ` Listin` ที่เป็นทั้ง `in` และ`in` List<?extendsMyClass>List<?superMyClass>

ตัวช่วยจำ PECS (Producer Extends, Consumer Super) จากหนังสือEffective JavaโดยJoshua Blochช่วยให้จำได้ง่ายว่าควรใช้ไวด์การ์ดเมื่อใด (ซึ่งสอดคล้องกับ Covariance และ Contravariance) ใน Java [ 5 ]

ข้อจำกัดประเภทในภาษาอื่นๆ

คุณสมบัติที่ใกล้เคียงที่สุดกับพารามิเตอร์ประเภทไวด์การ์ดของ Java คือ ไวด์การ์ดประเภทของ Scalaซึ่งแสดงด้วยสัญลักษณ์?ตั้งแต่ Scala 3 (ใน Scala 2 จะแสดงด้วยสัญลักษณ์_) [ 7 ]ขอบเขตของ Scala ทำงานเหมือนกับของ Java: เทียบเท่ากับในขณะที่ เทียบเท่ากับ List[?<:Number]List<?extendsNumber>List[?>:Integer]List<?superInteger>

ในC++ข้อจำกัดประเภททั่วไปสามารถแสดงได้โดยใช้แนวคิด[ 8 ]

import std ;using std :: is_base_of_v ; using std :: vector ;คลาสPlayer { // ... };template < typename T > concept ExtendsPlayer = is_base_of_v < Player , T > ;// T ต้องเป็นประเภทที่มีขอบเขตการสืบทอดสูงสุดเป็น Player // ซึ่งจะบล็อกประเภทใดๆ ที่ไม่ได้สืบทอดมาจาก Player template < ExtendsPlayer T > void processListOfPlayers ( vector < T > players ) { // ... }

ตัวอย่างนี้เทียบเท่ากับโค้ด Java ต่อไปนี้:

import java.util.List ;คลาสPlayer { // ... }public class Example { // T ถูกจำกัดให้เป็นประเภทที่สืบทอดมาจาก Player public static < T extends Player > void processListOfPlayers ( List < T > players ) { // ... } }

ในC#ขอบเขตของประเภทสามารถแสดงได้เป็นและ(เมื่อเทียบกับ Java และตามลำดับ) ในขณะที่ข้อจำกัดของประเภททั่วไปจะแสดงด้วยข้อความ ซึ่งมีความชัดเจนและมีประสิทธิภาพมากกว่าไวด์การ์ดใน Java [ 9 ]X<outT>X<inT>X<?extendsT>X<?superT>where

โดยใช้ระบบ;public class MyGenericClass < T , U > where T : IComparable < T > , allows ref struct where U : class , notnull , new () { // ... }

แม้ว่า Kotlinจะเป็นภาษา JVM เช่นกัน แต่ก็ไม่รองรับสัญลักษณ์ตัวแทนประเภทแบบ Java อย่างไรก็ตาม มันแสดง?แทนด้วย*(ตัวอย่างเช่นList<*>) รวมถึงขอบเขตประเภทเป็นและ(เมื่อเทียบกับ Java และ ตามลำดับ) นอกจากนี้ยังมี ข้อความแบบ C# ดังนี้[ 10 ]X<outT>X<inT>X<?extendsT>X<?superT>where

fun < T > copyWhenGreater ( list : List < T > , threshold : T ): List < String > where T : CharSequence , T : Comparable < T > { return list . filter { it > threshold }. map { it . toString () } }

Rustยังใช้whereclauses เพื่อผูก trait เข้า ด้วยกันอีกด้วย

ใช้std :: cmp :: Ord ;struct MyStruct < T > where T : Ord + Default { value : T }impl < T > MyStruct < T > where T : Ord + Default { fn new ( value : T ) -> Self { MyStruct { value } }fn is_less_than ( & self , other : & Self ) -> bool { self . value < other . value } }

ดูเพิ่มเติม

การอ้างอิง

  1. ^ "บทที่ 4. ประเภท ค่า และตัวแปร" . docs.oracle.com . สืบค้นเมื่อ2020-11-03 .
  2. ^ a b c d e Bloch 2018 , หน้า 117–122, บทที่ §5 ข้อ 26: ห้ามใช้ชนิดข้อมูลดิบ
  3. ^ Gilad Bracha (มิถุนายน 2547), "4. Wildcards", Generics ในภาษาการเขียนโปรแกรม Java (PDF) , สืบค้นเมื่อ6 มีนาคม 2559
  4. ^ "8.1.2 คลาสทั่วไปและพารามิเตอร์ประเภท", ข้อกำหนดภาษา Java , Oracle , สืบค้นเมื่อ6 มีนาคม 2016
  5. ^ a b c d e f Bloch 2018 , หน้า 139–145, บทที่ §5 ข้อ 31: ใช้ไวลด์การ์ดแบบจำกัดขอบเขตเพื่อเพิ่มความยืดหยุ่นของ API
  6. ^การสืบทอด (การเขียนโปรแกรมเชิงวัตถุ)
  7. ^ scala-lang.org (28 พฤษภาคม 2026). "อาร์กิวเมนต์ไวด์การ์ดในประเภท" . docs.scala-lang.org . scala-lang.org.
  8. ^ cppreference.com (6 มิถุนายน 2026). "ข้อจำกัดและแนวคิด" . cppreference.com . cppreference.com.
  9. ^ "where (generic type constraint)" . learn.microsoft.com . Microsoft Learn. 30 กรกฎาคม 2024.
  10. ^ "Generics: in, out, where Kotlin" . kotlinlang.org . JetBrains sro . สืบค้นเมื่อ15 ตุลาคม 2025 .
ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Wildcard_(Java)&oldid=1359254933 "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ ไวลด์การ์ด (Java)

ใน ภาษาการเขียนโปรแกรม Java ตัวอักษร ตัวแทน (wildcard ) ? เป็นอาร์กิวเมนต์ประเภทพิเศษ [ 1 ] ที่ควบคุม ความปลอดภัยของประเภท ในการใช้ ประเภท ทั่วไป (แบบมีพารามิเตอร์) [ 2 ]...

ความแปรปรวนร่วมสำหรับประเภททั่วไป

ต่างจากอาร์เรย์ (ซึ่งเป็น โคเวเรียนต์ ใน Java [ 2 ] ) การสร้างอินสแตนซ์ที่แตกต่างกันของประเภททั่วไปจะไม่เข้ากันได้ แม้จะระบุไว้อย่างชัดเจนก็ตาม [ 2 ] ตัวอย่างเช่น การประกาศ

ไวลด์การ์ดเป็นประเภทพารามิเตอร์

ในตัวหน่วยทั่วไป พารามิเตอร์ประเภท (อย่างเป็นทางการ) จะถูกจัดการเหมือนกับ ขอบเขตบน (แสดงด้วย extends ; java.lang.Object หากไม่ถูกจำกัด) [ 5 ] หากประเภทการส่งคืนของเมธอดเป็นพารามิเตอร์ประเภท ผลลัพธ์ (เช่น ประเภท ?

ไวลด์การ์ดแบบจำกัดขอบเขต

ไวลด์การ์ดแบบมีขอบเขต คือ ไวลด์การ์ดที่มีข้อจำกัด การสืบทอด แบบบนหรือล่างขอบเขตของไวลด์การ์ดอาจเป็นประเภทคลาส ประเภท อินเทอร์เฟ ซ ประเภทอาร์เรย์ หรือ ตัวแปรประเภท extends ขอบเขตบนแสดงโดยใช้ คำหลัก `upper` และขอบเขตล่างแสดง โดยใช้ super คำหลัก `lower`...