Java泛型详细内容讲解

news2024/9/20 12:38:54

1.什么是泛型

1.1背景:

JAVA推出泛型以前,程序员可以构建一个元素类型为Object的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要程序员明确知道存储每个元素的数据类型,否则很容易引发ClassCastException异常。

1.2.概念:

Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数。

1.3.好处:

类型安全

消除了强制类型的转换

1.4.类型:

E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(表示Java 类,包括基本的类和我们自定义的类)
K - Key(表示键,比如Map中的key)
V - Value(表示值)
N - Number(表示数值类型)
? - (表示不确定的java类型)
S、U、V - 2nd、3rd、4th types

2.泛型类、接口

2.1 泛型类

(1)使用语法
类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();

(2)Java1.7以后,后面的<>中的具体的数据类型可以省略不写
类名<具体的数据类型> 对象名 = new 类名<>(); 菱形语法

2.2泛型类注意事项:

泛型类,如果没有指定具体的数据类型,此时,操作类型是Object
泛型的类型参数只能是类类型,不能是基本数据类型
泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同类型
有Generic这个类
Generic strGeneric = new Generic,
Generic intGeneric = new Generic
intGeneric.getClass() == strGeneric.getClass(),
结果是true

package gengic;

public class Generic <T>{
    private T key;


    public Generic(T key) {
        this.key = key;
    }

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }
}

package gengic;

public class Mainclass {
    public static void main(String[] args) {
//泛型类在创建对象的时候,来指定操作的具体数据类型
        Generic<String> test = new Generic<>("a");
        String key = test.getKey();
        System.out.println(key);
        System.out.println("======");
        Generic<Integer> test1 = new Generic<>(100);
        int key2 = test1.getKey();
        System.out.println(key2);
        System.out.println("======");
        // Generic<int> test1 = new Generic<>(100);
        //泛型类,不支持基本数据类型

        //在创建对象的时候,没有指定类型,将按照Object类型来操作
        Generic generic = new Generic("ABC");
        Object key1 = generic.getKey();
        System.out.println(key1);
        System.out.println("======");
        //同一泛型类,根据不同的数据类型创建的对象不同,本质上是同一类型

        System.out.println(test.getClass());
        System.out.println(test1.getClass());
        System.out.println( test.getClass()== test1.getClass());
    }
}


运行结果:

a
======
100
======
ABC
======
class gengic.Generic
class gengic.Generic
true

可以结合后面的泛型擦除理解,泛型擦除之后 Generic < String > 和Generic< Integer >都是Generic类。

抽奖demo案列:

package gengic;

import java.util.ArrayList;
import java.util.Random;

public class Product<T> {
    Random random = new Random();
    //产品
    private T product;
    //奖品池
    ArrayList<T> list = new ArrayList<>();//建立一个list存储数据

    public void  addProduct(T t) {//在addProduct的方法中添加数据到list里
         list.add(t);
    }
    //抽奖

    public T getProduct() {
        return product = list.get(random.nextInt(list.size())); //取出list中的数据
    }


}

package gengic;

public class GetProduct {
    public static void main(String[] args) {
        Product<String> getProductString = new Product<>();//生成新的对象
        String[]data = {"iphone","shopping card","coffe"}; //String的数组对象
        //给抽奖器填充数据
       for (int i = 0; i < data.length; i++) {
            getProductString.addProduct(data[i]);//遍历数据并调用addProduct方法添加生成对象的数据中

        }
        //抽奖
       String product1 = getProductString.getProduct();//getProduct方法取出对象中的数据
       System.out.println("抽出产品"+ product1);
        System.out.println("=================");
        Product<Integer> getProductInteger = new Product<>();//生成新的对象
        int []data1 = {1000,2000,3000,4000}; //String的数组对象
        //给抽奖器填充数据
        for (int i = 0; i < data1.length; i++) {
            getProductInteger.addProduct(data1[i]);//遍历数据并调用addProduct方法添加生成对象的数据中

        }
        //抽奖
        int product2 = getProductInteger.getProduct();//getProduct方法取出对象中的数据
        System.out.println("抽出产品"+ product2);




    }
}

运行结果

抽出产品coffe
=================
抽出产品1000

2.3 从泛型类派生子类

子类也是泛型类,子类和父类的泛型类型要一致

package gengic;

public class Father <E>{
    private E value;

    public E getValue() {
        return value;
    }

    public void setValue(E value) {
        this.value = value;
    }
}


package gengic;
/*
* 泛型类派生子类,子类也是泛型类,那么子类的泛型标识要和父类一致
*
* */

public class FirstChild<T> extends Father<T> {
    @Override
    public T getValue() {
        return super.getValue();
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

package gengic;

public class FatherMain {
    public static void main(String[] args) {
        FirstChild<String> test1 = new FirstChild<>();
        test1.setValue("a");
        System.out.println(test1.getValue());
    }
}

运行结果:

a

子类不是泛型类,父类要明确泛型的数据类型

package gengic;

public class Father <E>{
    private E value;

    public E getValue() {
        return value;
    }

    public void setValue(E value) {
        this.value = value;
    }
}

package gengic;
/*
*
* 泛型类派生子类,如果子类不是泛型类,那么父类要明确数据类型
* */
public class SecondChild extends Father<Integer>{
    @Override
    public Integer getValue() {
        return super.getValue();
    }

    @Override
    public void setValue(Integer value) {
        super.setValue(value);
    }
}

package gengic;

public class FatherMain {
    public static void main(String[] args) {
        FirstChild<String> test1 = new FirstChild<>();//泛型类
        test1.setValue("a");
        System.out.println(test1.getValue());

        System.out.println("===================");
        SecondChild test2= new SecondChild();//普通类
        test2.setValue(50000);
        System.out.println(test2.getValue());
    }

}

运行结果:

a
===================
50000

2.4泛型接口

泛型接口的定义语法:
interface 接口名称 <泛型标识,泛型标识,…> {
泛型标识 方法名();
}

2.5.泛型接口的使用

实现泛型接口的类不是泛型类

package gengic;
/*
* 泛型接口
* */

public interface Generator<T> {
     T getValue();

}

package gengic;
/*
* 实现泛型接口的类不是泛型类
* */
public class FirstInterface implements Generator<String> {
    @Override
    public String getValue() {
        return "hello,world";
    }
}

package gengic;

public class MainClass1 {
    public static void main(String[] args) {
        FirstInterface test1 = new FirstInterface();
        System.out.println(test1.getValue());
    }
}

运行结果:

hello,world

泛型接口的实现类,是一个泛型类,那么要保证实现接口的泛型类泛型标识包含泛型接口的泛型标识

package gengic;
/*
* 泛型借口
* */

public interface Generator<T> {
     T getValue();

}

package gengic;
/*
泛型接口的实现类,是一个泛型类,那么要保证实现接口的泛型类泛型标识包含泛型接口的泛型标识
* */

public class SecondInterface<T,E> implements Generator<T>{
    private T value;
    private E key;

    public SecondInterface(T value, E key) {
        this.value = value;
        this.key = key;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public E getKey() {
        return key;
    }

    public void setKey(E key) {
        this.key = key;
    }

    @Override
    public T getValue() {
        return value;
    }
}

package gengic;

public class MainClass1 {
    public static void main(String[] args) {
        FirstInterface test1 = new FirstInterface();
        System.out.println(test1.getValue());

        System.out.println("======");
        SecondInterface<String,Integer> test2 = new SecondInterface<>("age",10);
        String value = test2.getValue();
        int key = test2.getKey();
        System.out.println(value);
        System.out.println(key);
    }
}

运行结果:

hello,world
======
age
10

3.泛型方法

3.1.用法

泛型类,是在实例化类的时候指明泛型的具体类型
泛型方法,是在调用方法的时候指明泛型的具体类型。

3.2.语法:

修饰符 <T,E, …> 返回值类型 方法名(形参列表) { 方法体… }

3.3.说明:

public与返回值中间非常重要,可以理解为声明此方法为泛型方法。
只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
< T >表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。

package gengic;

import java.util.ArrayList;
import java.util.Random;

public class Product<T> {

    Random random = new Random();
    //产品
    private T product;
    //奖品池
    ArrayList<T> list = new ArrayList<>();//建立一个list存储数据

    public void  addProduct(T t) {//在addProduct的方法中添加数据到list里
         list.add(t);
    }
    //抽奖

    public T getProduct() {
        return product = list.get(random.nextInt(list.size())); //取出list中的数据
    }


    public ArrayList<T> getList() {
        return list;
    }
    /**
     * @Description 定义泛型方法
     * @Param :list参数
     *  @Param :<E>泛型标识,具体类型,由调用方法的时候指定
     * @return: <null>
     * @Author: Amy
     * @Date: 2023-01-04
     */
    public <E> E getProduct(ArrayList<E> list){
        return list.get(random.nextInt(list.size()));
    }
    

}
package gengic;

import java.util.ArrayList;

/**
 * @program: datastuct
 * @description:test
 * @author: Amy
 * @create: 2023-01-04 12:39
 **/
public class test {
    public static void main(String[] args) {
        Product<Integer> test3 = new Product<>();
        int[] data2 ={100,200,300};
        for (int i = 0; i < data2.length; i++) {
            test3.addProduct(data2[i]);
        }
        //泛型类的成员方法的调用
        Integer product3 = test3.getProduct();
        System.out.println(product3);
        System.out.println("====");

        Product<Integer> test1 = new Product<>();
        ArrayList<String> data = new ArrayList<>();
        data.add("computer");
        data.add("phone");
        data.add("money");
        //泛型方法的调用,类型是通过调用方法的时候来指定
        String product1 = test1.getProduct(data);
        System.out.println(product1+"\t"+product1.getClass().getName());
        System.out.println("====");


        //泛型方法的调用,类型是通过调用方法的时候来指定
        Product<Integer> test2 = new Product<>();
        ArrayList<Integer> data1 = new ArrayList<>();
        data1.add(1000);
        data1.add(2000);
        data1.add(3000);
        //泛型方法的调用,类型是通过调用方法的时候来指定
        Integer product2 = test2.getProduct(data1);
        System.out.println(product2+"\t"+product2.getClass().getName());

    }
}

结果运行:

300
====
money	java.lang.String
====
1000	java.lang.Integer

3.4 泛型方法与可变参数

    /*泛型方法与可变参数*/
    public static <E> void print(E...e){
        for (int i = 0; i < e.length; i++) {
            System.out.println(e[i]);

        }
    }
//测试
        /*泛型方法与可变参数*/
        test2.print(1,2,3,4);

运行结果:

1
2
3
4

3.5 静态的泛型方法,采用多个泛型类型

/**
     * 静态的泛型方法,采用多个泛型类型
     * @param t
     * @param e
     * @param k
     * @param <T>
     * @param <E>
     * @param <K>
     */
    public static <T,E,K> void printType(T t, E e, K k) {
        System.out.println(t + "\t" + t.getClass().getSimpleName());
        System.out.println(e + "\t" + e.getClass().getSimpleName());
        System.out.println(k + "\t" + k.getClass().getSimpleName());
    }

3.6 泛型方法总结

  • 泛型方法能使方法独立于类而产生变化
  • 如果static方法要使用泛型能力,就必须使其成为泛型方法

4、类型通配符

4.1.什么是类型通配符

类型通配符一般是使用"?"代替具体的类型实参。
所以,类型通配符是类型实参,而不是类型形参。

问题:
在这里插入图片描述

解决方法

package gengic;

/**
 * @description:
 * @author: Amy
 * @create: 2023-01-04 15:01
 **/
public class Box<E> {
    private E first;

    public E getFirst() {
        return first;
    }

    public void setFirst(E first) {
        this.first = first;
    }


}

package gengic;

/**
 * @description:
 * @author: Amy
 * @create: 2023-01-04 15:09
 **/
public class TestBox {
    public static void main(String[] args) {
        //类型通配符
        Box<Number> box1 = new Box<>();
        box1.setFirst(100);
        showBox(box1);

        Box<Integer> box2 = new Box<>();
        box2.setFirst(300);
        showBox(box2);
    }


    public static void showBox(Box<?> box){    //类型通配符,不具体指定数据类型,用?
        Object first = box.getFirst();
        System.out.println(first);

    }
}

运行结果:

100
300

4.2.类型通配符的上限

语法:
类/接口<? extends 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的子类类型

代码:

package gengic;

/**
 * @description:
 * @author: Amy
 * @create: 2023-01-04 15:25
 **/
public class Animal {
}
package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class Cat extends Animal{
}

package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class MiniCat extends Cat{
}

package gengic;

import java.util.ArrayList;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class Animaltest {
    public static void main(String[] args) {
        ArrayList<Animal> animals = new ArrayList<>();
        ArrayList<Cat> cat = new ArrayList<>();
        ArrayList<MiniCat> minicat = new ArrayList<>();
        // showAnimal(animals); 报错的原因是泛型的通配符是Cat,包括其继承的子类MiniCat,但不包括父类的Animal
        showAnimal(cat);
        showAnimal(minicat);


    }
//    泛型上限通配符,传递的集合类型,只能是Cat或Cat的子类
    public static void showAnimal(ArrayList<? extends Cat> list){
        //泛型的通配符上限是不允许填充数据
        //list.addAll(new Cat());
        for (int i = 0; i < list.size(); i++) {
            Cat cat = list.get(i);
            System.out.println(cat);
        }
    }
}

4.3.类型通配符的下限

语法:
类/接口<? super 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的父类类型

代码:

package gengic;

/**
 * @description:
 * @author: Amy
 * @create: 2023-01-04 15:25
 **/
public class Animal {
}
package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class Cat extends Animal{
}

package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class MiniCat extends Cat{
}

package gengic;

import java.util.ArrayList;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class Animaltest {
    public static void main(String[] args) {
        ArrayList<Animal> animals = new ArrayList<>();
        ArrayList<Cat> cat = new ArrayList<>();
        ArrayList<MiniCat> minicat = new ArrayList<>();
        showAnimal(animals);
        showAnimal(cat);
        //showAnimal(minicat);


    }
//    泛型通配符下限,传递的集合类型,只能是Cat或Cat的父类Animal
    public static void showAnimal(ArrayList<? super Cat> list){
        //泛型通配符下限可以添加其子类的数据
        list.add(new Cat());
        list.add(new MiniCat());
        for(Object o:list){
            System.out.println(o);
        }
    }
}

案例:
代码:

package gengic;

/**
 * @description:
 * @author: Amy
 * @create: 2023-01-04 15:25
 **/
public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                '}';
    }
}

package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class Cat extends Animal{
    public int age;

    public Cat(String name, int age) {
        super(name);
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class MiniCat extends Cat{
    public int level;

    public MiniCat(String name, int age, int level) {
        super(name, age);
        this.level = level;
    }

    @Override
    public String toString() {
        return "MiniCat{" +
                "level=" + level +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

package gengic;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class Animaltest {
    public static void main(String[] args) {
       TreeSet<Cat> treeSet = new TreeSet<>(new Com2());
        // TreeSet<Cat> treeSet = new TreeSet<>(new Com1()); //TreeSet是下限通配符,所以可以
        //按照字母的顺序排序
//        TreeSet<Cat> treeSet = new TreeSet<>(new Com3());//Cat以及父类是可以的,子类是不可以
        treeSet.add(new Cat("a",10));
        treeSet.add(new Cat("c",5));
        treeSet.add(new Cat("d",17));
        treeSet.add(new Cat("b",11));

        for(Cat cat :treeSet){
            System.out.println(cat);
        }




    }
   static class Com1 implements Comparator<Animal>{


       @Override
       public int compare(Animal o1, Animal o2) {
           return o1.name.compareTo(o2.name);
       }
   }
    static class Com2 implements Comparator<Cat>{


        @Override
        public int compare(Cat o1, Cat o2) {
            return o1.age-o2.age;
        }
    }
    static class Com3 implements Comparator<MiniCat>{


        @Override
        public int compare(MiniCat o1, MiniCat o2) {
            return o1.level-o2.level;
        }
    }
}

运行结果:

//按照age的大小排序
Cat{age=5, name='c'}
Cat{age=10, name='a'}
Cat{age=11, name='b'}
Cat{age=17, name='d'}

代码:

package gengic;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author: Amy
 * @create: 2023-01-04 15:27
 **/
public class Animaltest {
    public static void main(String[] args) {
//        TreeSet<Cat> treeSet = new TreeSet<>(new Com2());
        TreeSet<Cat> treeSet = new TreeSet<>(new Com1()); //TreeSet是下限通配符,所以可以
        //按照字母的顺序排序
//        TreeSet<Cat> treeSet = new TreeSet<>(new Com3());//Cat以及父类是可以的,子类是不可以
        treeSet.add(new Cat("a",10));
        treeSet.add(new Cat("c",5));
        treeSet.add(new Cat("d",17));
        treeSet.add(new Cat("b",11));

        for(Cat cat :treeSet){
            System.out.println(cat);
        }




    }
   static class Com1 implements Comparator<Animal>{


       @Override
       public int compare(Animal o1, Animal o2) {
           return o1.name.compareTo(o2.name);
       }
   }
    static class Com2 implements Comparator<Cat>{


        @Override
        public int compare(Cat o1, Cat o2) {
            return o1.age-o2.age;
        }
    }
    static class Com3 implements Comparator<MiniCat>{


        @Override
        public int compare(MiniCat o1, MiniCat o2) {
            return o1.level-o2.level;
        }
    }
}

运行结果:

//按照字母的顺序排序
Cat{age=10, name='a'}
Cat{age=11, name='b'}
Cat{age=5, name='c'}
Cat{age=17, name='d'}

5、类型擦除

5.1.概念

泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是泛型代码能够很好地和之前版本的代码兼容。那是因为,泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,我们称之为–类型擦除。

5.2.分类:

1)无限制类型擦除

在这里插入图片描述
代码:

package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 16:22
 **/
public class Erasure<T> {
    private T key;

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }
}

package gengic;

import java.lang.reflect.Field;

/**
 * @author: Amy
 * @create: 2023-01-04 16:23
 **/
public class TestErasure {
    public static void main(String[] args) {
        Erasure<Integer> erasure = new Erasure<>();
        Class<? extends  Erasure> clz= erasure.getClass();
        Field[] declareFields = clz.getDeclaredFields();
        for(Field declareField:declareFields){
            System.out.println(declareField.getName()+":"+declareField.getType().getSimpleName());
        }
    }
}

运行结果:

key:Object

2)有限制类型擦除

在这里插入图片描述
代码:

package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 16:22
 **/
public class Erasure< T extends Number> {
    private T key;

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }
}

package gengic;

import java.lang.reflect.Field;

/**
 * @author: Amy
 * @create: 2023-01-04 16:23
 **/
public class TestErasure {
    public static void main(String[] args) {
        Erasure<Integer> erasure = new Erasure<>();
        //利用反射,获取Erasure类的字节码文件的Class类对象
        Class<? extends  Erasure> clz= erasure.getClass();
        //获取所有的成员变量
        Field[] declareFields = clz.getDeclaredFields();
        for(Field declareField:declareFields){
            //打印成员变量的名称和类型
            System.out.println(declareField.getName()+":"+declareField.getType().getSimpleName());
        }
    }
}

运行结果:

key:Number

3)擦除方法中类型定义的参数

在这里插入图片描述
代码:


package gengic;

import java.util.List;

/**
 * @author: Amy
 * @create: 2023-01-04 16:22
 **/
public class Erasure< T extends Number> {
    private T key;

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }

    /**
     * 泛型方法
     * @Author: Amy
     * @Date: 2023-01-04
     */
    public <T extends List> T show(T t){
        return t;
    }
}

package gengic;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author: Amy
 * @create: 2023-01-04 16:23
 **/
public class TestErasure {
    public static void main(String[] args) {
        // 获取所有方法
        Method[] declaredFields = clz.getDeclaredMethods();
        for(Method declaredMethod : declaredFields){
        // 打印方法名和方法的返回值类型
            System.out.println(declaredMethod.getName()+":"+ declaredMethod.getReturnType().getSimpleName());
        }
    }
}

运行结果:

getKey:Number
setKey:void
show:List

4)桥接方法

在这里插入图片描述

代码:

package gengic;

public interface Info<T> {
    T info(T t);
}

package gengic;

/**
 * @author: Amy
 * @create: 2023-01-04 17:40
 **/
public class InfoImpl implements Info<Integer> {

    @Override
    public Integer info(Integer value) {
        return value;
    }
}

package gengic;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author: Amy
 * @create: 2023-01-04 16:23
 **/
public class TestErasure {
    public static void main(String[] args) {
        //拿到字节码对象
        Class<InfoImpl> infoClass = InfoImpl.class;
        // 获取所有方法
        Method[] infoImplMethods = infoClass.getDeclaredMethods();
        for(Method infoImplMethod : infoImplMethods){
            // 打印方法名和方法的返回值类型
            System.out.println(infoImplMethod.getName()+":"+ infoImplMethod.getReturnType().getSimpleName());
        }
    }
}

运行结果:

info:Integer
info:Object

6.泛型与数组

泛型数组的创建

可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象

错误:
在这里插入图片描述

错误:

import java.util.ArrayList;

/**
 * @author: Amy
 * @create: 2023-01-04 18:11
 **/
//型数组的创建
public class ArrList {
    public static void main(String[] args) {
        ArrayList[] list = new ArrayList[5];//原生数组
        ArrayList<String>[] listArr = list ;//泛型数组

        ArrayList<Integer> intList = new ArrayList<>();
        intList.add(100);

        list[0]=intList;
        String s = listArr[0].get(0);
        System.out.println(s);
    }
}

报错原因:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
	at gengic.ArrList.main(ArrList.java:19)

Process finished with exit code 1

正确代码:

import java.util.ArrayList;

/**
 * @author: Amy
 * @create: 2023-01-04 18:11
 **/
//型数组的创建
public class ArrList {
    public static void main(String[] args) {
        ArrayList<String>[] strlistArr = new ArrayList[5];
        ArrayList<String> strList = new ArrayList<>();
        strList.add("abc");


        strlistArr[0]=strList;
        String s = strlistArr[0].get(0);
        System.out.println(s);
    }
}

运行结果:

abc

可以通过java.lang.reflect.Array的newInstance(Class,int) 创建T[] 数组

案例:
代码:

import java.lang.reflect.Array;

/**
 * @author: Amy
 * @create: 2023-01-04 20:18
 **/
public class Fruit<T> {
    private T[] array;
    public Fruit(Class<T> clz,int length){
//        通过Array。newInstance创建泛型数组
        array = (T[]) Array.newInstance(clz,length);
    }
    //填充数组
    public void put(int index,T item){
        array[index] = item;
    }
    //获取数组元素
    public T get(int index){
        return array[index];
    }

    public T[] getArray(Fruit<String> fruit){
        return array;
    }
}

/**
 * @author: Amy
 * @create: 2023-01-04 20:25
 **/
public class Test1 {
    public static void main(String[] args) {
        Fruit<String> fruit = new Fruit<>(String.class,3);
        fruit.put(0,"apple");
        fruit.put(1,"peach");
        fruit.put(2,"banana");
        System.out.println(Arrays.toString(fruit.getArray(fruit)));
        String s = fruit.get(1);
        System.out.println(s);
    }
}

运行结果:

[apple, peach, banana]
peach

7、泛型和反射

反射常用的泛型类
Class
Constructor

代码:

public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Test1 {
    public static void main(String[] args) throws Exception {
        //泛型和反射

//        Class<Person> personClass = Person.class;
//        Constructor<Person> constructor = personClass.getConstructor();
//        Person person = constructor.newInstance();

        //如果不使用泛型会在之后还需要再转类型
        Class personClass = Person.class;
        Constructor constructor = personClass.getConstructor();
        Object o = constructor.newInstance();

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142127.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql中的实现字段或字符串拼接的三种方式

一、CONCAT函数concat函数是将多个字段或字符串拼接为一个字符串&#xff1b;但是字符串之间没有任何分隔。concat函数官方介绍-- CONCAT函数的语法如下&#xff1a; CONCAT(str1,str2,...)1.1、拼接非空字段或字符串SELECT CONCAT(字段1,字段2,字段3,...) from 表名;-- 拼接表…

C#构建Web服务项目实战(一)

概述本文通过VS2017&#xff0c;利用C#语言构建一个Web应用项目&#xff08;旧的ASP.NETWeb应用&#xff0c;非微软最新的.NETCore&#xff09;&#xff0c;并演示了如何利用Windows的IIS服务发布项目&#xff08;网站&#xff09;&#xff0c;以及在发布项目&#xff08;允许用…

C语言及算法设计课程实验三:最简单的C程序设计——顺序程序设计(三)

C语言及算法设计课程实验三&#xff1a;最简单的C程序设计——顺序程序设计&#xff08;三&#xff09;一、实验目的二、 实验内容2.3、计算存款利息三、 实验步骤3.3、顺序程序设计实验题目3&#xff1a;计算存款利息的实验步骤3.3.1、变量的声明3.3.2、变量的赋值3.3.3、计算…

递归分治时间复杂度主定理法

记录一下以前博客的证明过程&#xff0c;补充一下之前的结论 在算法导论中lgn一般指2为底的对数n&#xff0c;特此说明 以前写的博客记录了一下分治递归时间复杂度的结论&#xff0c;发现少了一个正则条件&#xff0c;而且也不覆盖所有的一般情况 https://blog.csdn.net/qq_1…

乌鸦安全2022年度文章合集

说明 乌鸦安全2022年精选原创文章合集&#xff0c;基本上大部分都是原创&#xff0c;当然还有一部分文章由其他师傅投稿提供&#xff0c;在此感谢各位师傅的投稿和帮助&#xff01; 乌鸦安全2021年度文章合集 你可以在这里找到我&#xff1a; GitHub&#xff1a;https://gi…

开源的工作流都有哪些特征?

开源的工作流是什么&#xff1f;都有什么样的特征和优势特点&#xff1f;众所周知&#xff0c;随着现代化办公管理的兴起&#xff0c;工作效率高的低代码开发平台涌上前线&#xff0c;成为很多企业实现数字化转型和做好数据管理的重要系统。这篇文章主要是围绕开源的工作流方面…

记一次2022某地HVV中的逆向分析

声明&#xff1a;本文仅限于技术讨论与分享&#xff0c;严禁用于非法途径。若读者因此作出任何危害网络安全行为后果自负&#xff0c;与本号及原作者无关。 前言 事情是这样的&#xff0c;国庆前期某地HVV&#xff0c;所以接到了客户通知他们收到了钓鱼邮件想要溯源 直接下载…

云视频会议系统私有化实践

点击上方“LiveVideoStack”关注我们▲扫描图中二维码或点击阅读原文▲了解音视频技术大会更多信息编者按&#xff1a;云视频会议系统支持多服务器动态集群部署&#xff0c;并提供多台高性能服务器&#xff0c;大大提升了会议稳定性、安全性、可用性。视频会议为用户大幅提高沟…

(Java高级教程)第三章Java网络编程-第一节2:网络编程必备网络知识2之网络协议分层

文章目录一&#xff1a;生活中的协议分层&#xff08;1&#xff09;生活中的分层1——汉堡包&#xff08;2&#xff09;生活中的分层2——打电话二&#xff1a;网络分层&#xff08;1&#xff09;OSI七层模型&#xff08;2&#xff09;TCP/IP分层模型三&#xff1a;OSI参考模型…

前端基础(六)_流程控制语句(if、if-else、if-else嵌套、switch)

流程控制语句主要分为 : 顺序结构&#xff1a;即按顺序执行代码 ;条件选择结构 ( 分支语句 )&#xff1a;包括 if-else 以及 switch;循环结构&#xff1a;包括 for循环&#xff0c;while&#xff0c;do-while,for-in 等;其他语句&#xff1a; break 和continue。 一、流程控制…

Java学习(23)Java一维数组概述

什么是数组 数组是相同类型的数据按顺序组成的一种引用数据类型。 数据类型分为基本数据类型和引用数据类型&#xff0c;引用数据类型分为类、接口、数组。要学习的内容 一维数组的声明、创建、初始化、元素的引用、长度。数组声明 语法格式&#xff1a; 数据类型[] 数组名; 数…

卡尔曼滤波原理公式详细推导过程[包括引出]

卡尔曼滤波在很多项目中都有用到&#xff0c;但是对于原理却很少有详细分析&#xff0c;而只是直接应用&#xff0c;在看完b站up主DR_CAN视频推导后自行推导一遍和查看其他资料后进行总结&#xff0c;将从最初的递归算法&#xff0c;利用数据融合&#xff0c;协方差矩阵&#x…

[vp] 2021 山东省赛 CDGHM

目录前言G. Grade Point Average ( 难度有先后)M. Matrix ProblemH. Adventurers GuildD.Dyson BoxC. Cat Virus前言 打满 2个小时30分钟 基本都在做题 体验非常好 传送门 : https://codeforces.com/gym/103118 G. Grade Point Average ( 难度有先后) 题意 : 让你求sum/ns…

UG/NX二开Siemens官方实例解析 4.4 EX_Curve_ProjCurves(创建投影曲线)

前言 本系列文章主要讲解NXOpen UF API&#xff08;简称ufun函数&#xff09;的使用&#xff0c;之前看教学视频大都建议用ufun进行开发&#xff0c;这里西门子官方还专门给了一套系列文章来讲&#xff0c;说明官方也是特别推崇ufun。 本人从事二开也有一段时间了&#xff0c;我…

干货 | 测试人职场晋升“潜规则”:15 年经验资深测试经理的职场忠告

大家好&#xff0c;我是云胖虎&#xff0c;有近 15 年工作经验&#xff0c;在测试专业上擅长的方向是自动化测试&#xff0c;测试工具平台开发和探索测试相关的一些领域&#xff0c;也拿到过项目管理和敏捷教练的认证&#xff0c;目前是在某知名金融银行企业担任技术经理。今天…

dataworks调度问题

文章目录名词解释月调度关于空跑名词解释 业务日期 定时日期 - 1 自定义参数示例&#xff1a; 月调度 调度详情&#xff1a; 重要 使用补数据功能对月调度任务执行补数据操作时&#xff0c;请注意补数据选择的为业务日期 &#xff0c;业务日期定时调度日期-1。 例如&#xf…

初始C++(一)

文章目录前言cout的用法cin的用法endl的用法一.命名空间1.:: (域作用限定符)2.命名空间定义3.命名空间的使用4.命名空间的一些其它使用5.全局展开6.部分展开二.缺省参数2.1全缺省2.2半缺省前言 既然这篇文章叫初始C&#xff0c;看我文章的应该和我一样&#xff0c;基本是个小白…

React-Router6路由相关二(路由传参、编程式路由导航、路由相关hooks)(八)

系列文章目录 第一章&#xff1a;React基础知识&#xff08;React基本使用、JSX语法、React模块化与组件化&#xff09;&#xff08;一&#xff09; 第二章&#xff1a;React基础知识&#xff08;组件实例三大核心属性state、props、refs&#xff09;&#xff08;二&#xff0…

ffmpeg vs2017录制vp9格式的桌面视频

ffmpeg本身不支持vp8,vp9&#xff1b;若要支持&#xff0c;则需要自己事先编译好vpx库&#xff0c;然后在ffmpeg中显式支持vpx库。 windows下采用mingw编译器编译vpx&#xff1b;本人采取的是MSYS2&#xff0c;并且本人编译vpx和ffmpeg时&#xff0c;编译的都是静态库&#xf…

【云原生】在Ubuntu18/20上部署Kubernetes/k8s集群详细教程——亲测可用!!网上其他教程均有问题!

在Ubuntu18/20上部署Kubernetes/k8s详细教程一、设置Docker二、安装Kubernetes第 1 步&#xff1a;添加Kubernetes签名密钥第 2 步&#xff1a;添加软件存储库第 3 步&#xff1a;Kubernetes 安装工具三、部署 Kubernetes步骤 1&#xff1a;准备 Kubernetes 部署步骤 2&#xf…