Yöntem dönüş türünü nasıl genel hale getirebilirim?


588

Bu örneği düşünün (OOP kitaplarında tipik olan):

Bir Animalsınıfım var, her birinin Animalçok fazla arkadaşı olabilir.
Ve alt sınıflar gibi Dog, Duck, Mousevb gibi belirli davranış eklemek hangi bark(), quack()vb

İşte Animalsınıf:

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);
    }
}

Ve burada çok sayıda daktilo içeren bazı kod snippet'i:

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

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

Tipik yazımdan kurtulmak için dönüş türü için jenerik ilaçları kullanabilmemin herhangi bir yolu var mı?

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

İşte hiç kullanılmayan bir parametre olarak yönteme aktarılan dönüş türüne sahip bazı başlangıç ​​kodları.

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

Ek parametre kullanmadan çalışma zamanında dönüş türünü anlamanın bir yolu var mı instanceof? Ya da en azından sahte bir örnek yerine bir tür sınıf geçirerek.
Jeneriklerin derleme zamanı türü denetimi için olduğunu anlıyorum, ancak bunun için bir çözüm var mı?

Yanıtlar:


903

callFriendBu şekilde tanımlayabilirsiniz :

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

Sonra şöyle deyin:

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

Bu kodun herhangi bir derleyici uyarısı oluşturmama avantajı vardır. Tabii ki bu gerçekten sadece jenerik öncesi günlerden dökümün güncellenmiş bir versiyonudur ve ek güvenlik sağlamaz.


29
... ancak yine de callFriend () çağrısının parametreleri arasında derleme zamanı türü denetimi yok.
David Schmitt

2
Bu şimdiye kadarki en iyi cevap - ama addFriend'i aynı şekilde değiştirmelisin. Her iki yerde de bu sınıf değişmezine ihtiyacınız olduğu için hata yazmayı zorlaştırır.
Craig P. Motlin

@Jaider, tam olarak aynı değil ama bu işe yarayacak: // Animal Class public T CallFriend <T> (dize adı) burada T: Animal {arkadaşlarını T olarak geri döndürür; } // Calling Class jerry.CallFriend <Dog> ("başak"). Bark (); jerry.CallFriend <Ördek> ( "Quacker") Vak ().;
Nestor Ledon

124

Hayır. Derleyici hangi türün jerry.callFriend("spike")döneceğini bilemez . Ayrıca, uygulamanız herhangi bir ek tür güvenliği olmadan yöntemdeki oyuncuları gizler. Bunu düşün:

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

Bu özel durumda, soyut bir talk()yöntem oluşturmak ve alt sınıflarda uygun şekilde geçersiz kılmak size daha iyi hizmet edecektir:

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

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

10
Mmyers yöntemi işe yarayabilse de, bu yöntemin daha iyi OO programlaması olduğunu ve gelecekte size biraz sorun kazandıracağını düşünüyorum.
James McMahon

1
Aynı sonucu elde etmenin doğru yolu budur. Amacınız, çirkin tür denetimi ve dökümünü yapmak için açıkça kod yazmadan çalışma zamanında türetilmiş sınıfa özel davranış elde etmektir. @Laz tarafından önerilen yöntem işe yarıyor ancak tip güvenliğini pencereden dışarı atıyor. Bu yöntem daha az kod satırı gerektirir (çünkü yöntem uygulamaları geç bağlıdır ve yine de çalışma zamanında aranır), ancak yine de Animal'in her alt sınıfı için benzersiz davranışı kolayca tanımlamanıza izin verir.
dcow

Ancak asıl soru tip güvenliği hakkında soru sormuyor. Okuduğum şekilde, asker sadece dökümü yapmaktan kaçınmak için jeneriklerden yararlanmanın bir yolu olup olmadığını bilmek istiyor.
laz

2
@laz: evet, asıl soru - ortaya atıldığı gibi - tip güvenliği ile ilgili değildir. Bu, bunu uygulamak için güvenli bir yol olduğu gerçeğini değiştirmez ve sınıf döküm hatalarını ortadan kaldırır. Ayrıca bkz. Weblogs.asp.net/alex_papadimoulis/archive/2005/05/25/…
David Schmitt

3
Buna katılmıyorum, ancak Java ve tüm tasarım kararları / aksaklıklarıyla uğraşıyoruz. Bu soruyu, Java jeneriklerinde neyin mümkün olduğunu öğrenmeye çalışmak olarak görüyorum, yeniden tasarlanması gereken bir xyproblem ( meta.stackexchange.com/questions/66377/what-is-the-xy-problem ) olarak görmüyorum . Herhangi bir model veya yaklaşım gibi, sağladığım kodun uygun olduğu zamanlar ve tamamen farklı bir şeyin (bu cevapta önerdiğiniz gibi) gerekli olduğu zamanlar vardır.
laz

114

Bunu şu şekilde uygulayabilirsiniz:

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

(Evet, bu yasal koddur; bkz. Java Generics: Genel tür yalnızca dönüş türü olarak tanımlanmıştır .)

Dönüş türü arayandan çıkarılır. Ancak @SuppressWarningsek açıklamaya dikkat edin : bu size bu kodun güvenli olmadığını belirtir . Bunu kendiniz doğrulamanız gerekiyor veya ClassCastExceptionsçalışma zamanında alabilirsiniz .

Ne yazık ki, onu kullanma şekliniz (dönüş değerini geçici bir değişkene atamadan), derleyiciyi mutlu etmenin tek yolu onu şöyle çağırmaktır:

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

Bu dökümden biraz daha hoş olsa da , David Schmitt'in dediği gibi , muhtemelen Animalsınıfa soyut bir talk()yöntem vermek daha iyidir .


Yöntem zincirleme aslında bir niyet değildi. Ben bir Subtyped değişkeni değeri atama ve kullanma sakıncası yok. Çözüm için teşekkürler.
Sathish

Bu yöntem çağrı zincirleme yaparken mükemmel çalışır!
Hartmut P.

Bu sözdizimini gerçekten çok seviyorum. Bence C # jerry.CallFriend<Dog>(...daha iyi görünüyor düşünüyorum.
andho

JRE'nin kendi java.util.Collections.emptyList()işlevinin tam olarak bu şekilde uygulanması ilginçtir ve javadoc kendini tipik bir reklam olarak tanıtır.
Ti Strga

31

Bu soru, Etkili Java'daki 29. Maddeye çok benzer - "Türdeş olmayan heterojen kapları düşünün." Laz'ın cevabı Bloch'un çözümüne en yakın olanıdır. Ancak, hem koy hem de al güvenlik için Sınıf değişmezini kullanmalıdır. İmzalar:

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

Her iki yöntemde de parametrelerin aklı başında olup olmadığını kontrol etmelisiniz. Daha fazla bilgi için Etkili Java ve Sınıf javadoc bölümüne bakın .


17

Ayrıca, yöntemden belirli bir türdeki değeri bu şekilde döndürmesini isteyebilirsiniz

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

Diğer örnekler burada Oracle Java belgelerine


17

İşte daha basit sürüm:

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
}

Tamamen çalışma kodu:

    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();

        }
    }

1
Ne yapar Casting to T not needed in this case but it's a good practice to do. Demek istediğim, çalışma sırasında düzgün bir şekilde halledilirse "iyi uygulama" ne demektir?
Farid

Metot beyannamesi üzerindeki dönüş tipi bildirimi <T> yeterli olduğundan, açık dökümün (T) gerekli olmadığını söylemek istedim
webjockey

9

Bir sınıfı geçmenin iyi olacağını söylediğin gibi şunu yazabilirsin:

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

Ve sonra böyle kullanın:

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

Mükemmel değil, ama bu Java jenerikleri ile elde ettiğiniz kadar. Süper Tip Jetonları kullanarak Typesafe Heterojen Konteynerleri (THC) uygulamanın bir yolu vardır , ancak yine kendi sorunları vardır.


Üzgünüm ama bu laz'ın cevabı aynı, bu yüzden ya onu kopyalıyorsunuz ya da o sizi kopyalıyor.
James McMahon

Bu tür geçmek için temiz bir yol. Ama yine de Schmitt'in söylediği gibi güvenli değil. Hala farklı bir sınıftan geçebilirdim ve daktilo bombası patlayacak. mmyers Dönüş Türünü ayarlamak için 2. cevap daha iyi görünüyor
Sathish

4
Nemo, eğer gönderme zamanını kontrol ederseniz onları hemen hemen aynı anda gönderdiğimizi göreceksiniz. Ayrıca, tam olarak aynı değil, sadece iki satır.
Fabian Steeg

@Fabian Benzer bir cevap yayınladım, ancak Bloch'un slaytları ile Etkili Java'da yayınlananlar arasında önemli bir fark var. TypeRef <T> yerine Class <T> kullanır. Ama bu hala harika bir cevap.
Craig P. Motlin

8

Süper Tür Belirteçleri ile aynı fikre dayanarak, bir dize yerine kullanmak için yazılı bir kimlik oluşturabilirsiniz:

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];
  }
}

Ama şimdi her dize için yeni kimlik nesneleri oluşturmak ve onlara tutun (veya doğru tip bilgileri ile onları yeniden) gerekir, çünkü bu amacı yenebilir düşünüyorum.

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());

Ama artık sınıfı, atma olmadan başlangıçta istediğiniz şekilde kullanabilirsiniz.

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

Bu sadece id içindeki type parametresini gizliyor olsa da, daha sonra isterseniz tanımlayıcıdan türü alabileceğiniz anlamına gelir.

Bir kimliğin iki özdeş örneğini karşılaştırabilmek istiyorsanız, TypedID'in karşılaştırma ve karma yöntemlerini de uygulamanız gerekir.


8

Msgstr "instanceof kullanarak fazladan parametre olmadan çalışma zamanında dönüş türünü bulmanın bir yolu var mı?"

Alternatif bir çözüm olarak Ziyaretçi kalıbını bu şekilde kullanabilirsiniz. Hayvan soyut yapmak ve onu uygulanabilir olun

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);
  }
}

Ziyaret edilebilir, sadece bir Hayvan uygulamasının bir ziyaretçiyi kabul etmeye istekli olduğu anlamına gelir:

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

Bir ziyaretçi uygulaması, bir hayvanın tüm alt sınıflarını ziyaret edebilir:

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

Örneğin, bir Köpek uygulaması şöyle görünecektir:

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

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

Buradaki hile, Köpek'in ne tür olduğunu bildiği gibi, ziyaretçinin v ilgili aşırı yüklenmiş ziyaret yöntemini bir parametre olarak "bu" ileterek tetikleyebilmesidir. Diğer alt sınıflar accept () yöntemini tamamen aynı şekilde uygular.

Alt sınıfa özgü yöntemleri çağırmak isteyen sınıfın Ziyaretçi arabirimini şu şekilde uygulaması gerekir:

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(); }
}

Sizin için pazarlık yaptığınızdan çok daha fazla arayüz ve yöntem olduğunu biliyorum, ancak kontrolleri ve sıfır tipi dökümleri tam olarak sıfır olan her belirli alt tür üzerinde işlemek için standart bir yol. Ve hepsi standart bir dil agnostik tarzında yapılır, bu yüzden sadece Java için değil, herhangi bir OO dili de aynı şekilde çalışmalıdır.


6

Mümkün değil. Haritanın sadece bir String anahtarı verildiğinde hangi Hayvan alt sınıfını alacağını nasıl bilebilir?

Bunun mümkün olabilmesinin tek yolu, her Hayvan yalnızca bir tür arkadaş kabul ettiğinde (o zaman Animal sınıfının bir parametresi olabilir) veya callFriend () yönteminin bir type parametresi varsa. Ama gerçekten miras noktasını kaçırmışsınız gibi görünüyor: sadece üst sınıf yöntemlerini kullanırken sadece alt sınıflara eşit davranabilirsiniz.


5

Konsept kanıtı, destek sınıfları ve Super Type Token'ların çalışma zamanında sınıflarınız tarafından nasıl alınabileceğini gösteren bir test sınıfı içeren bir makale yazdım. Özetle, arayan tarafından geçirilen gerçek jenerik parametrelere bağlı olarak alternatif uygulamalara delege etmenizi sağlar. Misal:

  • TimeSeries<Double> kullanan özel bir iç sınıfa delege double[]
  • TimeSeries<OHLC> kullanan özel bir iç sınıfa delege ArrayList<OHLC>

Bakınız: Genel parametreleri almak için TypeTokens kullanma

Teşekkürler

Richard Gomes - Blog


Gerçekten, görüşünüzü paylaştığınız için teşekkür ederiz, makaleniz gerçekten her şeyi açıklıyor!
Yann-Gaël Guéhéneuc

3

Burada çok sayıda harika yanıt var, ancak bu, tek bir öğeye göre hareket etmenin, kullanıcının ayarlarına bağlı olarak farklı uygulama durumlarına gitmesine neden olabileceği bir Appium testi için aldığım yaklaşımdır. OP örneğinin kurallarına uymasa da, umarım birine yardımcı olur.

public <T extends MobilePage> T tapSignInButton(Class<T> type) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //signInButton.click();
    return type.getConstructor(AppiumDriver.class).newInstance(appiumDriver);
}
  • MobilePage, türün genişlettiği süper sınıftır ve çocuklarından herhangi birini kullanabileceğiniz anlamına gelir (duh)
  • type.getConstructor (Param.class, vb.) türün yapıcısı ile etkileşime girmenizi sağlar. Bu kurucu beklenen tüm sınıflar arasında aynı olmalıdır.
  • newInstance, yeni nesneler yapıcısına iletmek istediğiniz bildirilen bir değişkeni alır

Hataları atmak istemiyorsanız, bunları şöyle yakalayabilirsiniz:

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;
}

Anladığım kadarıyla, Generics'i kullanmanın en iyi ve en zarif yolu budur.
cbaldan

2

Gerçekten değil, çünkü dediğin gibi, derleyici sadece callFriend'in () bir Köpek veya Ördek yerine bir Hayvan döndürdüğünü biliyor.

Animal'e alt sınıfları tarafından havlama veya quack olarak uygulanacak soyut bir makeNoise () yöntemi ekleyemez misiniz?


1
hayvanların, çıkartılabilecek ortak bir eylemde bile bulunmayan birden fazla yöntemi varsa ne olur? Ben bir örnek değil, Tip geçen ile iyi im farklı eylemler ile alt sınıflar arasındaki iletişim için buna ihtiyacım var.
Sathish

2
Gerçekten kendi sorunuzu cevapladınız - bir hayvanın benzersiz bir eylemi varsa, o belirli hayvana atmanız gerekir. Bir hayvanın diğer hayvanlarla gruplandırılabilecek bir eylemi varsa, bir temel sınıfta soyut veya sanal bir yöntem tanımlayabilir ve bunu kullanabilirsiniz.
Matt Jordan

2

Burada aradığınız şey soyutlama. Arayüzlere karşı daha fazla kodlama yapın ve daha az döküm yapmanız gerekir.

Aşağıdaki örnek C # 'dadır, ancak kavram aynı kalır.

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!");
    }
}
}

Bu soru kavram değil kodlama ile ilgilidir.

2

Lib kontraktorumda aşağıdakileri yaptım:

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

sınıflara:

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

en azından bu mevcut sınıf içinde ve güçlü bir tür referansı olduğunda çalışır. Birden fazla miras işe yarıyor, ama o zaman gerçekten zor oluyor :)


1

Bunun tamamen sorduğu tamamen farklı bir şey olduğunu biliyorum. Bunu çözmenin başka bir yolu da düşünme olacaktır. Demek istediğim, bu Generics'ten faydalanmıyor, ancak bir şekilde, yapmak istediğiniz davranışı (bir köpek kabuğu yapmak, ördek quack yapmak, vb.) Tip dökümüne dikkat etmeden taklit etmenizi sağlar:

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");

    }

}

1

ne dersin

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);
}

}


0

Başka bir yaklaşım var, bir yöntemi geçersiz kıldığınızda dönüş türünü daraltabilirsiniz. Her alt sınıfta, o alt sınıfı geri döndürmek için callFriend'i geçersiz kılmanız gerekir. Maliyet, callFriend'in çoklu bildirimleri olacaktır, ancak ortak bölümleri dahili olarak adlandırılan bir yöntemle izole edebilirsiniz. Bu benim için yukarıda belirtilen çözümlerden çok daha basit görünüyor ve dönüş türünü belirlemek için ekstra bir argümana gerek yok.


"Dönüş tipini daralt" derken ne demek istediğinizden emin değilim. Afaik, Java ve çoğu yazılan diller, dönüş türüne göre yöntem veya işlevleri aşırı yüklemez. Örneğin derleyiciler açısından public int getValue(String name){}ayırt edilemez public boolean getValue(String name){}. Aşırı yüklenmenin tanınması için parametre türünü değiştirmeniz veya parametre eklemeniz / kaldırmanız gerekir. Belki de seni sadece yanlış anlıyorum ...
The One True Colter

java'da bir alt sınıftaki bir yöntemi geçersiz kılabilir ve daha "dar" (yani daha spesifik) bir dönüş türü belirtebilirsiniz. Bkz. Stackoverflow.com/questions/14694852/… .
FeralWhippet

-3
public <X,Y> X nextRow(Y cursor) {
    return (X) getRow(cursor);
}

private <T> Person getRow(T cursor) {
    Cursor c = (Cursor) cursor;
    Person s = null;
    if (!c.moveToNext()) {
        c.close();
    } else {
        String id = c.getString(c.getColumnIndex("id"));
        String name = c.getString(c.getColumnIndex("name"));
        s = new Person();
        s.setId(id);
        s.setName(name);
    }
    return s;
}

Herhangi bir türü iade edebilir ve doğrudan gibi alabilirsiniz. Tahmin etmeye gerek yok.

Person p = nextRow(cursor); // cursor is real database cursor.

Gerçek imleçler yerine başka tür kayıtları özelleştirmek istiyorsanız bu en iyisidir.


2
"Tahmin etmeye gerek yok" diyorsunuz, ancak açıkça ilgili (Cursor) cursorörnekleme var : örneğin.
Sami Laine

Bu jeneriklerin tamamen uygunsuz kullanımıdır. Bu kodun cursora olması gerekir Cursorve her zaman bir Person(veya null) döndürür . Jenerik kullanımı bu kısıtlamaları kontrol etmeden kodu güvenli hale getirmez.
Andy Turner
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.