java泛型_fanchenms的博客-程序员秘密

技术标签: java  泛型  

泛型

什么是泛型

1.背景:

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

2.概念:

Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。

泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数。

3.好处:

  • 类型安全

  • 消除了强制类型的转换

4.类型:

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

泛型类、接口

1.泛型类

  • 泛型类的定义语法

    class 类名称<泛型标识,泛型标识,...> {
          
        private 泛型标识 变量名;
        ......
    }
    
  • 常用的泛型标识:T、E、K、V

  • 使用语法

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

    类名<具体的数据类型> 对象名 = new 类名<>();  //菱形语法
    

1.1 泛型类注意事项

  • 泛型类,如果没有指定具体的数据类型,此时,操作类型是Object
  • 泛型的类型参数只能是类类型,不能是基本数据类型
  • 泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同类型

1.2 泛型类测试

泛型类的定义

/**
 * 泛型类的定义
 * @param <T> 泛型标识--类型形参
 *           T 创建对象的时候来指定具体的数据类型
 */
public class Generic<T> {
    
    // T 到底是什么? 是由外部使用类的时候类指定的
    private T key;

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

    public Generic() {
    
    }

    public T getKey() {
    
        return key;
    }

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

    @Override
    public String toString() {
    
        return "Generic{" +
                "key=" + key +
                '}';
    }
}

使用:

public class MainClass {
    
    public static void main(String[] args) {
    
        // 泛型类在创建的时候,来指定操作的具体数据类型
        Generic<String> stringGeneric = new Generic<String>("张三");
        String stringGenericKey = stringGeneric.getKey();
        System.out.println(stringGenericKey);

        System.out.println("-------------------------------------");

        Generic<Integer> integerGeneric = new Generic<>();
        integerGeneric.setKey(200);
        Integer integerGenericKey = integerGeneric.getKey();
        System.out.println(integerGenericKey);

        System.out.println("-------------------------------------");
        // 泛型类在创建对象的时候,没有指定类型,将按照 Object 类型类操作
        Generic generic1 = new Generic("李四");
        Object key1 = generic1.getKey();
        Generic generic2 = new Generic(300);
        Object key2 = generic2.getKey();


        // 泛型类不支持基本数据类型。(底层T转为Object,再转成指定类型,基本数据类型没有继承自Object)
//        Generic<int> intGeneric = new Generic<int>(100);  // 编译检测不通过


        System.out.println("-------------------------------------");

        // 同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型
        // 可以结合后面的泛型擦除理解,泛型擦除之后 Generic < String > 和Generic< Integer >都是Generic类。
        System.out.println(stringGeneric.getClass());   // class com.yzp.demo2.Generic
        System.out.println(integerGeneric.getClass());  // class com.yzp.demo2.Generic
        System.out.println(stringGeneric.getClass() == integerGeneric.getClass());  // true
    }
}

1.3 泛型类案例

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

/**
 * 抽奖器(奖品)
 */
public class ProductGetter<T> {
    
    // 随机数
    Random random = new Random();
    // 奖品
    private T product;

    // 奖品池
    List<T> list =new ArrayList<>();

    // 添加奖品
    public void addProduct(T t) {
    
        list.add(t);
    }

    // 抽奖
    public T getProduct() {
    
        product = list.get(random.nextInt(list.size()));
        return product;
    }

}
public class MainClass {
    
    public static void main(String[] args) {
    
        // 创建抽奖器对象,指定数据类型
        ProductGetter<String> stringProductGetter = new ProductGetter<>();
        String[] strProducts = {
    "苹果手机", "华为手机", "扫地机器人", "咖啡机"};
        // 给抽奖器中填充奖品
        for (String strProduct : strProducts) {
    
            stringProductGetter.addProduct(strProduct);
        }
        // 抽奖
        String product = stringProductGetter.getProduct();
        System.out.println("恭喜您抽中了:" + product);


        System.out.println("-------------------------------");
        ProductGetter<Integer> integerProductGetter = new ProductGetter<>();
        int[] intProducts = {
    500, 3000, 5000, 10000, 300000};
        for (int i = 0; i < intProducts.length; i++) {
    
            integerProductGetter.addProduct(intProducts[i]);
        }
        Integer product1 = integerProductGetter.getProduct();
        System.out.println("恭喜您,抽中了:" + product1 + "元");
    }
}

2.从泛型类派生子类

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

    class ChildGeneric<T> extends Generic<T>
    
  • 子类不是泛型类,父类要明确泛型的数据类型

    class ChildGeneric extends Generic<String>
    

父类

/**
 * 父类
 */
public class Parent<E> {
    
    private E value;

    public E getValue() {
    
        return value;
    }

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

泛型子类

/** 
 * 泛型类派生子类,子类也是泛型类,那么子类的泛型标识要和父类的一致。 
 * 子类可以进行泛型扩展,比如 ChildFirst<T,E,K> 
 * @param <T> 
 */
public class ChildFirst<T> extends Parent<T> {
        
	 @Override    
	 public T getValue() {
            
	 	return super.getValue();    
	 }
}

非泛型子类

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

测试

public class Test04 {
    
    public static void main(String[] args) {
    
        ChildFirst<String> stringChildFirst = new ChildFirst<>();
        stringChildFirst.setValue("张三");
        String value = stringChildFirst.getValue();
        System.out.println(value);

        System.out.println("--------------");

        ChildSecond childSecond = new ChildSecond();
        childSecond.setValue(100);
        Integer value1 = childSecond.getValue();
        System.out.println(value1);
    }
}

3.泛型接口

3.1 泛型接口的定义语法

interface 接口名称<泛型标识,泛型标识,...> {
    
    泛型标识 方法名();
    ...
}

3.2 泛型接口的使用

  • 实现类不是泛型类,接口要明确数据类型。
  • 实现类也是泛型类,实现类和接口的泛型类型要一致。

泛型接口

/**
 * 泛型接口
 * @param <T>
 */
public interface Generator<T> {
    
    T getKey();
}

非泛型实现类

/**
 * 实现泛型接口的类不是泛型类,需要明确指定实现泛型接口的数据类型
 * Apple 不是泛型类,需要明确指定Generator接口的数据类型 Generator<String>
 */
public class Apple implements Generator<String> {
    

    @Override
    public String getKey() {
    
        return "hello generic";
    }

}

泛型实现类

/**
 * 泛型接口的实现类是一个泛型类,那么要保证实现接口的泛型类泛型标识包含泛型接口的泛型标识
 * 即 Pair<T>是泛型类,接口泛型要相同Generator<T>,
 * Pair类可以对泛型进行扩充 Pair<T,E,K,...>
 * @param <T>
 */
public class Pair<T,E> implements Generator<T> {
    

    private T key;
    private E value;

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

    @Override
    public T getKey() {
    
        return key;
    }

    public E getValue() {
    
        return value;
    }
}

测试

public class Test05 {
    
    public static void main(String[] args) {
    
        Apple apple = new Apple();
        String key = apple.getKey();
        System.out.println(key);

        System.out.println("-----------------------");

        Pair<String, Integer> stringIntegerPair = new Pair<>("张三", 100);
        String key1 = stringIntegerPair.getKey();
        Integer value = stringIntegerPair.getValue();
        System.out.println(key1);
        System.out.println(value);
    }
}

泛型方法

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

1.语法

  • 泛型方法是在调用方法的时候指明泛型的具体类型。

    只有包含泛型列表的方法才是泛型方法 <T,E, …>

    // 非泛型方法 (泛型类中的使用了泛型的成员方法并不是泛型方法)
    修饰符 T 方法名(形参列表) {
          
        方法体...
    }
    
    // 泛型方法
    修饰符 <T> T 方法名(形参列表) {
          
        方法体...
    }
    
  • 语法:

    修饰符 <TE, ...> 返回值类型 方法名(形参列表) {
              方法体...}
    
  • public与返回值中间< T >非常重要,可以理解为声明此方法为泛型方法。

  • 只有声明了< T >的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

  • < T >表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。

  • 与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。

2.泛型方法与可变参数

public <E> void print(E... e){
    
	for (E e1 : e) {
    
		System.out.println(e);
	}
}

3.泛型方法总结

  • 泛型方法能使方法独立于类而产生变化(泛型方法最重要的特点)

    (注:实际工作中能够用泛型方法解决的尽量不用定义泛型类,因为泛型方法更加灵活)

  • 如果static方法要使用泛型能力,就必须使其成为泛型方法

4.测试

定义泛型方法

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

/**
 * 抽奖器(奖品)
 */
public class ProductGetter<T> {
    
    // 随机数
    private Random random = new Random();
    // 奖品
    private T product;

    // 奖品池
    List<T> list =new ArrayList<>();

    // 添加奖品
    public void addProduct(T t) {
    
        list.add(t);
    }

    /**
     * 抽奖,
     * 非泛型方法,泛型类的成员方法
     * 不能定义为 static 静态的
     * @return
     */
    public T getProduct() {
    
        product = list.get(random.nextInt(list.size()));
        return product;
    }


    /**
     * 定义泛型方法
     * 泛型方法的调用,类型是通过调用方法的时候来指定的
     * 泛型方法的泛型是独立,与泛型类定义的泛型无关
     * 泛型方法可以为 static 静态的
     * @param list  参数
     * @param <E>   泛型标识,具体类型由调用方法的时候来指定
     * @return
     */
    public <E> E getProduct(List<E> list) {
    
        return list.get(random.nextInt(list.size()));
    }

    /**
     * 静态泛型方法,可以采用多个泛型类型
     * @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());
    }


    /**
     * 可变参数泛型方法定义
     * @param e
     * @param <E>
     */
    public static <E> void print(E... e) {
    
        for (E e1 : e) {
    
            System.out.println(e1);
        }
    }


}

使用

/**
 * 泛型方法的使用
 */
public class Test06 {
    
    public static void main(String[] args) {
    
        ProductGetter<Integer> integerProductGetter = new ProductGetter<>();
        List<String> list = new ArrayList<>();
        list.add("笔记本电脑");
        list.add("苹果手机");
        list.add("扫地机器人");
        // 泛型方法的调用,类型是通过调用方法的时候来指定的
        String product = integerProductGetter.getProduct(list);
        System.out.println(product);
        // 泛型方法的泛型是独立,与泛型类定义的泛型无关
        System.out.println(product.getClass().getSimpleName()); // String


        System.out.println("--------------------------------");

        List<Integer> list1 = new ArrayList<>();
        list1.add(1000);
        list1.add(2000);
        list1.add(3000);
        Integer product1 = integerProductGetter.getProduct(list1);
        System.out.println(product1);
        System.out.println(product1.getClass().getSimpleName());    // Integer

        System.out.println("--------------------------------");

        // 静态泛型方法的调用,多个泛型类型
        ProductGetter.printType(100, "java", true);

        System.out.println("--------------------------------");
        // 可变参数泛型方法的调用
        ProductGetter.print(1,2,3,4,5);

    }
}

类型通配符

1.什么是类型通配符?

  • 类型通配符一般是使用 “?” 代替具体的类型实参。
  • 所以,类型通配符是类型实参,而不是类型形参。
public class Box<E> {
    
    private E first;

    public E getFirst() {
    
        return first;
    }

    public void setFirst(E first) {
    
        this.first = first;
    }
}
public class Test07 {
    
    public static void main(String[] args) {
    
        Box<Number> numberBox = new Box<>();
        numberBox.setFirst(100);
        showBox(numberBox);

        System.out.println("-----------------");

        Box<Integer> integerBox = new Box<>();
        integerBox.setFirst(200);
        showBox(integerBox);
    }

    /**
     * 类型通配符上限
     * @param box
     */
//    public static void showBox(Box<? extends Number> box) {
    
//        Number first = box.getFirst();
//        System.out.println(first);
//    }

    /**
     * 类型通配符是类型实参,而不是类型形参
     * @param box
     */
    public static void showBox(Box<?> box) {
    
        Object first = box.getFirst();
        System.out.println(first);
    }

    // 泛型不支持多态,需用类型通配符替代实参
//    public static void showBox(Box<Number> box) {
    
//        Object first = box.getFirst();
//        System.out.println(first);
//    }


}

2.类型通配符的上限

  • 语法:

    /接口<? extends 实参类型>
    

    要求该泛型的类型,只能是实参类型,或实参类型的子类类型

public class Animal {
    }
public class Cat extends Animal {
    }
public class MiniCat extends Cat {
    }
public class Test08Up {
    
    public static void main(String[] args) {
    
        ArrayList<Animal> animals = new ArrayList<>();
        ArrayList<Cat> cats = new ArrayList<>();
        ArrayList<MiniCat> miniCats = new ArrayList<>();

        //showAnimal(animals);  // 无法传递
        showAnimal(cats);
        showAnimal(miniCats);

    }

    /**
     * 泛型上限通配符,传递的集合类型,只能是 Cat 或 Cat的子类
     * @param list
     */
    public static void showAnimal(ArrayList<? extends Cat> list) {
    
        // 不能填充元素
        //list.add(new Animal());
        //list.add(new Cat());
        //.add(new MiniCat());
        for (Cat cat : list) {
    
            System.out.println(cat);
        }
    }
}

3.类型通配符的下限

  • 语法:

    /接口<? super 实参类型>
    

    要求该泛型的类型,只能是实参类型,或实参类型的父类类型

public class Animal {
    }
public class Cat extends Animal {
    }
public class MiniCat extends Cat {
    
}
public class Test08Down {
    
    public static void main(String[] args) {
    
        ArrayList<Animal> animals = new ArrayList<>();
        ArrayList<Cat> cats = new ArrayList<>();
        ArrayList<MiniCat> miniCats = new ArrayList<>();


        showAnimal(animals);
        showAnimal(cats);
        // showAnimal(miniCats);  // 无法床底
    }

    /**
     * 类型通配符下限,要求集合只能是Cat或Cat的父类类型
     * @param list
     */
    public static void showAnimal(ArrayList<? super Cat> list) {
    
        // 可以填充元素;(自己或子类类型)
        list.add(new Cat());
        list.add(new MiniCat());
        for (Object o : list) {
    
            System.out.println(o);
        }
    }
}

案例

jdk中TreeSet

public class Animal {
    
    public String name;

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

    @Override
    public String toString() {
    
        return "Animal{" +
                "name='" + name + '\'' +
                '}';
    }
}
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 + '\'' +
                '}';
    }
}
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 + '\'' +
                '}';
    }
}
/**
 * 类型通配符下限的使用
 */
public class Test08 {
    
    public static void main(String[] args) {
    
//        TreeSet<Cat> treeSet = new TreeSet<>(new Comparator2());
        TreeSet<Cat> treeSet = new TreeSet<>(new Comparator1());
        treeSet.add(new Cat("jerry", 20));
        treeSet.add(new Cat("amy", 22));
        treeSet.add(new Cat("frank", 35));
        treeSet.add(new Cat("jim", 15));

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

// 比较器
class Comparator1 implements Comparator<Animal> {
    
    @Override
    public int compare(Animal o1, Animal o2) {
    
        return o1.name.compareTo(o2.name);
    }
}

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

class Comparator3 implements Comparator<MiniCat> {
    
    @Override
    public int compare(MiniCat o1, MiniCat o2) {
    
        return o1.level - o2.level;
    }
}

类型擦除

1.概念

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

2. 无限制类型擦除

直接转成Object

在这里插入图片描述

public class Erasure<T> {
    
    private T key;

    public T getKey() {
    
        return key;
    }

    public void setKey(T key) {
    
        this.key = key;
    }
}
public class Test09 {
    
    public static void main(String[] args) {
    
//        ArrayList<Integer> integers = new ArrayList<>();
//        ArrayList<String> strings = new ArrayList<>();
//
//        System.out.println(integers.getClass().getSimpleName());    // ArrayList
//        System.out.println(strings.getClass().getSimpleName());     // ArrayList
//        System.out.println(integers.getClass() == strings.getClass());  // true


        Erasure<Integer> integerErasure = new Erasure<>();
        // 利用反射,获取Erasure类的字节码文件的Class类对象
        Class<? extends Erasure> clz = integerErasure.getClass();
        // 获取所有的成员变量
        Field[] declaredFields = clz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
    
            // 打印名称和类型,结果已经泛型T转成Object再进入JVM中 
            // 结果输出 =>   key:Object
            System.out.println(declaredField.getName() + ":" + declaredField.getType().getSimpleName());
        }
    }
}

3. 有限制的类型擦除

有上限,转成上限类型

在这里插入图片描述

/**
 * Erasure<T>                   无限制类型擦除
 * Erasure<T extends Number>    有上限类型擦除
 */
public class Erasure<T extends Number> {
    
    private T key;

    public T getKey() {
    
        return key;
    }

    public void setKey(T key) {
    
        this.key = key;
    }
}
public class Test09 {
    
    public static void main(String[] args) {
    
        Erasure<Integer> integerErasure = new Erasure<>();
        // 利用反射,获取Erasure类的字节码文件的Class类对象
        Class<? extends Erasure> clz = integerErasure.getClass();
        // 获取所有的成员变量
        Field[] declaredFields = clz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
    
            // 打印名称和类型,
            // 结果 =>  有上限类型擦除Number     key:Number
            System.out.println(declaredField.getName() + ":" + declaredField.getType().getSimpleName());
        }
    }
}

4.擦除方法中类型定义的参数

如果没有上下限,转为Object,有则转为上下限的类型

在这里插入图片描述

public class Erasure<T extends Number> {
    
    private T key;

    public T getKey() {
    
        return key;
    }

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

    /**
     * 泛型方法
     * @param t
     * @param <T>
     * @return
     */
    public <T extends List> T show(T t) {
    
        return t;
    }

}
public class Test09 {
    
    public static void main(String[] args) {
    
        Erasure<Integer> integerErasure = new Erasure<>();
        // 利用反射,获取Erasure类的字节码文件的Class类对象
        Class<? extends Erasure> clz = integerErasure.getClass();
        // 获取所有的成员变量
        Field[] declaredFields = clz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
    
            // 打印名称和类型,
            // 结果 =>  无上限类型擦除           key:Object
            // 结果 =>  有上限类型擦除Number     key:Number
            System.out.println(declaredField.getName() + ":" + declaredField.getType().getSimpleName());
        }


        System.out.println("-----------------------");

        // 获取所有的方法
        Method[] declaredMethods = clz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
    
            // 打印方法名和方法的返回值类型
            /**
             * 结果:
             * getKey:Number
             * show:List
             * setKey:void
             */
            System.out.println(declaredMethod.getName() + ":" + declaredMethod.getReturnType().getSimpleName());
        }


    }
}

5.桥接方法

在这里插入图片描述

/**
 * 泛型接口
 * @param <T>
 */
public interface Info<T> {
    
    T info(T t);
}
public class InfoImpl implements Info<Integer> {
    
    @Override
    public Integer info(Integer integer) {
    
        return integer;
    }
}
public class Test09 {
    
    public static void main(String[] args) {
    
        Class<InfoImpl> infoClass = InfoImpl.class;
        Method[] declaredMethods1 = infoClass.getDeclaredMethods();
        for (Method method : declaredMethods1) {
    
            /**
             * 打印结果: 有两个 info 方法
             * info:Integer
             * info:Object
             */
            System.out.println(method.getName() + ":" + method.getReturnType().getSimpleName());
        }
    }
}

泛型和数组

1.泛型数组的创建

注:在实际的开发中,尽量使用泛型集合替代泛型数组

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

    public class Test10 {
          
        public static void main(String[] args) {
          
            // 报错,可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象
            //ArrayList<String>[] listArr = new ArrayList<>[];
    
            // 此种方式易发生 ClassCastException 异常
    //        ArrayList[] lists = new ArrayList[5];   // 非泛型数组
    //        ArrayList<String>[] listArr = lists;
    
            ArrayList<String>[] listArr = new ArrayList[5]; // 用 new ArrayList 原生的创建数组,不要用泛型
    
        }
    }
    
  • 可以通过 java.lang.reflect.ArraynewInstance(Class,int) 创建T[]数组

    import java.lang.reflect.Array;
    
    /**
     * @author yzp
     * @version 1.0
     * @data 2021/9/8 - 0:37
     */
    public class Fruit<T> {
          
        // 不允许
        //private T[] array = new T[];
    
        private T[] array;
    
        public Fruit(Class<T> clz, int length) {
          
            // 通过 Array.newInstance 创建泛型数组
            array = (T[]) Array.newInstance(clz, length);
        }
    
        /**
         * 填充数组
         * @param index
         * @param item
         */
        public void put(int index,T item) {
          
            array[index] = item;
        }
    
        /**
         * 获取数组元素
         * @param index
         * @return
         */
        public T get(int index) {
          
            return array[index];
        }
    
        public T[] getArray() {
          
            return array;
        }
    
    }
    
    /**
     * 泛型与数据
     */
    public class Test10 {
          
        public static void main(String[] args) {
          
            Fruit<String> fruit = new Fruit<>(String.class, 3);
            fruit.put(0, "苹果");
            fruit.put(1, "西瓜");
            fruit.put(2, "香蕉");
            System.out.println(Arrays.toString(fruit.getArray()));
            String banana = fruit.get(2);
            System.out.println(banana);
        }
    }
    

泛型和反射

1.反射常用的泛型类

  • Class< T >
  • Constructor< T >
public class Person {
    
    private String name;

    public String getName() {
    
        return name;
    }

    public void setName(String name) {
    
        this.name = name;
    }
}
public class Test11 {
    
    public static void main(String[] args) throws Exception {
    
        Class<Person> clz = Person.class;
        Constructor<Person> constructor = clz.getConstructor();
        Person person = constructor.newInstance();

//        Class personClass = Person.class;
//        Constructor constructor = personClass.getConstructor();
//        Object o = constructor.newInstance();
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_45882068/article/details/120171022

智能推荐

2021最适合大学生的 MacBook_Mac柠檬的博客-程序员秘密

现代 Mac 已经取得了长足的进步,为大学生挑选 Mac 的困难不在于找到值得信赖、便携和最新的东西; 相反,需要寻找满足学生需求的最佳工具。 这就是为什么在购买之前进行研究并了解专业要求和日常使用细节很重要的原因。那么最适合大学生的 MacBook该怎么选?

xdoj用除留余数法和线性探测再散列的冲突解决方法构造哈希表_gledfish的博客-程序员秘密

(XDOJ)用除留余数法和线性探测再散列的冲突解决方法构造哈希表

并发编程3:操作线程_一只大马猴的博客-程序员秘密

线程执行是有优先级的,共分三种:最高优先级,默认值是10 最低优先级,默认值是1 默认优先级,默认值是5线程自身带有一些操作,下面看看每个操作的作用以及用途:start() join() sleep() yield() interrupt() 守护线程1.start使该线程开始执行;Java 虚拟机调用该线程的run方法。结果是两个线程并发地运行;当前线程(从...

Dedecms本地上传缩略图无法自动添加水印的解决方法_weixin_30535043的博客-程序员秘密

客户遇到一个问题,DEDECMS(V5.7)后台添加文档时,本地上传缩略图无法自动添加水印(系统设置里的图片水印设置没有问题),找了半天,终于找到了解决方法,留个记号:打开dede/archives_do.php 找到第111行$upfile = AdminUpload('litpic', 'imagelit', 0, false ); 改成$...

Spark之---UpdateStateByKey算子操作_小小的天和蜗牛的博客-程序员秘密

1.说明SparkStreaming的一般是7天24小时不停息的运行,而在运行的时候,中间会有很多的状态,而有些状态我们需要一些操作,比如累计,更新或者其他的操作。那么如何将这些独立的状态联系起来就成了一种迫切的需求。2.介绍UpdateStateByKey的主要功能:1、为Spark Streaming中每一个Key维护一份state状态,state类型可以是任意类型的, 可以是一个自...

如何对比Python和Java,只需三分钟告诉你!_weixin_33725515的博客-程序员秘密

Java和Python两门语言都是目前非常热门的语言,可谓北乔峰南慕容,二者不分上下,棋逢对手。但是对于初学者来说,非常困惑,因为时间和精力有限,上手必须要先学一门,到底选那个好呢,今天3分钟带你透彻了解。1.运行速度java是静态语言静态编译的,速度上要比Python快的很多,而Python动态类型语言,一边执行一边编译,速度要上慢一些。2.对Legacy代码的支持对于legacy代码的...

随便推点

tar/gz/bz/gz2/bz2...压缩与解压缩_Vivan的博客-程序员秘密

*.gz2用gunzip2 *.gz2 For examplegunzip2 *.tar.gz2,解出一个*.tar文件,然后tar -vxf *.tar即可.rar格式解压:[*******]$ rar a FileName.rar压缩:[*******

【全网世界区划最全整理输出之第五部分】全世界所有国家的行政区划整理,省市信息,已按照国家,省,市排好序,可直接复制使用,第五部分到结束行21088,总条数:21088_forestsea的博客-程序员秘密

序号 国家 省 城市 17194 美国 爱荷华州   17195 美国 爱荷华州 丹尼森 17196 美国 爱荷华州 丹维尔 17197 美国 爱荷华州 乔治 17198 美国 爱荷华州 亚历山大 17199 美国 爱荷华州 亚当斯县 17200 美国 爱荷华州 伍尔斯托克 17201 美国 爱荷华州 伯灵顿 1

压力测试工具Wrk使用_wrk latency是0_qingxinziran007的博客-程序员秘密

压力测试工具Wrk介绍概念GitHub地址:https://github.com/wg/wrk安装方式安装环境:Contos7List item切换到用户级的源码目录 cd /usr/local/src安装git,因为要从GitHub下载,如果已经安装,忽略此步,其他机器请使用其他命令如apt-get yum install git -y从GitHub中clone源码git clone https://github.com/wg/wrk.git完成以后,进入wr

Docker一站式教程,教你快速构建自己的镜像(一)_自己搭建docker镜像服务器_风中追风。的博客-程序员秘密

Docker简介什么是Docker?随着容器化技术的发展,现在Docker和K8s等技术越来越火,学习的人也越来越多。今天我们就来学习一下Docker,帮助你从0到你快速构建自己的镜像并运行在容器里。Dokcer技术是为了解决微服务架构中依赖冲突的问题,因为在分布式系统中,以来的组件非常多,不同组件之间部署往往会产生一些冲突,亦或是在成百上千台服务中重复部署而环境不一致造成的各种问题。例如一个项目中,部署时需要依赖于node.js、Redis、RabbitMQ、MySQL等,这些服务部署时所需要的

Ubuntu20.04改成中文并且添加中文输入法_ubuntu怎么设置成中文20.04_y健锋的博客-程序员秘密

一:首先先把系统改成中文:1、打开系统软件Language Support 2、点击3、勾选Chinese4、点击apply等待安装完成PS:在这个过程中你可能会遇到下图问题,这个时候你需要这三个指令,具体是干嘛的我也不知道,我只是一个萌新sudo rm /var/cache/apt/archives/locksudo rm /var/lib/dpkg/locksudo rm /var/lib/dpkg/lock-frontend5、点击Setting...

CUDA入门1——配置开发环境_薛大胖的博客-程序员秘密

安装CUDA Toolkithttps://developer.nvidia.com/cuda-downloads 从官网下载相应的安装包,它会提示下载网络版还是本地版,建议使用网络版,省事。一个空的CUDA程序1,使用CUDA Runtime创建直接创建 创建CUDA项目的时候可以通过选择CUDA Runtime来直接创建,省事。1.1 添加CUDA C/C++文件1.2 添加CUDA头文件#