Khởi tạo đối tượng của tham số kiểu


88

Tôi có một lớp mẫu như sau:

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

Làm cách nào để tạo một phiên bản mới của T trong lớp của tôi?

Câu trả lời:


85

Sau khi xóa kiểu, tất cả những gì được biết Tlà nó là một số lớp con của Object. Bạn cần chỉ định một số nhà máy để tạo các phiên bản củaT .

Một cách tiếp cận có thể sử dụng 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();
  }

}

Cách sử dụng có thể trông như thế này:

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

Ngoài ra, bạn có thể cung cấp một Class<T>đối tượng, sau đó sử dụng phản xạ.

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

}

Gói nào Suppliernằm trong? `MyClass (Class <? Expand T> impl)` phải khai báo `ném NoSuchMethodException` để được biên dịch. Câu trả lời của bạn rất tiếc là không thân thiện với người mới bắt đầu Java.
purucat

@ user927387java.util.function.Supplier
erickson

Nhà cung cấp <T> yêu cầu Java 8, JFTR cho bất cứ nơi nào có giá trị.
Fran Marzoa

14

Một cách tiếp cận không phản chiếu khác là sử dụng mẫu Builder / Abstract Factory kết hợp.

Trong Java hiệu quả, Joshua Bloch xem xét chi tiết mẫu Builder và ủng hộ giao diện Builder chung:

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

Người xây dựng bê tông có thể triển khai giao diện này và các lớp bên ngoài có thể sử dụng trình xây dựng bê tông để định cấu hình Trình xây dựng theo yêu cầu. Trình tạo có thể được chuyển tới MyClass dưới dạng Builder<T>.

Sử dụng mẫu này, bạn có thể nhận các phiên bản mới T, ngay cả khi Tcó tham số hàm tạo hoặc yêu cầu cấu hình bổ sung. Tất nhiên, bạn sẽ cần một số cách để chuyển Builder vào MyClass. Nếu bạn không thể chuyển bất cứ thứ gì vào MyClass, thì Builder và Abstract Factory sẽ không hoạt động.


12

Điều này có thể nặng hơn những gì bạn đang tìm kiếm, nhưng nó cũng sẽ hoạt động. Lưu ý rằng nếu bạn thực hiện phương pháp này, sẽ có ý nghĩa hơn khi đưa nhà máy vào MyClass khi nó được xây dựng thay vì chuyển nó vào phương thức của bạn mỗi khi nó được gọi.

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

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

1
Cách tiếp cận tốt, không phản chiếu; phản chiếu không phải lúc nào cũng là một lựa chọn. myMethod sẽ có thể chấp nhận MyFactory <? mở rộng T>, phải không?
erickson

1
Lời gọi tốt - bạn sẽ muốn đặt một ký tự đại diện có giới hạn trên nhà máy để cho phép các đối tượng kiểu T và các lớp con của T được tạo trong myMethod ().
Dan Hodge


-3

Class classOfT

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

2
Lớp classOfT đó được khai báo ở đâu?
Fran Marzoa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.