2011-08-04 36 views
7

Ý nghĩa của mã thông báo <?> trong mã này được sao chép từ www.JavaPractices.com là gì? Khi tôi thay thế nó bằng cách tìm kiếm thông thường hơn <T> được sử dụng cho các loại chung, nó không biên dịch được. (Lỗi: T không thể được giải quyết thành một loại.) Tại sao?Ý nghĩa của mã thông báo <?> trong Java là gì?

// <?> occurs 3 times in the entire program. When it is replaced with <T> the 
// program no longer compiles. 

void activateAlarmThenStop() 
{ 
    Runnable myPeriodicTask = new PeriodicTask(); 
    ScheduledFuture<?> soundAlarmFuture = 
     this.executorService.scheduleWithFixedDelay(myPeriodicTask, 
              startT, 
              period, 
              TimeUnit.SECONDS 
             ); 
    Runnable stopAlarm = new StopAlarmTask(soundAlarmFuture); 
    this.executorService.schedule(stopAlarm, stopT, TimeUnit.SECONDS); 
} 

private final class StopAlarmTask implements Runnable 
{ 
    StopAlarmTask(ScheduledFuture<?> aSchedFuture) 
    { 
     fSchedFuture = aSchedFuture; 
    } 

    public void run() 
    { 
     CConsole.pw.println("Stopping alarm."); 
     fSchedFuture.cancel(doNotInterruptIfRunningFlag); 

     executorService.shutdown(); 
    } 
    private ScheduledFuture<?> fSchedFuture; 
} 

Chỉnh sửa: Tất nhiên khi chúng tôi sử dụng các loại mã thông thường như <T>, nó phải xuất hiện trong khai báo lớp. Ở đây không có <T> hoặc <?> trong tuyên bố lớp học nhưng nó vẫn biên dịch và chạy đúng cách.

+0

nhìn vào câu trả lời thay đổi nội dung của tôi .. – ngesh

+0

Kiểm tra mới chỉnh sửa – BOSS

Trả lời

6

Nó không biên dịch, bởi vì lớp học của bạn không phải là chung chung (cũng không phải bất kỳ phương pháp nào của bạn). Trong ví dụ cụ thể này joker (?) Có nghĩa là ScheduledFuture có thể được parametrized bởi bất cứ điều gì.

Đôi khi, không có ý nghĩa để làm cho toàn bộ lớp chung nếu bạn sử dụng một lớp chung chung bên trong và bạn không biết loại chính xác sẽ được sử dụng. Trong ví dụ này, bạn có ba lựa chọn:

  1. làm StopAlarmTask generic (không có ý nghĩa trong trường hợp này)
  2. sử dụng loại bê tông trong ScheduledFuture, nhưng sau đó nó sẽ chỉ có một thể loại kết quả, ví dụ chuỗi hoặc Số nguyên
  3. sử dụng ký tự đại diện() - nó cho phép truy xuất mọi thứ dưới dạng kết quả của FutureResult (Chuỗi, Số nguyên, lớp tùy chỉnh của bạn). Bạn cũng có thể thu hẹp phạm vi của một kiểu generic có thể vào một số lớp con, ví dụ ScheduledGeneric< ? extends MyObject > hoặc vào superclasses: ScheduledGeneric< ? super MyObject >
+0

Câu trả lời của bạn có vẻ phù hợp với như được sử dụng cho các loại chung chung. Tuy nhiên, câu hỏi là về . – H2ONaCl

+0

Vui lòng xem các chỉnh sửa của tôi. Hy vọng nó rõ ràng bây giờ. –

1

Đó là Generic Type ... thường chúng tôi đặt Chuỗi, đối tượng hoặc bất kỳ đối tượng nào khác làm loại chung ... nhưng ở đây chúng làm cho nó chung chung. và loại chung là viết tắt của giá trị nó có thể store or hold. nó thường được sử dụng trong Collections ..

cũng không có nhiều khác biệt giữa cả hai .. - mất tất cả các loại của các đối tượng

   <T>-is also called `formal type parameter` makes use of what ever type of object you pass in .. for instance you can do this with <T> and not with <?> 

public class Box<T> { 

    private T t; // T stands for "Type" 

    public void add(T t) { 
     this.t = t; 
    } 

    public T get() { 
     return t; 
    } 
} 

để biết thêm thấy http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdfhttp://download.oracle.com/javase/tutorial/java/generics/gentypes.html

+0

câu trả lời của bạn không mô tả sự khác biệt giữa . – H2ONaCl

+0

"Không có nhiều khác biệt" không phải là một câu trả lời, LOL. – H2ONaCl

2

Đây là một ví dụ của việc sử dụng ký tự đại diện trong một cuộc tranh luận kiểu. tức là một loại chung. Loại tham số ký tự đại diện là một phiên bản của loại chung mà ít nhất một đối số loại là ký tự đại diện. Ví dụ về các loại tham số ký tự đại diện là Collection<?>, List<? extends Number>, Comparator<? super String>Pair<String,?>.

Loại tham số ký tự đại diện biểu thị một nhóm các kiểu bao gồm các dấu hiệu cụ thể của loại chung. Loại ký tự đại diện được sử dụng xác định loại tham số cụ thể nào thuộc về gia đình.

0

Có thể mất bất kỳ thông số như Object, String, Integer .... và vân vân

Bây giờ khi bạn có kế hoạch để sử dụng Generics sau đó bạn phải cung cấp các loại bên trong khung thiên thần.

CHỈNH SỬA:

<?> hoàn toàn phù hợp với Bộ sưu tập. <T> được sử dụng làm loại hoặc mẫu cho lớp bình thường của bạn

+0

Bạn đang mô tả nhưng câu hỏi là về . – H2ONaCl

0

Joker ? có thể chứa bất kỳ loại nào. Nếu bạn muốn sử dụng cùng một loại cho tất cả các phương pháp/thành viên, bạn có thể làm cho toàn bộ lớp chung chung. Bằng cách viết StopAlarmTask<T>, bạn xác định loại T trong toàn bộ lớp học.

private final class StopAlarmTask<T> implements Runnable 
{ 
    StopAlarmTask(ScheduledFuture<T> aSchedFuture) 
    { 
     fSchedFuture = aSchedFuture; 
    } 

    public void run() 
    { /* */ } 

    private ScheduledFuture<T> fSchedFuture; 
} 
+0

Bạn đang mô tả nhưng câu hỏi là về . – H2ONaCl

1

Một chữ cái trong ngoặc đơn như <T> sẽ là thông số loại. Bạn có thể nói class StopAlarmTask<T> để có nghĩa là bạn đang tham số loại StopAlarmTask với loại T. Tham số kiểu T sẽ trở thành một phần của kiểu, kiểu giống như một đối số hàm tạo trở thành một phần của một cá thể mới.

Sau đó, bất cứ khi nào bạn khai báo số StopAlarmTask, bạn sẽ cung cấp một loại, ví dụ: String, để điền thông số loại T. Sau đó, bạn có thể tham khảo thông số loại đó trong nội dung lớp. Ví dụ: bạn có thể xác định các phương pháp lấy số T hoặc trả về một số T hoặc tham số hóa biến thành viên như fSchedFuture với T. Ví dụ: nếu bạn đã tham số hóa một tuyên bố là StopAlarmTask<T>StopAlarmTask<String> thì String sẽ được ghi lại là T và bất cứ nơi nào bạn sử dụng T trong đó StopAlarmTask nó sẽ hoạt động như String.

Tuy nhiên, trong mã bạn đã liệt kê, StopAlarmTask không có thông số loại và không thể tham số hóa với bất kỳ loại nào. Không có loại bị bắt nào để tham chiếu là T trong nội dung lớp học.

Mặt khác, <?> có nghĩa là "Tôi không biết loại đó sẽ là gì; Tôi thậm chí không biết rằng đó sẽ là loại mà ai đó đã sử dụng để tham số StopAlarmTask".

Bạn có thể có tham số StopAlarmTask<T>, và trong trường hợp đó bạn có thể có hai biến:

private ScheduledFuture<T> fSchedFuture1; 
private ScheduledFuture<?> fSchedFuture2; 

Việc kê khai đầu tiên nói rằng tham số kiểu của ScheduledFuture cũng giống như tham số kiểu của kèm theo StopAlarmTask. Ví dụ. StopAlarmTask<String> sẽ đặt fSchedFuture1 thành ScheduledFuture<String>. Tuyên bố thứ hai nói rằng chúng ta không biết tham số kiểu của ScheduledFuture là gì, ngay cả khi chúng ta biết tham số kiểu của kèm theo StopAlarmTask.

1

Giả sử this.executorService là loại phụ của ScheduledExecutorService (có sẵn từ Java 1.5), loại trả về là scheduleWithFixedDelay()ScheduledFuture<?>. Bạn không thể thay đổi loại trả lại từ ScheduledFuture<?> thành ScheduledFuture<T>, ScheduledFuture<Integer> hoặc bất kỳ thứ gì khác cho vấn đề đó. Tuy nhiên, bạn có thể thay đổi nó thành chỉ ScheduledFuture kể từ <?> là một thông số loại ký tự đại diện chung chung xấp xỉ một loại thô cho khả năng tương thích ngược.

Xem What is a raw type and why shouldn't we use it? để có cuộc thảo luận tốt về loại thô và thuốc generic.

0

StopAlarmTask không phải là loại chung.

Trong ví dụ sau, bạn sẽ không nghĩ rằng Foo là loại chung.

class Foo 
{ 
    Foo(int i) 
    { } 

    doStuff(List<Integer> numbers) 
    { } 
} 

Thực tế là các nhà xây dựng của StopAlarmTask sử dụng một tham số chung không làm cho lớp generic bất kỳ hơn doStuff() làm Foo generic.

Sử dụng <?> để "tham chiếu" khai báo loại chung theo cách chung chung, tức là không có tính đặc hiệu. Trong StopAlarmTask nó chỉ xảy ra là một tham số hàm tạo. Nó là một "việc làm" một loại chung chung và không phải là một tuyên bố của một loại chung chung bởi vì nó là "chỉ đơn thuần" một khai báo tham số.

Nói cách khác, câu trả lời ngắn gọn là tham số trong phương pháp

StopAlarmTask(ScheduledFuture<?> aSchedFuture) 
{ ... } 

được áp dụng cho tất cả các đối tượng đó là trường hợp củaScheduledFuture<T> cho tất cả T.

Sau đây là nền thêm về Generics.

Sử dụng <T> hoặc <E> hoặc bất kỳ điều gì để khai báo loại chung ScheduledFuture<T>. Cụ thể, <?> sẽ không được sử dụng trong khai báo ScheduledFuture<> vì quy ước là sử dụng một chữ cái hoa duy nhất. Lưu ý rằng mã thử nghiệm sau đây, nếu được cung cấp cho trình biên dịch, sẽ chỉ ra rằng lớp đầu tiên biên dịch nhưng thứ hai không, vì vậy để nói rằng có một quy ước sử dụng một chữ cái thực sự là một cách nói.

class TGeneric1<E> { 
    List<E> list = new ArrayList<E>(); 
    TGeneric1(E value) { 
     this.list.add(value); 
    } 
    E getHead() { 
     return this.list.get(0); 
    } 
} 

class TGeneric2<?> { 
    List<?> list = new ArrayList<?>(); 
    TGeneric2(? value) { 
     this.list.add(value); 
    } 
    ? getHead() { 
     return this.list.get(0); 
    } 
} 

Minh họa trong mã kiểm tra sau, không có ràng buộc chữ cái nào, do đó, điều sau cũng đúng.

class TGeneric1<EE> { 
    List<EE> list = new ArrayList<EE>(); 
    TGeneric1(EE value) { 
     this.list.add(value); 
    } 
    EE getHead() { 
     return this.list.get(0); 
    } 
} 
Các vấn đề liên quan