Java Generic
一、介绍
泛型又称为参数化类型,在编写代码时通过一个标识表示类中某个属性的类型或者方法返回值的、参数类型,在实例化时作为参数指明这些类型。
泛型可以保证如果程序在编译时没有警告,运行时则不产生ClassCastException
异常,使得代码更简洁更健壮。
二、泛型的使用
在接口interface
和类class
的声明时,加上类似<T>
的形式,其中尖括号之间可以使用任意大写字母,
表示类型,常用T,是Type的缩写。
//集合类中使用,标识集合中只能加入String类型的元素,添加其他类型元素就会报错
ArrayList<String> list = new ArrayList<>();
泛型只能填入引用类型,而不能是基本数据类型
ArrayList<int> list = new ArrayList<>(); //错误,类型参数不能是基本数据类型
在指定泛型后,可以传入该类型以及它的子类类型
当不传入泛型时,相当于传入Object类型
//当不传入泛型时,相当于传入Object类型
ArrayList list = new ArrayList();
//等价于下面一行代码
//ArrayList<Object> list = new ArrayList<>();
//集合可以传入Object以及Object的子类类型
list.add(1);
list.add(1.23);
list.add('a');
list.add(true);
list.add("asd");
System.out.println(list); //[1, 1.23, a, true, asd]
泛型通配符:
1.<?> 表示支持任意泛型类型
2.<? extend A> 规定泛型的上限,支持A类以及A类的子类
3.<? super A> 规定泛型的下限,支持A类以及A类的父类
class Animal{
}
class Mammal extends Animal{
}
class Dog extends Mammal{
}
class Cat extends Mammal{
}
//List<?> 可以传入任意类型组成的集合
public static void print(List<?> a){
for (Object o : a) {
System.out.println(o.getClass());
}
}
//List<? extends Mammal> 只能传入Mammal以及它的子类组成的集合
public static void print1(List<? extends Mammal> a){
for (Object o : a) {
System.out.println(o.getClass());
}
}
//List<? super Mammal> 只能传入Mammal以及它的父类组成的集合
public static void print2(List<? super Mammal> a){
for (Object o : a) {
System.out.println(o.getClass());
}
}
public static void main(String[] args) {
Animal animal = new Animal();
Mammal mammal = new Mammal();
Dog dog = new Dog();
Cat cat = new Cat();
ArrayList<Animal> animals = new ArrayList<>();
animals.add(animal);
ArrayList<Mammal> mammals = new ArrayList<>();
mammals.add(mammal);
ArrayList<Dog> dogs = new ArrayList<>();
dogs.add(dog);
ArrayList<Cat> cats = new ArrayList<>();
cats.add(cat);
//测试?
print(animals);
print(mammals);
print(dogs);
print(cats);
System.out.println("--------------------------");
//测试? extends Mammal,Animal为Mammal的父类不能传入
//print1(animals);
print1(mammals);
print1(dogs);
print1(cats);
System.out.println("--------------------------");
//测试? super Mammal
print2(animals);
print2(mammals);
//Dog、Cat为Mammal的子类不能传入
//print2(dogs);
//print2(cats);
}
/*
class com.hubu.generic.Animal
class com.hubu.generic.Mammal
class com.hubu.generic.Dog
class com.hubu.generic.Cat
--------------------------
class com.hubu.generic.Mammal
class com.hubu.generic.Dog
class com.hubu.generic.Cat
--------------------------
class com.hubu.generic.Animal
class com.hubu.generic.Mammal
*/
三、自定义泛型
1.自定义泛型类
-
成员属性、方法可以使用泛型
-
泛型数组不能初始化,因为无法确定该数组开辟的空间大小
-
静态属性、方法不能使用泛型,泛型在创建对象时才确定,但是静态属性、方法在类加载时就要确定
class A<T> {
//成员属性可以使用泛型
private T a;
//静态成员属性不能使用泛型
//private static T b;
//使用泛型的数组不能初始化
//T[] arr = new T[5];
private T[] arr;
//成员方法返回值可以使用泛型
public T f1(){
return a;
}
//成员方法参数值可以使用泛型
public void f2(T b){}
//静态方法不能使用泛型
//public static void f3(T c){}
public T getA() {
return a;
}
public void setA(T a) {
this.a = a;
}
public T[] getArr() {
return arr;
}
public void setArr(T[] arr) {
this.arr = arr;
}
}
public static void main(String[] args) {
A<String> a = new A<>();
a.setA("123");
System.out.println(a.f1()); //"123"
}
2.自定义泛型接口
-
接口的泛型在继承接口或者实现接口时确定
-
接口中的属性默认为static修饰无法使用泛型
-
抽象方法可以使用泛型
interface IB<T>{
//接口中的成员属性是静态的无法使用泛型
//public static T a = 1;
//抽象方法的返回值可以使用泛型
T f1();
//抽象方法的参数可以使用泛型
T f2(T a);
}
//实现接口时确定泛型
class B implements IB<String>{
@Override
public String f1() {
return "f1()...";
}
@Override
public String f2(String a) {
return a;
}
}
public static void main(String[] args) {
B b = new B();
System.out.println(b.f1()); //f1()...
System.out.println(b.f2("f2()...")); //f2()...
}
//继承接口时确定泛型
interface IC extends IB<Integer>{
}
class C implements IC{
@Override
public Integer f1() {
return 1;
}
@Override
public Integer f2(Integer a) {
return a;
}
}
public static void main(String[] args) {
C c = new C();
System.out.println(c.f1()); //1
System.out.println(c.f2(2)); //2
}
3.自定义泛型方法
-
在方法前面使用
<T>
声明泛型 -
可以定义在普通类和泛型类中
-
在调用泛型方法时确定类型
//在普通类中定义泛型方法
class Car {
public <T> T run(T a) {
return a;
}
}
public static void main(String[] args) {
Car car = new Car();
System.out.println(car.run("小汽车跑了2km...")); //小汽车跑了2km...
}
//在泛型类中定义泛型方法
class Person<T, R> {
T a;
R b;
public <K, V> Map<K, V> getInfo(K k, V v){
HashMap<K, V> map = new HashMap<>();
map.put(k, v);
return map;
}
public T getA() {
return a;
}
public void setA(T a) {
this.a = a;
}
public R getB() {
return b;
}
public void setB(R b) {
this.b = b;
}
}
public static void main(String[] args) {
Person<Object, Object> person = new Person<>();
System.out.println(person.getInfo("姓名", "张三")); //{姓名=张三}
System.out.println(person.getInfo("年龄", "18")); //{年龄=18}
System.out.println(person.getInfo("性别", "男")); //{性别=男}
}