Parametre türü örnekleme nesnesi


90

Aşağıdaki gibi bir şablon sınıfım var:

class MyClass<T>
{
    T field;
    public void myMethod()
    {
       field = new T(); // gives compiler error
    }
}

Sınıfımda yeni bir T örneğini nasıl oluşturabilirim?

Yanıtlar:


86

Tür silme işleminden sonra, bilinen Ttek şey onun bazı alt sınıfı olduğudur Object. Örneklerini oluşturmak için bazı fabrika belirtmeniz gerekir T.

Bir yaklaşım a kullanabilir Supplier<T>:

class MyClass<T> {

  private final Supplier<? extends T> ctor;

  private T field;

  MyClass(Supplier<? extends T> ctor) {
    this.ctor = Objects.requireNonNull(ctor);
  }

  public void myMethod() {
    field = ctor.get();
  }

}

Kullanım şöyle görünebilir:

MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);

Alternatif olarak, bir Class<T>nesne sağlayabilir ve ardından yansımayı kullanabilirsiniz.

class MyClass<T> {

  private final Constructor<? extends T> ctor;

  private T field;

  MyClass(Class<? extends T> impl) throws NoSuchMethodException {
    this.ctor = impl.getConstructor();
  }

  public void myMethod() throws Exception {
    field = ctor.newInstance();
  }

}

Hangi pakette Supplierbulunuyor? "MyClass (Class <? Extends T> impl)", derlenmek için "NoSuchMethodException" atar bildirmelidir. Cevabınız ne yazık ki Java acemi için uygun değil.
purucat

@ user927387java.util.function.Supplier
erickson

Tedarikçi <T>, değerli olan her yerde Java 8, JFTR gerektirir.
Fran Marzoa

14

Yansıtıcı olmayan başka bir yaklaşım, hibrit bir Oluşturucu / Soyut Fabrika modeli kullanmaktır.

Etkili Java'da Joshua Bloch, Builder modelini ayrıntılı olarak ele alır ve genel bir Builder arayüzünü savunur:

public interface Builder<T> {
  public T build();
}

Beton inşaatçılar bu arabirimi uygulayabilir ve dış sınıflar, Oluşturucu'yu gerektiği gibi yapılandırmak için beton oluşturucuyu kullanabilir. Oluşturucu, MyClass'a bir Builder<T>.

Bu kalıbı kullanarak , yapıcı parametreleri olsa veya ek yapılandırma gerektirse Tbile yeni örneklerini alabilirsiniz T. Elbette, Builder'ı MyClass'a geçirmek için bir yola ihtiyacınız olacak. MyClass'a hiçbir şey aktaramazsanız, Builder ve Abstract Factory devre dışıdır.


12

Bu, aradığınızdan daha ağır olabilir, ancak aynı zamanda işe yarayacaktır. Bu yaklaşımı kullanırsanız, fabrikayı her çağrıldığında yönteminize geçirmek yerine, inşa edildiğinde MyClass'a enjekte etmenin daha mantıklı olacağını unutmayın.

interface MyFactory<T> 
{
    T newObject();
}

class MyClass<T> 
{
    T field;
    public void myMethod(MyFactory<T> factory)
    {
       field = factory.newObject()
    }
}

1
İyi, yansıtıcı olmayan yaklaşım; yansıtma her zaman bir seçenek değildir. myMethod bir MyFactory <? T> uzatır, değil mi?
erickson

1
İyi çağrı - myMethod () içinde T türü nesnelerin ve T alt sınıflarının oluşturulmasına izin vermek için fabrikaya sınırlı bir joker karakter koymak isteyeceksiniz.
Dan Hodge


0

Bir seçenek, onu Object ile yayınlamak olabilir.

{field = (T) new Object();}

alan başlangıçta Object türü olacak, ancak daha sonra T türüne geçecektir. Bu çirkin bir durumdur, çünkü nesne başlatmalarında hedefin sıfıra düşürülmesi gerekir. Ama bunun işe yarayacağını düşünüyorum.


-2

Sınıf classOfT

        try {
            t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
        } catch (Exception e) {
            e.printStackTrace();
        }

2
Bu classOfT sınıfı nerede bildirilir?
Fran Marzoa
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.