Cum pot face ca tipul de returnare a metodei să fie generic? (Programare, Java, Generice, Valoare De Returnare)

Sathish a intrebat.

Luați în considerare acest exemplu (tipic în cărțile OOP):

Am o metodă Animal clasă, în care fiecare Animal poate avea mai mulți prieteni.
Și subclase precum Dog, , Duck, , Mouse etc. care adaugă un comportament specific, cum ar fi bark(), , quack() etc.

Iată Animal clasa:

public class Animal {
    private Map<String,Animal> friends = new HashMap<>();

    public void addFriend(String name, Animal animal){
        friends.put(name,animal);
    }

    public Animal callFriend(String name){
        return friends.get(name);
    }
}

Și iată câteva fragmente de cod cu o mulțime de tipărire:

Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());

((Dog) jerry.callFriend("spike")).bark();
((Duck) jerry.callFriend("quacker")).quack();

Există vreo posibilitate de a folosi generice pentru tipul return pentru a scăpa de tipărire, astfel încât să pot spune

jerry.callFriend("spike").bark();
jerry.callFriend("quacker").quack();

Iată un cod inițial cu tipul de retur transmis metodei ca parametru care nu este niciodată utilizat.

public<T extends Animal> T callFriend(String name, T unusedTypeObj){
    return (T)friends.get(name);        
}

Există vreo modalitate de a afla tipul de returnare în timpul execuției fără parametrul suplimentar, folosind instanceof? Sau cel puțin prin trecerea unei clase de tip în loc de o instanță fictivă.
Înțeleg că genericele sunt pentru verificarea tipului în timpul compilării, dar există o soluție pentru acest lucru?

19 răspunsuri
laz

Ați putea defini callFriend în acest fel:

public <T extends Animal> T callFriend(String name, Class<T> type) {
    return type.cast(friends.get(name));
}

Apoi apelați-l ca atare:

jerry.callFriend("spike", Dog.class).bark();
jerry.callFriend("quacker", Duck.class).quack();

Acest cod are avantajul de a nu genera avertismente de compilator. Bineînțeles, aceasta este de fapt doar o versiune actualizată a casting-ului din zilele de dinainte de generică și nu adaugă nicio siguranță suplimentară.

Comentarii

    33

  • … dar tot nu are nicio verificare de tip în timp de compilare între parametrii apelului callFriend(). –  > Por David Schmitt.
  • Acesta este cel mai bun răspuns de până acum – dar ar trebui să modificați addFriend în același mod. Este mai greu să scrii bug-uri, deoarece ai nevoie de acel literal de clasă în ambele locuri. –  > Por Craig P. Motlin.
  • @Jaider, nu este exact la fel, dar acest lucru va funcționa: // Clasa Animal public T CallFriend<T>(string name) where T : Animal { return friends[name] as T; } // Clasa de apelare jerry.CallFriend<Dog>(„spike”).Bark(); jerry.CallFriend<Duck>(„quacker”).Quack(); –  > Por Nestor Ledon.
David Schmitt

Nu. Compilatorul nu poate ști ce tip de fișier jerry.callFriend("spike") ar returna. De asemenea, implementarea dvs. ascunde pur și simplu cast-ul în metodă, fără nicio siguranță de tip suplimentară. Luați în considerare acest lucru:

jerry.addFriend("quaker", new Duck());
jerry.callFriend("quaker", /* unused */ new Dog()); // dies with illegal cast

În acest caz specific, crearea unui abstract talk() și suprascrierea ei în mod corespunzător în subclase ar fi mult mai utilă:

Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());

jerry.callFriend("spike").talk();
jerry.callFriend("quacker").talk();

Comentarii

  • Deși metoda mmyers poate funcționa, cred că această metodă este mai bună pentru programarea OO și vă va scuti de probleme în viitor. –  > Por James McMahon.
  • Acesta este modul corect de a obține același rezultat. Observați că scopul este de a obține un comportament specific clasei derivate în timpul execuției fără a scrie explicit cod pentru a face verificarea tipurilor și a distribuirii. Metoda propusă de @laz funcționează, dar aruncă siguranța tipurilor pe fereastră. Această metodă necesită mai puține linii de cod (deoarece implementările metodelor sunt oricum legate târziu și sunt consultate în timpul execuției), dar vă permite totuși să definiți cu ușurință un comportament unic pentru fiecare subclasă de Animal. –  > Por dcow.
  • Dar întrebarea inițială nu se referă la siguranța tipurilor. După cum am citit-o eu, cel care a întrebat vrea doar să știe dacă există o modalitate de a folosi genericele pentru a evita să fie nevoie să se facă cast. –  > Por laz.
  • @laz: da, întrebarea inițială – așa cum a fost pusă – nu se referă la siguranța tipurilor. Asta nu schimbă cu nimic faptul că există o modalitate sigură de a implementa acest lucru, eliminând eșecurile de cast de clasă. A se vedea, de asemenea weblogs.asp.net/alex_papadimoulis/archive/2005/05/25/… –  > Por David Schmitt.
  • Nu sunt în dezacord cu acest lucru, dar avem de-a face cu Java și cu toate deciziile/foilele sale de proiectare. Eu văd această întrebare ca pe o simplă încercare de a învăța ce este posibil în Java generics, nu ca pe o problemă xy (meta.stackexchange.com/questions/66377/what-is-the-xy-problem) care trebuie să fie reproiectată. Ca orice model sau abordare, există momente în care codul pe care l-am furnizat este adecvat și momente în care este necesar ceva total diferit (cum ar fi ceea ce ați sugerat în acest răspuns). –  > Por laz.
Michael Myers

Ați putea să o implementați astfel:

@SuppressWarnings("unchecked")
public <T extends Animal> T callFriend(String name) {
    return (T)friends.get(name);
}

(Da, acesta este un cod legal; consultați Java Generics: Tipul generic definit doar ca tip de retur).

Tipul de returnare va fi dedus de la apelant. Cu toate acestea, rețineți că @SuppressWarnings care vă spune că acest cod nu este sigur din punct de vedere al tipurilor. Trebuie să verificați singur acest lucru, altfel ați putea obține ClassCastExceptions în timpul execuției.

Din nefericire, în modul în care îl utilizați (fără a atribui valoarea de returnare unei variabile temporare), singura modalitate de a mulțumi compilatorul este să îl apelați astfel:

jerry.<Dog>callFriend("spike").bark();

În timp ce acest lucru poate fi puțin mai frumos decât casting, probabil că este mai bine să îi dați lui Animal o clasă abstractă talk() așa cum a spus David Schmitt.

Comentarii

  • înlănțuirea metodelor nu a fost cu adevărat o intenție. nu mă deranjează să atribui valoarea unei variabile subtipate și să o folosești. Vă mulțumim pentru soluție. –  > Por Sathish.
  • acest lucru funcționează perfect atunci când se face înlănțuirea apelurilor de metode! –  > Por Hartmut Pfarr.
  • Îmi place foarte mult această sintaxă. Cred că în C# este jerry.CallFriend<Dog>(... ceea ce cred că arată mai bine. –  > Por andho.
  • Este interesant faptul că în JRE se poate observa că propria java.util.Collections.emptyList() este implementată exact în acest mod, iar javadoc-ul său anunță că este sigură din punct de vedere al tipurilor. –  > Por Ti Strga.
  • @TiStrga: Este interesant! Motivul Collections.emptyList() poate scăpa cu asta este că, prin definiția unei liste goale, nu există nici un obiect element de tip T. Deci, nu există riscul de a distribui un obiect la un tip greșit. Obiectele de listă în sine pot funcționa cu orice tip, atâta timp cât nu există elemente. –  > Por Lii.
Craig P. Motlin

Această întrebare este foarte asemănătoare cu Punctul 29 din Java eficient – „Luați în considerare containerele eterogene de tip „typesafe”.” Răspunsul lui Laz este cel mai apropiat de soluția lui Bloch. Cu toate acestea, atât put cât și get ar trebui să utilizeze literalul Class pentru siguranță. Semnăturile ar deveni:

public <T extends Animal> void addFriend(String name, Class<T> type, T animal);
public <T extends Animal> T callFriend(String name, Class<T> type);

În interiorul ambelor metode ar trebui să se verifice dacă parametrii sunt sănătoși. A se vedea Effective Java and the Clasa javadoc pentru mai multe informații.

webjockey

Iată o versiune mai simplă:

public <T> T callFriend(String name) {
    return (T) friends.get(name); //Casting to T not needed in this case but its a good practice to do
}

Codul complet funcțional:

    public class Test {
        public static class Animal {
            private Map<String,Animal> friends = new HashMap<>();

            public void addFriend(String name, Animal animal){
                friends.put(name,animal);
            }

            public <T> T callFriend(String name){
                return (T) friends.get(name);
            }
        }

        public static class Dog extends Animal {

            public void bark() {
                System.out.println("i am dog");
            }
        }

        public static class Duck extends Animal {

            public void quack() {
                System.out.println("i am duck");
            }
        }

        public static void main(String [] args) {
            Animal animals = new Animal();
            animals.addFriend("dog", new Dog());
            animals.addFriend("duck", new Duck());

            Dog dog = animals.callFriend("dog");
            dog.bark();

            Duck duck = animals.callFriend("duck");
            duck.quack();

        }
    }

Comentarii

  • Ce face Casting to T not needed in this case but it's a good practice to do. Adică dacă este rezolvat corespunzător în timpul execuției ce înseamnă „bună practică”? –  > Por Farid.
  • Am vrut să spun că nu este necesară o distribuție explicită (T), deoarece declararea tipului de retur <T> în declarația metodei ar trebui să fie suficientă.  > Por webjockey.
isuru chathuranga

În plus, puteți cere metodei să returneze valoarea într-un anumit tip în felul următor

<T> T methodName(Class<T> var);

Alte exemple aici la documentația Oracle Java

Fabian Steeg

După cum ați spus că trecerea unei clase ar fi în regulă, ați putea scrie așa:

public <T extends Animal> T callFriend(String name, Class<T> clazz) {
   return (T) friends.get(name);
}

Și apoi să o utilizați astfel:

jerry.callFriend("spike", Dog.class).bark();
jerry.callFriend("quacker", Duck.class).quack();

Nu este perfect, dar cam atât de departe se poate ajunge cu genericele Java. Există o modalitate de a implementa Containere eterogene sigure din punct de vedere al tipurilor (THC) folosind Super Type Tokens, , dar acest lucru are din nou propriile sale probleme.

Comentarii

  • Îmi pare rău, dar acesta este exact același răspuns pe care îl are și Laz, așa că fie îl copiați pe el, fie el vă copiază pe dumneavoastră. –  > Por James McMahon.
  • Aceasta este o modalitate bună de a trece tipul. Dar totuși nu este sigur, așa cum a spus Schmitt. Aș putea să trec o clasă diferită, iar tipizarea va fi o bombă. Al doilea răspuns al lui mmyers de a seta tipul în tipul de returnare pare mai bun.  > Por Sathish.
  • Nemo, dacă verifici timpul de postare, vei vedea că le-am postat aproape exact în același moment. De asemenea, nu sunt exact la fel, doar două rânduri. –  > Por Fabian Steeg.
  • @Fabian Am postat un răspuns similar, dar există o diferență importantă între slide-urile lui Bloch și ceea ce a fost publicat în Effective Java. El folosește Class<T> în loc de TypeRef<T>. Dar acesta este în continuare un răspuns excelent. –  > Por Craig P. Motlin.
Mike Houston

Pe baza aceleiași idei ca și la Super Type Tokens, ați putea crea un id tipizat care să fie utilizat în locul unui șir de caractere:

public abstract class TypedID<T extends Animal> {
  public final Type type;
  public final String id;

  protected TypedID(String id) {
    this.id = id;
    Type superclass = getClass().getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
    this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
  }
}

Dar cred că acest lucru ar putea să contrazică scopul, deoarece acum trebuie să creați noi obiecte id pentru fiecare șir și să le păstrați (sau să le reconstruiți cu informațiile de tip corecte).

Mouse jerry = new Mouse();
TypedID<Dog> spike = new TypedID<Dog>("spike") {};
TypedID<Duck> quacker = new TypedID<Duck>("quacker") {};

jerry.addFriend(spike, new Dog());
jerry.addFriend(quacker, new Duck());

Dar acum puteți folosi clasa în modul în care ați dorit inițial, fără caste.

jerry.callFriend(spike).bark();
jerry.callFriend(quacker).quack();

Acest lucru nu face decât să ascundă parametrul de tip în interiorul id-ului, deși înseamnă că puteți prelua tipul din identificator mai târziu, dacă doriți.

Ar trebui să implementați și metodele de comparare și hashing ale TypedID dacă doriți să puteți compara două instanțe identice ale unui id.

Antti Siiskonen

„Există o modalitate de a afla tipul de returnare în timpul execuției fără parametrul suplimentar folosind instanceof?”

Ca o soluție alternativă, ați putea utiliza modelul Visitor în felul următor. Faceți Animal abstract și faceți-l să implementeze Visitable:

abstract public class Animal implements Visitable {
  private Map<String,Animal> friends = new HashMap<String,Animal>();

  public void addFriend(String name, Animal animal){
      friends.put(name,animal);
  }

  public Animal callFriend(String name){
      return friends.get(name);
  }
}

Visitable înseamnă doar că o implementare Animal este dispusă să accepte un vizitator:

public interface Visitable {
    void accept(Visitor v);
}

Iar implementarea unui vizitator este capabilă să viziteze toate subclasele unui animal:

public interface Visitor {
    void visit(Dog d);
    void visit(Duck d);
    void visit(Mouse m);
}

Deci, de exemplu, o implementare Dog ar arăta astfel:

public class Dog extends Animal {
    public void bark() {}

    @Override
    public void accept(Visitor v) { v.visit(this); }
}

Șmecheria aici este că, deoarece câinele știe ce tip este, poate declanșa metoda de vizitare supraîncărcată relevantă a vizitatorului v, trecând „this” ca parametru. Alte subclase ar implementa accept() exact în același mod.

Clasa care dorește să apeleze metodele specifice subclasei trebuie să implementeze interfața Visitor astfel:

public class Example implements Visitor {

    public void main() {
        Mouse jerry = new Mouse();
        jerry.addFriend("spike", new Dog());
        jerry.addFriend("quacker", new Duck());

        // Used to be: ((Dog) jerry.callFriend("spike")).bark();
        jerry.callFriend("spike").accept(this);

        // Used to be: ((Duck) jerry.callFriend("quacker")).quack();
        jerry.callFriend("quacker").accept(this);
    }

    // This would fire on callFriend("spike").accept(this)
    @Override
    public void visit(Dog d) { d.bark(); }

    // This would fire on callFriend("quacker").accept(this)
    @Override
    public void visit(Duck d) { d.quack(); }

    @Override
    public void visit(Mouse m) { m.squeak(); }
}

Știu că sunt mult mai multe interfețe și metode decât v-ați așteptat, dar este o modalitate standard de a obține controlul asupra fiecărui subtip specific cu exact zero verificări de tip instanceof și zero caste de tip. Și totul se face într-un mod standard agnostic față de limbaj, astfel încât nu este doar pentru Java, ci orice limbaj OO ar trebui să funcționeze la fel.

Michael Borgwardt

Nu este posibil. Cum ar trebui să știe Harta ce subclasă de Animal va obține, având în vedere doar o cheie String?

Singurul mod în care acest lucru ar fi posibil ar fi dacă fiecare Animal ar accepta un singur tip de prieten (atunci ar putea fi un parametru al clasei Animal), sau dacă metoda callFriend() ar primi un parametru de tip. Dar se pare că nu înțelegi sensul moștenirii: acesta constă în faptul că poți trata subclasele în mod uniform doar atunci când folosești exclusiv metodele superclasei.

Richard Gomes

Am scris un articol care conține o dovadă de concept, clase de suport și o clasă de test care demonstrează cum pot fi recuperate Super Type Token-urile de către clasele dvs. în timpul execuției.Pe scurt, vă permite să delegați la implementări alternative în funcție de parametrii generici reali trecuți de către apelant. Exemplu:

  • TimeSeries<Double> deleagă la o clasă internă privată care utilizează double[]
  • TimeSeries<OHLC> deleagă la o clasă internă privată care utilizează ArrayList<OHLC>

A se vedea:

Mulțumiri

Richard Gomes – Blog

Comentarii

  • Într-adevăr, vă mulțumim pentru că ați împărtășit cunoștințele dvs., articolul dvs. chiar explică totul! –  > Por Yann-Gaël Guéhéneuc.
  • Articolul original de pe blog (care este minunat!) este disponibil prin intermediul Internet Archive aici –  > Por Scott Babcock.
  • @ScottBabcock : Mulțumesc că m-ați anunțat despre acest link rupt. Am postat un link către noul meu blog, de asemenea. –  > Por Richard Gomes.
MTen

Există o mulțime de răspunsuri excelente aici, dar aceasta este abordarea pe care am adoptat-o pentru un test Appium în care acțiunea asupra unui singur element poate duce la trecerea la diferite stări ale aplicației în funcție de setările utilizatorului. Deși nu respectă convențiile din exemplul lui OP, sper că ajută pe cineva.

public <T extends MobilePage> T tapSignInButton(Class<T> type) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //signInButton.click();
    return type.getConstructor(AppiumDriver.class).newInstance(appiumDriver);
}
  • MobilePage este superclasa pe care tipul o extinde, ceea ce înseamnă că puteți utiliza oricare dintre copiii săi (duh)
  • type.getConstructor(Param.class, etc.) vă permite să interacționați cu constructorul tipului. Acest constructor ar trebui să fie același pentru toate clasele așteptate.
  • newInstance primește o variabilă declarată pe care doriți să o transmiteți constructorului noilor obiecte.

Dacă nu doriți să aruncați erorile, le puteți prinde astfel:

public <T extends MobilePage> T tapSignInButton(Class<T> type) {
    // signInButton.click();
    T returnValue = null;
    try {
       returnValue = type.getConstructor(AppiumDriver.class).newInstance(appiumDriver);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return returnValue;
}

Comentarii

  • După părerea mea, acesta este cel mai bun și mai elegant mod de a utiliza genericul. –  > Por cbaldan.
sk.

Nu chiar, pentru că, așa cum spuneți, compilatorul știe doar că callFriend() returnează un Animal, nu un Câine sau o Rață.

Nu poți adăuga o metodă abstractă makeNoise() la Animal care să fie implementată ca lătrat sau cotcodăceală de către subclasele sale?

Comentarii

  • ce se întâmplă dacă animalele au mai multe metode care nici măcar nu se încadrează într-o acțiune comună care poate fi abstractizată? Am nevoie de acest lucru pentru comunicarea între subclase cu acțiuni diferite, în cazul în care nu am nimic împotrivă să transmit tipul, nu o instanță. –  > Por Sathish.
  • De fapt, tocmai v-ați răspuns la propria întrebare – dacă un animal are o acțiune unică, atunci trebuie să faceți o distribuție la acel animal specific. Dacă un animal are o acțiune care poate fi grupată cu alte animale, atunci puteți defini o metodă abstractă sau virtuală într-o clasă de bază și o puteți folosi. –  > Por Matt Jordan.
Nestor Ledon

Ceea ce căutați aici este abstractizarea. Codificați mai mult în funcție de interfețe și ar trebui să trebuiască să faceți mai puțin casting.

Exemplul de mai jos este în C#, dar conceptul rămâne același.

using System;
using System.Collections.Generic;
using System.Reflection;

namespace GenericsTest
{
class MainClass
{
    public static void Main (string[] args)
    {
        _HasFriends jerry = new Mouse();
        jerry.AddFriend("spike", new Dog());
        jerry.AddFriend("quacker", new Duck());

        jerry.CallFriend<_Animal>("spike").Speak();
        jerry.CallFriend<_Animal>("quacker").Speak();
    }
}

interface _HasFriends
{
    void AddFriend(string name, _Animal animal);

    T CallFriend<T>(string name) where T : _Animal;
}

interface _Animal
{
    void Speak();
}

abstract class AnimalBase : _Animal, _HasFriends
{
    private Dictionary<string, _Animal> friends = new Dictionary<string, _Animal>();


    public abstract void Speak();

    public void AddFriend(string name, _Animal animal)
    {
        friends.Add(name, animal);
    }   

    public T CallFriend<T>(string name) where T : _Animal
    {
        return (T) friends[name];
    }
}

class Mouse : AnimalBase
{
    public override void Speak() { Squeek(); }

    private void Squeek()
    {
        Console.WriteLine ("Squeek! Squeek!");
    }
}

class Dog : AnimalBase
{
    public override void Speak() { Bark(); }

    private void Bark()
    {
        Console.WriteLine ("Woof!");
    }
}

class Duck : AnimalBase
{
    public override void Speak() { Quack(); }

    private void Quack()
    {
        Console.WriteLine ("Quack! Quack!");
    }
}
}

Comentarii

  • Această întrebare are de-a face cu codificarea, nu cu conceptul. – user1043000
R.Moeller

Am făcut următoarele în lib kontraktor:

public class Actor<SELF extends Actor> {
    public SELF self() { return (SELF)_self; }
}

subclasare:

public class MyHttpAppSession extends Actor<MyHttpAppSession> {
   ...
}

cel puțin acest lucru funcționează în interiorul clasei curente și atunci când are o referință puternic tipizată. Moștenirea multiplă funcționează, dar devine foarte complicat atunci 🙂

user743489

Știu că acesta este un lucru complet diferit de cel întrebat. O altă modalitate de a rezolva acest lucru ar fi reflecția. Adică, acest lucru nu ia beneficiul de la Generics, dar îți permite să emulezi, într-un fel, comportamentul pe care vrei să îl realizezi (să faci un câine să latre, să faci o rață să cotcodăcească, etc.) fără să te ocupi de turnarea tipurilor:

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

abstract class AnimalExample {
    private Map<String,Class<?>> friends = new HashMap<String,Class<?>>();
    private Map<String,Object> theFriends = new HashMap<String,Object>();

    public void addFriend(String name, Object friend){
        friends.put(name,friend.getClass());
        theFriends.put(name, friend);
    }

    public void makeMyFriendSpeak(String name){
        try {
            friends.get(name).getMethod("speak").invoke(theFriends.get(name));
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    } 

    public abstract void speak ();
};

class Dog extends Animal {
    public void speak () {
        System.out.println("woof!");
    }
}

class Duck extends Animal {
    public void speak () {
        System.out.println("quack!");
    }
}

class Cat extends Animal {
    public void speak () {
        System.out.println("miauu!");
    }
}

public class AnimalExample {

    public static void main (String [] args) {

        Cat felix = new Cat ();
        felix.addFriend("Spike", new Dog());
        felix.addFriend("Donald", new Duck());
        felix.makeMyFriendSpeak("Spike");
        felix.makeMyFriendSpeak("Donald");

    }

}

gafadr

ce ziceți de

public class Animal {
    private Map<String,<T extends Animal>> friends = new HashMap<String,<T extends Animal>>();

    public <T extends Animal> void addFriend(String name, T animal){
        friends.put(name,animal);
    }

    public <T extends Animal> T callFriend(String name){
        return friends.get(name);
    }
}

FeralWhippet

Există o altă abordare, puteți restrânge tipul de returnare atunci când suprascrieți o metodă. În fiecare subclasă ar trebui să suprascrieți callFriend pentru a returna subclasa respectivă. Costul ar fi declarațiile multiple ale callFriend, dar ați putea izola părțile comune într-o metodă apelată intern. Acest lucru mi se pare mult mai simplu decât soluțiile menționate mai sus și nu are nevoie de un argument suplimentar pentru a determina tipul de returnare.

Comentarii

  • Nu sunt sigur la ce vă referiți prin „a restrânge tipul de returnare”. Din câte se pare, Java și majoritatea limbajelor tipizate nu supraîncarcă metodele sau funcțiile pe baza tipului de retur. De exemplu public int getValue(String name){} nu se poate distinge de public boolean getValue(String name){} din punctul de vedere al compilatorilor. Ar trebui fie să schimbați tipul parametrilor, fie să adăugați/eliminați parametri pentru ca supraîncărcarea să fie recunoscută. Poate că totuși nu v-am înțeles bine… –  > Por The One True Colter.
  • în java puteți suprascrie o metodă într-o subclasă și specifica un tip de returnare mai „îngust” (adică mai specific). Consultați stackoverflow.com/questions/14694852/…. –  > Por FeralWhippet.
Cassio Seffrin

Deoarece întrebarea se bazează pe date ipotetice, iată un exemplu bun care returnează un generic care extinde interfața Comparable.

public class MaximumTest {
    // find the max value using Comparable interface
    public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
        T max = x; // assume that x is initially the largest

        if (y.compareTo(max) > 0){
            max = y; // y is the large now
        }
        if (z.compareTo(max) > 0){
            max = z; // z is the large now
        }
        return max; // returns the maximum value
    }    


    //testing with an ordinary main method
    public static void main(String args[]) {
        System.out.printf("Maximum of %d, %d and %d is %d

", 3, 4, 5, maximum(3, 4, 5));
        System.out.printf("Maximum of %.1f, %.1f and %.1f is %.1f

", 6.6, 8.8, 7.7, maximum(6.6, 8.8, 7.7));
        System.out.printf("Maximum of %s, %s and %s is %s
", "strawberry", "apple", "orange",
                maximum("strawberry", "apple", "orange"));
    }
}