ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Java 中使用 Class<T>?

this question 对泛型以及它们在幕后的真正作用进行了很好的讨论,所以我们都知道 Vector<int[]> 是整数数组的向量,而 HashTable<String, Person> 是一个表,其键是字符串和值 { 4}秒。然而,让我难过的是 Class<> 的用法。

java 类 Class 也应该采用模板名称,(或者我被 eclipse 中的黄色下划线告知)。我不明白我应该在那里放什么。 Class 对象的全部意义在于您不完全掌握有关对象的信息,用于反射等。为什么它让我指定 Class 对象将包含哪个类?我显然不知道,或者我不会使用 Class 对象,我会使用特定的对象。


K
Kanagavelu Sugumar

我们所知道的是“任何类的所有实例都共享该类的相同 java.lang.Class 对象”

例如)

Student a = new Student();
Student b = new Student();

那么 a.getClass() == b.getClass() 为真。

现在假设

Teacher t = new Teacher();

没有泛型,以下是可能的。

Class studentClassRef = t.getClass();

但是现在这是错误的..?

例如)可以使用 Teacher.class 调用 public void printStudentClassInfo(Class studentClassRef) {}

使用泛型可以避免这种情况。

Class<Student> studentClassRef = t.getClass(); //Compilation error.

现在T是什么?? T 是类型参数(也称为类型变量);由尖括号 (<>) 分隔,跟在类名之后。
T 只是一个符号,就像在编写类文件时声明的变量名(可以是任何名称)。稍后在初始化期间 T 将被替换为
有效的类名 (HashMap<String> map = new HashMap<String>();)

例如)class name<T1, T2, ..., Tn>

因此 Class<T> 表示特定类类型“T”的类对象。

假设您的类方法必须使用未知类型参数,如下所示

/**
 * Generic version of the Car class.
 * @param <T> the type of the value
 */
public class Car<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

这里 T 可以用作 String 类型,如 CarName

OR T 可以用作 modelNumberInteger 类型,

OR T 可以用作 Object 类型作为有效的汽车实例

现在,上面是简单的 POJO,它可以在运行时以不同的方式使用。
Collections 例如)List、Set、Hashmap 是最好的例子,它们将根据 T 的声明与不同的对象一起工作,但是一旦我们将 T 声明为 String
eg)HashMap<String> map = new HashMap<String>(); 那么它将只接受 String 类实例对象。

通用方法

泛型方法是引入自己的类型参数的方法。这类似于声明泛型类型,但类型参数的范围仅限于声明它的方法。允许使用静态和非静态泛型方法,以及泛型类构造函数。

泛型方法的语法包括类型参数,位于尖括号内,并出现在方法的返回类型之前。对于泛型方法,类型参数部分必须出现在方法的返回类型之前。

 class Util {
    // Generic static method
    public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

 class Pair<K, V> {

    private K key;
    private V value;
}

这里的 <K, V, Z, Y> 是方法参数中使用的类型声明,它应该在返回类型之前,这里是 boolean

在下面;方法级别不需要类型声明 <T>,因为它已在类级别声明。

class MyClass<T> {
   private  T myMethod(T a){
       return  a;
   }
}

但是下面是错误的,因为类级别的类型参数 K、V、Z 和 Y 不能在静态上下文中使用(这里是静态方法)。

class Util <K, V, Z, Y>{
    // Generic static method
    public static  boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

其他有效场景是

class MyClass<T> {

        //Type declaration <T> already done at class level
        private  T myMethod(T a){
            return  a;
        }

        //<T> is overriding the T declared at Class level;
        //So There is no ClassCastException though a is not the type of T declared at MyClass<T>. 
        private <T> T myMethod1(Object a){
                return (T) a;
        }

        //Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).  
        private T myMethod1(Object a){
                return (T) a;
        }       

        // No ClassCastException        
        // MyClass<String> obj= new MyClass<String>();
        // obj.myMethod2(Integer.valueOf("1"));
        // Since type T is redefined at this method level.
        private <T> T myMethod2(T a){
            return  a;
        }

        // No ClassCastException for the below
        // MyClass<String> o= new MyClass<String>();
        // o.myMethod3(Integer.valueOf("1").getClass())
        // Since <T> is undefined within this method; 
        // And MyClass<T> don't have impact here
        private <T> T myMethod3(Class a){
            return (T) a;
        }

        // ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
        // Should be o.myMethod3(String.valueOf("1").getClass())
    private  T myMethod3(Class a){
        return (T) a;
    }


        // Class<T> a :: a is Class object of type T
        //<T> is overriding of class level type declaration; 
        private <T> Class<T> myMethod4(Class<T> a){
            return  a;
        }
    }

最后静态方法总是需要显式的 <T> 声明;它不会派生自类级别 Class<T>。这是因为类级别 T 与实例绑定。

另请阅读Restrictions on Generics

Wildcards and Subtyping

type argument for a generic method


我对有界通配符的回答stackoverflow.com/questions/1368166/…
“ Class 表示特定类类型 'T' 的类对象。” 这确实是有道理的。谢谢..
这个答案在关于 Classes (in Java) 的问题中使用 Classes (from school) 的方式非常令人困惑。从一个句子到另一个句子,很难知道作者在说什么。
@Echox 对不起,如果您有任何具体问题,我可以改进它。
A
Aryaveer

使用类 Class 的通用版本,除其他外,您可以编写类似的东西

Class<? extends Collection> someCollectionClass = someMethod();

然后您可以确定您收到的 Class 对象扩展了 Collection,并且此类的一个实例将(至少)是一个 Collection。


P
Peter Ajtai

来自 Java 文档:

[...] 更令人惊讶的是,类 Class 已被泛化。类文字现在用作类型标记,提供运行时和编译时类型信息。这启用了一种静态工厂风格,以新 AnnotatedElement 接口中的 getAnnotation 方法为例:

<T extends Annotation> T getAnnotation(Class<T> annotationType); 

这是一个通用的方法。它从参数推断其类型参数 T 的值,并返回一个适当的 T 实例,如以下代码段所示:

Author a = Othello.class.getAnnotation(Author.class);

在泛型之前,您必须将结果转换为 Author。此外,您将无法让编译器检查实际参数是否代表 Annotation 的子类。 [...]

好吧,我从来不用这种东西。任何人?


我(以为我)做到了。我使用的(某种)框架要求您传递模块所依赖的服务的类名。我在其上构建了一个层,该层采用 Class 对象,以限制选择的数量。使用 Class<? extends X> 符号我想我可以将其限制为仅“服务”类型。除了没有常见的“服务”类型之外,我只能用 Class<?> 来做。唉。
K
Kire Haglin

在创建服务注册表查找时,我发现 class<T> 很有用。例如

<T> T getService(Class<T> serviceClass)
{
    ...
}

S
Stew

在@Kire Haglin 的回答之后,可以在documentation for JAXB unmarshalling 中看到另一个泛型方法示例:

public <T> T unmarshal( Class<T> docClass, InputStream inputStream )
         throws JAXBException {
  String packageName = docClass.getPackage().getName();
  JAXBContext jc = JAXBContext.newInstance( packageName );
  Unmarshaller u = jc.createUnmarshaller();
  JAXBElement<T> doc = (JAXBElement<T>)u.unmarshal( inputStream );
  return doc.getValue();
}

这允许 unmarshal 返回任意 JAXB 内容树类型的文档。


b
bruno conde

正如其他答案所指出的那样,将这个 class 设为通用有很多很好的理由。但是,很多时候您无法知道与 Class<T> 一起使用的泛型类型。在这些情况下,您可以简单地忽略黄色日食警告,或者您可以使用 Class<?> ...我就是这样做的;)


@SuppressWarnings("unchecked") 来救援! (请注意始终将其应用于尽可能小的范围,因为它确实掩盖了代码中的潜在问题。)
P
Priyesh Diukar

在 java 中 <T> 表示泛型类。泛型类是可以处理任何类型的数据类型的类,或者换句话说,我们可以说它是数据类型独立的。

public class Shape<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

其中 T 表示类型。现在,当您创建此 Shape 类的实例时,您需要告诉编译器它将处理哪种数据类型。

例子:

Shape<Integer> s1 = new Shape();
Shape<String> s2 = new Shape();

Integer 是一种类型,String 也是一种类型。

<T> 专门代表泛型类型。根据 Java Docs - 泛型类型是在类型之上参数化的泛型类或接口。


T
Tom Hawtin - tackline

您经常希望在 Class 中使用通配符。例如,Class<? extends JComponent> 将允许您指定该类是 JComponent 的某个子类。如果您已从 Class.forName 检索 Class 实例,那么您可以在尝试构造实例之前使用 Class.asSubclass 进行转换。


z
zeronone

举另一个例子,类 (Class<T>) 的泛型版本允许编写如下泛型函数。

public static <T extends Enum<T>>Optional<T> optionalFromString(
        @NotNull Class<T> clazz,
        String name
) {
    return Optional<T> opt = Optional.ofNullable(name)
            .map(String::trim)
            .filter(StringUtils::isNotBlank)
            .map(String::toUpperCase)
            .flatMap(n -> {
                try {
                    return Optional.of(Enum.valueOf(clazz, n));
                } catch (Exception e) {
                    return Optional.empty();
                }
            });
}

f
fastcodejava

一开始很混乱。但它在以下情况下有所帮助:

class SomeAction implements Action {
}

// Later in the code.
Class<Action> actionClass = Class.forName("SomeAction"); 
Action action = actionClass.newInstance();
// Notice you get an Action instance, there was no need to cast.

这不是说 Action a = new Action() 的一种非常复杂的方式吗?
Action a = new Action() Action 我是一个接口,它是 SomeAction 我们正在尝试获取的一个实例。我们只有 SomeAction 的名称在运行时可用。
这没有通过类型检查:java 编译器无法判断 Class.forName("SomeAction") 将是 Class 类型,因为这只会在运行时被知道。
@tonio,对,所以您可能必须将第一行包装在某种 try/catch 中。但是假设那里没有抛出异常,第二行保证可以工作。
您真正描述的是 SomeAction.class 匹配模式 Class - 也就是说,如果你有一个方法 useAction(Class klass),你可以调用 useAction(SomeAction.class)。
M
MasterAM

只需使用牛肉类:

public <T> T beefmarshal( Class<beef> beefClass, InputBeef inputBeef )
     throws JAXBException {
     String packageName = docClass.getPackage().getBeef();
     JAXBContext beef = JAXBContext.newInstance( packageName );
     Unmarshaller u = beef.createBeef();
     JAXBElement<T> doc = (JAXBElement<T>)u.beefmarshal( inputBeef );
     return doc.getBeef();
}

这并没有真正提供问题的完整答案。如果您认为您有什么要添加的,请编辑此答案。