2016-09-01 17 views
8

Với một API như:Với 'T` và' U` nơi 'T kéo dài U` làm thế nào để trả về một' U`

class Bar { ... } 
class Foo extends Bar { ... } 

Trong Optional loại Java, chúng ta có thể nói:

Optional<Foo> fooOption = ... 
fooOption.orElse(aFoo) // returns something of type Foo 

Nhưng, kể từ Foo là một Bar, tôi muốn để có thể nói:

Optional<Foo> fooOption = ... 
fooOption.orElse(aBar) // returns something of type Bar 

là một tập thể dục, tôi wa nted để thực hiện điều này với loại khác:

public abstract class Option<T> { 
    // this doesn't compile 
    public abstract <U super T> U orElse(U other); 
} 

Làm thế nào tôi sẽ viết lại này để biên dịch, mà còn hỗ trợ khả năng mở rộng các loại khi mong muốn cùng một lúc?

+0

'abstract class Lựa chọn {public abstract U OrElse (U khác);} '? tại sao bạn lại đặt tên cho phương thức 'orElse' - điều này có thể gây nhầm lẫn cho những người mong đợi' Optional.orElse' – alfasin

Trả lời

6

Nhưng, kể từ Foo là một Bar

Nhưng Bar không phải là một Foo. Những gì tôi có nghĩa là bạn có thể làm điều này:

Optional<Bar> fooOpt = Optional.of(new Foo()); 
Bar bar = fooOpt.orElse(new Bar()); 

Nhưng bạn không thể làm điều tương tự với Optional<Foo> vì nó vi phạm gõ hạn chế của phương pháp Optional.orElse.

Thực hiện giả thuyết của Option<T> bạn nên xác định một cách rõ ràng U như một supertype của T

public class Option<U, T extends U> { 
    T value; 

    public U orElse(U other) { 
     if (value != null) { 
      return value; 
     } 
     return other; 
    } 
} 

Trong trường hợp đó bạn có thể viết một mã như thế này

Option<Foo, Bar> fooOpt = Option.of(new Foo()); 
Bar bar = fooOpt.orElse(new Bar()); 
+0

Tôi đồng ý rằng 'Bar' không phải là' Foo', nhưng tôi có thể cung cấp giá trị 'Bar' và nhận 'Bar' đã nhập tham chiếu cho' Foo' chứa hoặc 'Bar' mà tôi đã cung cấp. – Scoobie

+0

Tôi muốn chỉ định 'U' loại * ngầm * tại thời điểm tôi gọi phương thức. – Scoobie

+0

Xác định 'Tùy chọn ' của nó là 'Tùy chọn 'mở rộng loại trong tất cả các tình huống, nơi tôi chỉ muốn mở rộng nó trong một tình huống cụ thể. – Scoobie

3

Kể từ U nên là siêu loại T, bạn có thể làm:

public abstract class Option<U, T extends U> { 

    public abstract of(T value); 

    public abstract U orElse(U other); 

} 
2

Có một tiền đề cơ bản mà là thiếu sót trong câu hỏi của bạn:

Trong loại tùy chọn của Java, chúng ta có thể nói:

Tùy chọn fooOption = ... fooOption.orElse (aFoo) // returns một cái gì đó của loại Foo Nhưng, vì Foo là một Bar, tôi muốn để có thể nói:

fooOption Tùy chọn = ... fooOption.orElse (Abar) // trả về một cái gì đó kiểu Bar

A Foo là một Bar, nhưng Bar không phải là một Foo. Nếu Chung của bạn được định nghĩa là:

Optional<Foo> fooOption = ... 

Sau đó, bạn có thể trả lại bất kỳ thứ gì thuộc loại Foo. A Barkhông phải loại Foo.

Nếu bạn đã có một đối tượng bổ sung:

class FooBar extends Foo{} 

Sau đó, bạn có thể bỏ nó vào một foo trong ví dụ của bạn:

Tùy chọn fooOption = ...

fooOption.orElse (aFooBar) // trả về một cái gì đó thuộc loại Foo

Hoặc, optiona lly, nếu bạn đã xác định OptionalOptional<Bar> thì bạn có thể sử dụng các đối tượng Foo hoặc Bar hoặc FooBar vì tất cả đều là hoặc được kế thừa từ loại Bar.

Đối với phần thứ hai của câu hỏi của bạn:

public abstract class Option<T> { 
    // this doesn't compile 
    public abstract <U super T> U orElse(U other); 
} 

Chỉ cần bằng cách viết này với siêu kiểu chung:

public abstract class Option<T> { 
    // this now compiles. 
    public abstract T orElse(T other); 
} 

Bạn đang nói rằng bất cứ điều gì đó là của hoặc kế thừa từ loại T là chấp nhận được.

+0

Kết luận của bạn là đúng, nhưng nó cung cấp chức năng đảo ngược. Tôi muốn * mở rộng * loại. Có nghĩa là, tôi muốn bất kỳ thứ gì có ** của ** hoặc ** có thể được thừa kế từ để tạo ra 'T' **. – Scoobie

+0

Tôi nghĩ chúng ta đang nói cùng một điều. Bất cứ thứ gì có một siêu lớp chung của T. – Kylar

3

Bạn có thể xác định phương pháp của riêng bạn sử dụng map để mở rộng loại:

public static <U, T extends U> U orElse(Optional<T> tOpt, U u) { 
    return tOpt.<U>map(Function.identity()).orElse(u); 
} 
+0

Rõ ràng là không. Tôi chỉ muốn làm cho nó có thể tái sử dụng được. –

+0

Đây không phải là một giải pháp tồi, nhưng tôi muốn nó là một phương pháp đối tượng, không phải là một tĩnh. – Scoobie

+0

@Scoobie có thể không thực hiện được. –

Các vấn đề liên quan