ฉันจะรับคลาสอินสแตนซ์ประเภท T ทั่วไปได้อย่างไร


700

ฉันได้เรียน Foo<T>generics, ในวิธีการของFooผมต้องการที่จะได้รับเช่นชั้นชนิดแต่ฉันก็ไม่สามารถเรียกTT.class

เป็นวิธีที่ต้องการเพื่อรับรอบโดยใช้T.classอะไร


2
ลองคำตอบในคำถามนี้ฉันคิดว่ามันคล้ายกัน stackoverflow.com/questions/1942644/…
Emil

3
เป็นไปได้ที่ซ้ำกันของGet ประเภททั่วไปของคลาสที่รันไทม์
7hi4g0

1
เป็นไปได้ซ้ำของInstantiating คลาสทั่วไปใน Java
matiasg

1
import com.fasterxml.jackson.core.type.TypeReference; new TypeReference<T>(){}
Bogdan Shulga

คำตอบ:


569

คำตอบสั้น ๆ คือไม่มีวิธีค้นหาชนิด runtime ของพารามิเตอร์ประเภททั่วไปใน Java ฉันขอแนะนำให้อ่านบทเกี่ยวกับการลบประเภทในJava Tutorialสำหรับรายละเอียดเพิ่มเติม

วิธีแก้ปัญหายอดนิยมสำหรับสิ่งนี้คือการส่งผ่านClassพารามิเตอร์ประเภทลงในตัวสร้างของประเภททั่วไปเช่น

class Foo<T> {
    final Class<T> typeParameterClass;

    public Foo(Class<T> typeParameterClass) {
        this.typeParameterClass = typeParameterClass;
    }

    public void bar() {
        // you can access the typeParameterClass here and do whatever you like
    }
}

73
คำตอบนี้ให้วิธีแก้ปัญหาที่ถูกต้อง แต่ไม่ถูกต้องที่จะบอกว่าไม่มีทางที่จะหาประเภททั่วไปที่รันไทม์ ปรากฎว่าการลบประเภทมีความซับซ้อนมากกว่าการลบแบบครอบคลุม คำตอบของฉันแสดงให้คุณเห็นว่าจะได้รับประเภทชั้นเรียนทั่วไปได้อย่างไร
Ben Thurley

3
@BenThurley เคล็ดลับเรียบร้อย แต่เท่าที่ฉันสามารถเห็นมันใช้งานได้เฉพาะถ้ามี supertype ทั่วไปเพื่อให้ใช้ ในตัวอย่างของฉันคุณไม่สามารถดึงประเภทของ T ใน Foo <T>
Zsolt Török

@webjockey ไม่คุณไม่ควรทำ การกำหนดtypeParameterClassโดยไม่มีการกำหนดค่าเริ่มต้นในตัวสร้างนั้นดีมาก ไม่จำเป็นต้องตั้งค่าเป็นครั้งที่สอง
Adowrath

นี่เป็นคำตอบแรกที่นึกถึง แต่บางครั้งไม่ใช่คุณที่จะสร้าง / เริ่มต้นวัตถุ ดังนั้นคุณจะไม่สามารถใช้ตัวสร้าง ตัวอย่างเช่นขณะดึงข้อมูลเอนทิตี JPA จากฐานข้อมูล
Paramvir Singh Karwal

234

ฉันกำลังมองหาวิธีที่จะทำสิ่งนี้ด้วยตัวเองโดยไม่เพิ่มการพึ่งพาพิเศษให้กับ classpath หลังจากการสอบสวนฉันพบว่ามันเป็นไปได้ตราบใดที่คุณมีซูเปอร์ไทป์ทั่วไป นี่เป็นสิ่งที่โอเคสำหรับฉันเนื่องจากฉันทำงานกับเลเยอร์DAOกับเลเยอร์ supertype ทั่วไป ถ้าสิ่งนี้เหมาะกับสถานการณ์ของคุณก็เป็นวิธีที่ประณีตที่สุด IMHO

ยาชื่อสามัญส่วนใหญ่ที่ใช้ในกรณีที่ฉันเจอมีซูเปอร์ไทป์ทั่วไปเช่นList<T>สำหรับArrayList<T>หรือGenericDAO<T>เพื่อDAO<T>ฯลฯ

โซลูชัน Pure Java

บทความการเข้าถึงประเภททั่วไปที่รันไทม์ใน Javaอธิบายวิธีที่คุณสามารถทำได้โดยใช้จาวาบริสุทธิ์

@SuppressWarnings("unchecked")
public GenericJpaDao() {
  this.entityBeanType = ((Class) ((ParameterizedType) getClass()
      .getGenericSuperclass()).getActualTypeArguments()[0]);
}

สารละลายสปริง

โครงการของฉันใช้สปริงซึ่งดียิ่งขึ้นเนื่องจากสปริงมีวิธีการใช้งานที่สะดวกในการค้นหาประเภท นี่เป็นวิธีที่ดีที่สุดสำหรับฉันเพราะดูเรียบร้อย ฉันเดาว่าถ้าคุณไม่ได้ใช้ Spring คุณสามารถเขียนวิธีอรรถประโยชน์ของคุณเอง

import org.springframework.core.GenericTypeResolver;

public abstract class AbstractHibernateDao<T extends DomainObject> implements DataAccessObject<T>
{

    @Autowired
    private SessionFactory sessionFactory;

    private final Class<T> genericType;

    private final String RECORD_COUNT_HQL;
    private final String FIND_ALL_HQL;

    @SuppressWarnings("unchecked")
    public AbstractHibernateDao()
    {
        this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractHibernateDao.class);
        this.RECORD_COUNT_HQL = "select count(*) from " + this.genericType.getName();
        this.FIND_ALL_HQL = "from " + this.genericType.getName() + " t ";
    }

1
กรุณาอธิบายความหมายของresolveTypeArgumentข้อโต้แย้ง
gstackoverflow

getClass () เป็นวิธีการของ java.lang.Object ซึ่งจะส่งคืนคลาสของวัตถุเฉพาะตอนรันไทม์ซึ่งเป็นวัตถุที่คุณต้องการแก้ไขประเภท AbstractHibernateDao.class เป็นเพียงชื่อของคลาสพื้นฐานหรือ superclass ของลำดับชั้นคลาสชนิดทั่วไป คำสั่งการนำเข้านั้นรวมอยู่ด้วยดังนั้นคุณควรจะสามารถค้นหาเอกสารและตรวจสอบตัวเองได้อย่างง่ายดาย นี่คือหน้าdocs.spring.io/spring/docs/current/javadoc-api/org/…
Ben Thurley

สปริงโซลูชั่นคือเวอร์ชัน 4.3.6ขึ้นไป มันใช้ไม่ได้กับฤดูใบไม้ผลิ 4.3.6
Erlan

1
ลิงก์ใน "โซลูชัน Java บริสุทธิ์" ไม่สามารถใช้งานได้ตอนนี้เป็นblog.xebia.com/acessing-generic-types-at-runtime-in-java
Nick Breen

1
@ AlikElzin-kilaka มันได้รับการเริ่มต้นในตัวสร้างโดยใช้ Spring class GenericTypeResolver
Ben Thurley

103

อย่างไรก็ตามมีช่องโหว่เล็ก ๆ น้อย ๆ : ถ้าคุณกำหนดFooคลาสของคุณเป็นนามธรรม นั่นหมายความว่าคุณต้องยกระดับชั้นเรียนเป็น:

Foo<MyType> myFoo = new Foo<MyType>(){};

(สังเกตเครื่องหมายวงเล็บปีกกาคู่ท้าย)

ตอนนี้คุณสามารถดึงข้อมูลชนิดของTat runtime:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];

อย่างไรก็ตามโปรดทราบว่าmySuperclassจะต้องเป็น superclass ของการกำหนดคลาสจริงกำหนดประเภทสุดท้ายสำหรับTของการกำหนดชั้นเรียนจริงการกำหนดประเภทสุดท้ายสำหรับ

นอกจากนี้ยังไม่หรูหรามาก แต่คุณต้องตัดสินใจว่าคุณต้องการnew Foo<MyType>(){}หรือnew Foo<MyType>(MyType.class);ในรหัสของคุณ


ตัวอย่างเช่น:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.NoSuchElementException;

/**
 * Captures and silently ignores stack exceptions upon popping.
 */
public abstract class SilentStack<E> extends ArrayDeque<E> {
  public E pop() {
    try {
      return super.pop();
    }
    catch( NoSuchElementException nsee ) {
      return create();
    }
  }

  public E create() {
    try {
      Type sooper = getClass().getGenericSuperclass();
      Type t = ((ParameterizedType)sooper).getActualTypeArguments()[ 0 ];

      return (E)(Class.forName( t.toString() ).newInstance());
    }
    catch( Exception e ) {
      return null;
    }
  }
}

แล้ว:

public class Main {
    // Note the braces...
    private Deque<String> stack = new SilentStack<String>(){};

    public static void main( String args[] ) {
      // Returns a new instance of String.
      String s = stack.pop();
      System.out.printf( "s = '%s'\n", s );
    }
}

5
นี่คือคำตอบที่ดีที่สุดได้อย่างง่ายดายที่นี่! นอกจากนี้สำหรับสิ่งที่คุ้มค่านี่เป็นกลยุทธ์ที่ Google Guice ใช้สำหรับการเรียนที่มีผลผูกพันTypeLiteral
ATG

14
โปรดทราบว่าทุกครั้งที่ใช้วิธีการสร้างวัตถุนี้คลาสนิรนามใหม่จะถูกสร้างขึ้น อีกสองวัตถุaและbสร้างด้วยวิธีนี้จะขยายคลาสเดียวกัน แต่ไม่มีคลาสอินสแตนซ์ที่เหมือนกัน a.getClass() != b.getClass()
Martin Serrano

3
มีสถานการณ์หนึ่งสถานการณ์ที่สิ่งนี้ไม่ทำงาน ถ้า Foo ควรใช้อินเทอร์เฟซเช่น Serializable กว่าคลาสนิรนามจะไม่เป็น Serializable เว้นแต่ว่าอินสแตนซ์ของคลาสนั้น ฉันพยายามที่จะแก้ไขมันด้วยการสร้างคลาสโรงงานที่ต่อเนื่องกันได้ซึ่งสร้างคลาสนิรนามที่ได้มาจาก Foo แต่ด้วยเหตุผลบางอย่าง getActualTypeArguments ส่งคืนประเภททั่วไปแทนคลาสจริง ตัวอย่างเช่น: (FooFactory ใหม่ <MyType> ()) createFoo ()
Lior Chaga

38

วิธีการมาตรฐาน / วิธีแก้ปัญหา / การแก้ปัญหาคือการเพิ่มclassวัตถุไปยังตัวสร้างเช่น:

 public class Foo<T> {

    private Class<T> type;
    public Foo(Class<T> type) {
      this.type = type;
    }

    public Class<T> getType() {
      return type;
    }

    public T newInstance() {
      return type.newInstance();
    }
 }

1
แต่ดูเหมือน @ ไม่สามารถใช้งานได้จริงในทางใดทางหนึ่งที่จะหลีกเลี่ยง?
Alfred Huang

@AlfredHuang วิธีแก้ไขคือสร้าง bean สำหรับคลาสที่ทำสิ่งนี้และไม่พึ่งพาการลงทะเบียนอัตโนมัติ
Calebj

20

ลองนึกภาพคุณมีนามธรรม superclass ที่เป็นทั่วไป:

public abstract class Foo<? extends T> {}

แล้วคุณมีคลาสที่สองที่ขยาย Foo ด้วยแถบทั่วไปที่ขยาย T:

public class Second extends Foo<Bar> {}

คุณสามารถรับคลาสBar.classในคลาสFoo ได้โดยเลือกType(จากคำตอบ bert bruynooghe) และอนุมานโดยใช้Classอินสแตนซ์:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
//Parse it as String
String className = tType.toString().split(" ")[1];
Class clazz = Class.forName(className);

คุณต้องทราบว่าการดำเนินการนี้ไม่เหมาะดังนั้นจึงควรเก็บค่าที่คำนวณไว้เพื่อหลีกเลี่ยงการคำนวณหลายอย่างในที่นี้ หนึ่งในการใช้งานทั่วไปคือการใช้ DAO ทั่วไป

การใช้งานขั้นสุดท้าย:

public abstract class Foo<T> {

    private Class<T> inferedClass;

    public Class<T> getGenericClass(){
        if(inferedClass == null){
            Type mySuperclass = getClass().getGenericSuperclass();
            Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
            String className = tType.toString().split(" ")[1];
            inferedClass = Class.forName(className);
        }
        return inferedClass;
    }
}

ค่าที่ส่งคืนคือ Bar.class เมื่อเรียกใช้จากคลาส Foo ในฟังก์ชันอื่นหรือจากคลาสบาร์


1
toString().split(" ")[1]นั่นคือปัญหาให้หลีกเลี่ยง"class "
IgniteCoders

16

นี่คือวิธีการแก้ปัญหาการทำงาน:

@SuppressWarnings("unchecked")
private Class<T> getGenericTypeClass() {
    try {
        String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
        Class<?> clazz = Class.forName(className);
        return (Class<T>) clazz;
    } catch (Exception e) {
        throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
    }
} 

หมายเหตุ: สามารถใช้เป็นซูเปอร์คลาสเท่านั้น

  1. จะต้องมีการขยายด้วยคลาสพิมพ์ ( Child extends Generic<Integer>)

หรือ

  1. จะต้องมีการสร้างเป็นการใช้งานที่ไม่ระบุชื่อ ( new Generic<Integer>() {};)

3
getTypeName เรียก toString ดังนั้นสามารถถูกแทนที่ด้วย. getActualTypeArguments () [0] .toString ();
Yaroslav Kovbas


9

เส้นทางที่ดีกว่าคลาสอื่น ๆ ที่แนะนำคือการส่งผ่านวัตถุที่สามารถทำสิ่งที่คุณจะทำกับคลาสเช่นสร้างอินสแตนซ์ใหม่

interface Factory<T> {
  T apply();
}

<T> void List<T> make10(Factory<T> factory) {
  List<T> result = new ArrayList<T>();
  for (int a = 0; a < 10; a++)
    result.add(factory.apply());
  return result;
}

class FooFactory<T> implements Factory<Foo<T>> {
  public Foo<T> apply() {
    return new Foo<T>();
  }
}

List<Foo<Integer>> foos = make10(new FooFactory<Integer>());

@ Ricky Clarkson: ฉันไม่เห็นว่าโรงงานนี้ควรส่งคืนค่าพารามิเตอร์ คุณช่วยอธิบายได้ไหมว่าคุณจะได้ประโยชน์จาก Foo <T> ได้อย่างไร? สำหรับฉันแล้วนี่เป็นเพียงการให้ฟูที่ไร้คู่แข่งเท่านั้น T ใน make10 ไม่ใช่เพียงแค่ Foo ที่นี่ใช่ไหม
ib84

@ ib84 ฉันแก้ไขรหัสแล้ว ฉันดูเหมือนจะพลาดว่า Foo นั้นเป็นพารามิเตอร์เมื่อฉันเขียนคำตอบในตอนแรก
Ricky Clarkson

9

ฉันมีปัญหานี้ในระดับทั่วไปที่เป็นนามธรรม ในกรณีนี้การแก้ปัญหานั้นง่ายกว่า:

abstract class Foo<T> {
    abstract Class<T> getTClass();
    //...
}

และต่อมาในชั้นเรียนที่ได้รับ:

class Bar extends Foo<Whatever> {
    @Override
    Class<T> getTClass() {
        return Whatever.class;
    }
}

ใช่มันเป็น แต่ฉันต้องการที่จะออกขั้นต่ำมากที่ต้องทำในขณะที่ขยายชั้นนี้ ตรวจสอบคำตอบของ droidpl
Paramvir Singh Karwal

5

ฉันมีวิธีแก้ปัญหา (น่าเกลียด แต่มีประสิทธิภาพ) สำหรับปัญหานี้ซึ่งฉันใช้เมื่อเร็ว ๆ นี้:

import java.lang.reflect.TypeVariable;


public static <T> Class<T> getGenericClass()
{
    __<T> ins = new __<T>();
    TypeVariable<?>[] cls = ins.getClass().getTypeParameters(); 

    return (Class<T>)cls[0].getClass();
}

private final class __<T> // generic helper class which does only provide type information
{
    private __()
    {
    }
}

5

มันเป็นไปได้:

class Foo<T> {
  Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}

คุณต้องใช้สองฟังก์ชันจากhibernate-generic-dao / blob / master / dao / src / main / java / com / googlecode / genericdao / dao / DAOUtil.javaจำศีล-genericdao

สำหรับคำอธิบายเพิ่มเติมโปรดดูที่สะท้อนให้เห็นถึงข้อมูลทั่วไป


3

ฉันพบวิธีทั่วไปและเรียบง่ายในการทำเช่นนั้น ในชั้นเรียนของฉันฉันสร้างวิธีที่ส่งกลับประเภททั่วไปตามตำแหน่งในนิยามของชั้นเรียน สมมติว่านิยามคลาสเป็นแบบนี้:

public class MyClass<A, B, C> {

}

ตอนนี้เรามาสร้างคุณลักษณะบางอย่างเพื่อคงประเภทไว้:

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;

// Getters and setters (not necessary if you are going to use them internally)

    } 

จากนั้นคุณสามารถสร้างวิธีการทั่วไปที่ส่งกลับชนิดตามดัชนีของคำจำกัดความทั่วไป:

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {
        // To make it use generics without supplying the class type
        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }

ในที่สุดในนวกรรมิกเพียงเรียกวิธีการและส่งดัชนีสำหรับแต่ละประเภท รหัสที่สมบูรณ์ควรมีลักษณะดังนี้:

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;


    public MyClass() {
      this.aType = (Class<A>) getGenericClassType(0);
      this.bType = (Class<B>) getGenericClassType(1);
      this.cType = (Class<C>) getGenericClassType(2);
    }

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {

        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }
}

2

ตามที่อธิบายไว้ในคำตอบอื่น ๆ ในการใช้ParameterizedTypeวิธีการนี้คุณจำเป็นต้องขยายชั้นเรียน แต่ดูเหมือนว่าจะมีงานพิเศษเพื่อสร้างชั้นเรียนใหม่ที่ขยายขอบเขต ...

ดังนั้นการทำให้คลาสเป็นนามธรรมมันบังคับให้คุณขยายออกไปดังนั้นจึงเป็นไปตามข้อกำหนดของคลาสย่อย (ใช้ @Getter ของ lombok)

@Getter
public abstract class ConfigurationDefinition<T> {

    private Class<T> type;
    ...

    public ConfigurationDefinition(...) {
        this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        ...
    }
}

ตอนนี้เพื่อขยายโดยไม่ต้องกำหนดคลาสใหม่ (หมายเหตุ {} ที่ส่วนท้าย ... ขยายออกไป แต่อย่าเขียนทับอะไรเลยยกเว้นว่าคุณต้องการ)

private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){};
private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){};
...
Class stringType = myConfigA.getType();
Class fileType = myConfigB.getType();

2

ฉันสมมติว่าเนื่องจากคุณมีคลาสทั่วไปคุณจะมีตัวแปรดังนี้:

private T t;

(ตัวแปรนี้จำเป็นต้องใช้ค่าที่ตัวสร้าง)

ในกรณีนั้นคุณสามารถสร้างวิธีการต่อไปนี้:

Class<T> getClassOfInstance()
{
    return (Class<T>) t.getClass();
}

หวังว่ามันจะช่วย!


1
   public <T> T yourMethodSignature(Class<T> type) {

        // get some object and check the type match the given type
        Object result = ...            

        if (type.isAssignableFrom(result.getClass())) {
            return (T)result;
        } else {
            // handle the error
        }
   }

1

หากคุณกำลังขยายหรือใช้คลาส / อินเทอร์เฟซใด ๆ ที่ใช้ชื่อสามัญคุณอาจได้รับประเภททั่วไปของคลาสแม่ / อินเตอร์เฟสโดยไม่ต้องแก้ไขคลาส / อินเตอร์เฟสใด ๆ ที่มีอยู่เลย

อาจมีความเป็นไปได้สามอย่าง

กรณีที่ 1 เมื่อคลาสของคุณขยายคลาสที่ใช้ Generics

public class TestGenerics {
    public static void main(String[] args) {
        Type type = TestMySuperGenericType.class.getGenericSuperclass();
        Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
        for(Type gType : gTypes){
            System.out.println("Generic type:"+gType.toString());
        }
    }
}

class GenericClass<T> {
    public void print(T obj){};
}

class TestMySuperGenericType extends GenericClass<Integer> {
}

กรณีที่ 2 เมื่อคลาสของคุณกำลังใช้อินเทอร์เฟซที่ใช้ Generics

public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

class TestMySuperGenericType implements GenericClass<Integer> {
    public void print(Integer obj){}
}

กรณีที่ 3 เมื่อส่วนต่อขยายของคุณขยายส่วนต่อประสานที่ใช้ Generics

public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

interface TestMySuperGenericType extends GenericClass<Integer> {
}

1

นั่นคือตรงไปตรงมาสวย หากคุณต้องการจากภายในชั้นเดียวกัน:

Class clazz = this.getClass();
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
try {
        Class typeClass = Class.forName( parameterizedType.getActualTypeArguments()[0].getTypeName() );
        // You have the instance of type 'T' in typeClass variable

        System.out.println( "Class instance name: "+  typeClass.getName() );
    } catch (ClassNotFoundException e) {
        System.out.println( "ClassNotFound!! Something wrong! "+ e.getMessage() );
    }

0

ที่จริงแล้วฉันคิดว่าคุณมีเขตข้อมูลในคลาสประเภท T ของคุณหากไม่มีเขตข้อมูลชนิด T จุดของการมีประเภททั่วไปคืออะไร ดังนั้นคุณสามารถทำอินสแตนซ์ของฟิลด์นั้นได้

ในกรณีของฉันฉันมี

รายการ <T> รายการ;
ในชั้นเรียนของฉันและฉันจะตรวจสอบว่าประเภทชั้นเรียนเป็น "สถานที่" โดย

if (items.get (0) instanceof Locality) ...

แน่นอนว่าจะใช้งานได้ก็ต่อเมื่อจำนวนคลาสที่เป็นไปได้ทั้งหมดถูก จำกัด


4
ฉันควรทำอย่างไรหาก items.isEmpty () เป็นจริง
chaotic3quilibrium

0

คำถามนี้เก่า แต่ตอนนี้ดีที่สุดคือใช้ google GsonGoogle

viewModelตัวอย่างที่จะได้รับที่กำหนดเอง

Class<CustomViewModel<String>> clazz = new GenericClass<CustomViewModel<String>>().getRawType();
CustomViewModel<String> viewModel = viewModelProvider.get(clazz);

คลาสชนิดทั่วไป

class GenericClass<T>(private val rawType: Class<*>) {

    constructor():this(`$Gson$Types`.getRawType(object : TypeToken<T>() {}.getType()))

    fun getRawType(): Class<T> {
        return rawType as Class<T>
    }
}

0

ฉันต้องการส่ง T.class ไปยังวิธีที่ใช้ Generics

วิธีreadFileอ่านไฟล์. csv ที่ระบุโดย fileName ด้วย fullpath สามารถมีไฟล์ csv ที่มีเนื้อหาต่างกันดังนั้นฉันต้องผ่านคลาสไฟล์โมเดลเพื่อที่ฉันจะได้รับวัตถุที่เหมาะสม เนื่องจากนี่คือการอ่านไฟล์ csv ฉันต้องการจะทำในลักษณะทั่วไป ด้วยเหตุผลบางอย่างหรือไม่มีวิธีการแก้ปัญหาใดที่ได้ผลสำหรับฉัน ฉันต้องใช้ Class<? extends T> typeเพื่อทำให้มันใช้งานได้ ฉันใช้ไลบรารี opencsv สำหรับการแยกวิเคราะห์ไฟล์ CSV

private <T>List<T> readFile(String fileName, Class<? extends T> type) {

    List<T> dataList = new ArrayList<T>();
    try {
        File file = new File(fileName);

        Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        Reader headerReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        CSVReader csvReader = new CSVReader(headerReader);
        // create csv bean reader
        CsvToBean<T> csvToBean = new CsvToBeanBuilder(reader)
                .withType(type)
                .withIgnoreLeadingWhiteSpace(true)
                .build();

        dataList = csvToBean.parse();
    }
    catch (Exception ex) {
        logger.error("Error: ", ex);
    }

    return dataList;
}

นี่คือวิธีที่ readFile วิธีการที่เรียกว่า

List<RigSurfaceCSV> rigSurfaceCSVDataList = readSurfaceFile(surfaceFileName, RigSurfaceCSV.class);

-4

ฉันใช้วิธีแก้ปัญหาสำหรับสิ่งนี้:

class MyClass extends Foo<T> {
....
}

MyClass myClassInstance = MyClass.class.newInstance();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.