Java中泛型T和Class<T>的理解

Class类

Class类的实例表示Java应用运行时的类(class ans enum)或接口(interface and annotation)(每个Java类运行时都在JVM里表现为一个Class对象,可通过类名.class,类型.getClass(),Class.forName("类名")等方法获取Class对象)。数组同样也被映射为为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。基本类型boolean,byte,char,short,int,long,float,double和关键字void同样表现为Class对象。

T、Class<T>和Class<?>

单独的T代表一个类型,而Class<T>和Class<?>代表这个类型所对应的类

Class<T>在实例化时,T要替换成具体类

Class<?>是个通配泛型,?可以代表任何类型  

<? extends T>受限通配,表示T的一个未知子类。

<? super T>下限通配,表示T的一个未知父类。

public T find(Class<T> clazz, int id);

 

根据类来反射生成一个实例,而单独用T没法做到。

 

Object类中包含一个方法名叫getClass,利用这个方法就可以获得一个实例的类型类。类型类指的是代表一个类型的类,因为一切皆是对象,类型也不例外,在Java使用类型类来表示一个类型。所有的类型类都是Class类的实例。getClass()会看到返回Class<?>。

 

JDK中,普通的Class.newInstance()方法的定义返回Object,要将该返回类型强制转换为另一种类型;

 

但是使用泛型的Class<T>,Class.newInstance()方法具有一个特定的返回类型;

 

 

public class Main2 {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        System.out.println("1-----------");
        Dog dog1 = creatNew1(Dog.class);
        System.out.println(dog1.name + " is " + dog1.type+ "\n");

        System.out.println("2-----------");
        Animal ani1 = creatNew2(Cat.class);
        Cat cat1 = (Cat) ani1;
        System.out.println(cat1.name + " is " + cat1.type + "\n");

        System.out.println("3-----------");
        Object obj = creatNew3(Dog.class);
        Dog dog2 = (Dog) obj;
        System.out.println(dog1.name + " is " + dog2.type + "\n");

        System.out.println("4-----------");
        Object obj2 = creatNew4(Cat.class);
        Cat cat2 = (Cat) obj2;
        System.out.println(cat2.name + " is " + cat2.type + "\n");

        System.out.println("5-----------");
        Object obj3 = creatNew5(new Cat());
        Cat cat3 = (Cat) obj3;
        System.out.println(cat3.name + " is " + cat3.type + "\n");
    }

    /**
     * 此方法是一个非泛型类中的泛型方法,参数为Class<T>类型,可以传入任何类,但是Class<T>将参数在函数内部的类型固定为 T类,使用clazz.newInstance(),返回的类型也为固定的 T 类型。
     * 如: 传入Dog.class, 函数中的 T 固定为Dog.class,函数返回的是Dog类型,不需要强制转换为Dog类型
     * (当然,函数返回类型也可以是Object类型,但是没必要)
     */
    public static <T> T creatNew1(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        System.out.println(clazz);//打印具体传入的类型。
        return clazz.newInstance();
    }

    /**
     * 此方法参数是Class<? extends Animal>,只能传入Animal及其子类的类型,函数返回类型只能声明为Animal或Object类型,
     * 如:传入Cat.class,函数返回一个Animal的子类对象,需将此子类对象强制转换为具体的子类(即Cat类)。
     */
    public static Animal creatNew2(Class<? extends Animal> clazz) throws IllegalAccessException, InstantiationException {
        System.out.println(clazz);//打印具体传入的类型。
        return clazz.newInstance();
    }

    /**
     * 此方法参数是Class,可传入任何类,其返回只能声明为Object类对象。
     * 如:传入Dog.class, 返回的是Object类型的对象,需强制转换为Dog类型的对象。
     */
    public static Object creatNew3(Class clazz) throws IllegalAccessException, InstantiationException {
        System.out.println(clazz);//打印具体传入的类型。
        return clazz.newInstance();
    }

    /**
     * 传入参数Class<?> 和 上一个方法传入 Class 的区别还不是很清楚,其返回只能声明为Object类对象。
     * 如:Cat.class, 返回的是Object类型的对象,需强制转换为Cat类型的对象。
     */
    public static Object creatNew4(Class<?> clazz) throws IllegalAccessException, InstantiationException {
        System.out.println(clazz);//打印具体传入的类型。
        return clazz.newInstance();
    }

    /**
     * 传入Object类型的对象,返回也声明为Object类型。
     */
    public static Object creatNew5(Object object) {
        System.out.println(object.getClass());//打印具体传入的类型。
        return object;
    }
}

abstract class Animal {
    public String type = "type = animal ";
}

class Dog extends Animal {
    public String name = "name = gou";
}

class Cat extends Animal {
    public String name = "name = mao";
}

/**
 * 这些方法,传的参数声明不同,其返回的声明也必然要随之不同。
 */
<think>好的,我现在需要解决用户提出的Java问题:“类名称<? extends List> a=null 在这个语法中a是什么”。首先,我要仔细分析这个语法结构,并理解其中的各个部分。 用户给出的代码示例是“类名称<? extends List> a=null”。这里的“类名称”应该是一个占位符,代表某个具体的类,比如常见的类如ArrayList、LinkedList等,或者是用户自定义的类。接下来是通配符<? extends List>,然后是变量a的声明,并初始化为null。 首先,我需要明确Java中的通配符用法。通配符有三种形式:无界通配符<?>,上边界通配符<? extends T>,下边界通配符<? super T>。在这个例子中,使用的是上边界通配符,即<? extends List>,这表示该可以是List本身或其任何子类。例如,如果有一个类ArrayList extends List,那么ArrayList就符合这个通配符的条件。 接下来,变量a的类是“类名称<? extends List>”。这里的类名称可能是一个参数化的类,比如一个容器类,比如Box<? extends List>,或者类似的情况。例如,如果有一个类定义如下: public class Container<T> { private T value; // getter and setter } 那么声明Container<? extends List> a = null; 就表示变量a是一个Container类的引用,其参数是List或其子类。此时,a可以指向任何Container实例,其参数是List或List的子类,比如Container<ArrayList>、Container<LinkedList>等,只要这些类是List的子类或实现。 但用户的问题中,类名称可能本身就是一个类,例如假设用户实际指的是类似于这样的代码: SomeGenericClass<? extends List> a = null; 这时候,变量a的类是SomeGenericClass的一个参数化类,其类参数是上界为List的通配符。这意味着a可以引用SomeGenericClass类的实例,其参数是任何实现了List接口的类,比如ArrayList、LinkedList等。 需要注意的是,当使用上界通配符时,对于该类的某些方法可能会有使用上的限制。例如,如果SomeGenericClass有一个方法接受类参数T作为参数,那么在声明为<? extends List>的情况下,该方法的参数类会被视为某种具体的List子类,但编译器无法确定具体类,因此不能安全地传递任何子类的List(除了null)。不过,如果方法返回类是T,那么可以安全地将其赋值给List类的变量,因为T的上界是List。 回到用户的问题,变量a被声明为类名称<? extends List>类,并初始化为null。这里的a是一个引用变量,它可以指向该类的实例,其中参数是List或其子类。但此时a被赋值为null,所以它并没有实际引用任何对象,只是类声明为带有上界通配符的类。 需要进一步确认的是,用户是否对通配符的用途限制有疑问,或者对变量a可以赋什么类的对象存在疑问。例如,如果有一个实例如: SomeGenericClass<ArrayList> instance = new SomeGenericClass<>(); a = instance; // 这是允许的,因为ArrayList是List的子类 这种情况下,a可以指向这个instance对象,因为参数匹配上界。 总结来说,变量a是一个类的引用,其类参数使用上界通配符,限制为List或其子类。这使得a可以灵活地引用多种不同的具体实例,但同时也限制了某些操作,如添加元素到集合中的能力,因为具体类未知。 接下来需要将这些分析整理成用户需要的回答格式,先回答问题,再解释原因,然后给出相关问题。需要注意的是,用户可能对通配符的更多细节感兴趣,或者对的使用场景有疑问,因此相关问题需要围绕这些点展开。</think><< 在`类名称<? extends List> a = null`语法中,变量`a`是一个**类的引用**,其参数被声明为**上界通配符(`? extends List`)**。具体来说: 1. **类声明**:`a`的类是`类名称<? extends List>`,表示该类的类参数可以是`List`接口或其任何子类(如`ArrayList`、`LinkedList`)。 2. **初始化值**:`a`被赋值为`null`,表示它尚未引用任何实际对象。 3. **用途**:通过上界通配符,`a`可以接受`类名称<具体List子类>`的实例(例如`类名称<ArrayList>`),但会限制某些操作(如向集合中添加元素)。 **示例代码**: ```java // 假设存在一个类 class MyGenericClass<T> { /* ... */ } // 声明一个上界通配符的引用 MyGenericClass<? extends List> a = null; // 允许赋值 a = new MyGenericClass<ArrayList>(); // ArrayList是List的子类 a = new MyGenericClass<LinkedList>(); // LinkedList也是List的子类 ``` **关键限制**: - 无法安全调用参数类依赖的方法(如`add`方法),因为编译器无法确定具体类。 - 可以安全调用返回值类依赖的方法(如`get`),因为返回值可以向上转为`List`。 >>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值