2016-09-01 10 views
8

Biorąc API jak:Biorąc `T` i` `T U` gdzie rozciąga U` jak zwrócić` U`

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

W Java Optional typu, możemy powiedzieć:

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

Ale ponieważ Foo jest Bar, chciałbym móc powiedzieć:

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

Jako ćwiczenie, ja wa nted do osiągnięcia tego celu z innego typu:

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

Jak bym przepisać to skompilować, ale także wspierać zdolność do poszerzenia typ gdy jest to pożądane w tym samym czasie?

+0

'klasa abstrakcyjna Opcja {public abstract U OrElse (U inne);}'? dlaczego nazwałbyś metodę 'orElse' - może to zmylić ludzi oczekujących' Opcjonalnie.orElse' – alfasin

Odpowiedz

6

Ale ponieważ Foo jest Bar

Ale Bar nie jest Foo. Chodzi mi o to, że można to zrobić:

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

Ale nie można zrobić to samo z Optional<Foo> ponieważ narusza typu ograniczeń Optional.orElse metody.

W hipotetycznym realizacji Option<T> należy wyraźnie określić jako U supertypem z T

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

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

W takim przypadku można napisał kod jak poniżej

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

Zgadzam się, że 'Bar' nie jest' Foo', ale powinienem być w stanie podać wartość 'Bar' i uzyskać 'Bar' wpisał referencję dla' Foo' zawartego lub 'Bar', które dostarczyłem. – Scoobie

+0

Chciałbym określić 'U' typ * niejawnie * w czasie wywołać metodę. – Scoobie

+0

Definiowanie mojego "Opcjonalnie " jako "Opcjonalnie " rozszerza typ we wszystkich sytuacjach, w których chcę go rozszerzyć tylko w określonej sytuacji. – Scoobie

3

Od U powinna być super- typ T, możesz zrobić:

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

    public abstract of(T value); 

    public abstract U orElse(U other); 

} 
2

Jest to podstawowa przesłanka, że ​​jest wadliwy w swoim pytaniu:

W opcjonalnego typu Java, możemy powiedzieć:

Opcjonalnie fooOption = ... fooOption.orElse (aFoo) // zwraca coś typu Foo Ale ponieważ Foo jest bar, chciałbym móc powiedzieć:

Opcjonalnie fooOption = ... fooOption.orElse (Abar) // zwraca coś typu Bar

Foo to bar, ale bar nie jest Foo. Jeśli Generic jest zdefiniowany jako to:

Optional<Foo> fooOption = ... 

Następnie można powrócić niczego, co jest rodzaju Foo. A Bar jest typu typu.

Jeśli miał dodatkowy przedmiot:

class FooBar extends Foo{} 

Następnie można rzucić go do foo w przykładzie:

Opcjonalnie fooOption = ...

fooOption.orElse (aFooBar) // zwraca coś typu Foo

Lub, optiona lly, jeśli zdefiniowałeś swoje Optional jako Optional<Bar>, możesz użyć obiektów Foo lub Bar lub FooBar, ponieważ wszystkie one są lub dziedziczą z typu Bar.

Co do drugiej części pytania:

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

Wystarczy pisząc ten ze wspólnym supertypem:

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

Mówisz, że wszystko, co jest z lub dziedziczy od typ T jest dopuszczalny.

+0

Twój wniosek jest słuszny, ale zapewnia odwrotną funkcjonalność. Chcę * poszerzyć * typ. Znaczenie: chcę, aby wszystko, co ** lub **, mogło zostać odziedziczone, aby utworzyć 'T' **. – Scoobie

+0

Myślę, że mówimy to samo. Cokolwiek, co ma wspólną superklasę T. – Kylar

3

Można zdefiniować swoją własną metodę z użyciem map rozszerzyć typ:

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

Oczywiście nie. Chciałem po prostu zrobić to ponownie. –

+0

To nie jest złe rozwiązanie, ale chciałbym, aby była to metoda obiektowa, a nie statyczna. – Scoobie

+0

@Scoobie, które może nie być możliwe. –