Java泛型知识点总结
一、Java泛型的概述:
泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。
由来:通过Object转型问题引入,早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。
理解:泛型可以定义类、接口、方法比如说在类上使用泛型,我们一个让这个类的数据不再单一化,可以让此类创建各种类型数据的对象。总之,泛型就相当于参数化类型,把类型当作参数一样的传递。
泛型的格式 :
<数据类型> 这里的数据类型只能是引用数据类型
- 优点:
- 把运行时期的问题提前到了编译期间
- 避免了强制类型转换
- 优化了程序设计,解决了黄色警告线
注意:泛型只在编译期有效 但在运行期就擦除了。
二、泛型应用:
注意:泛型形参不止可以定义一个,可以定义多个,具体以实际情况为准。
1. 泛型类:把泛型加在类上。
我们将泛型定义在类上之后,T代表一个泛型标志,可以在new对象的时候,传入不同的引用数据类型,类的多样化就体现出来了。
格式 public class 类名<泛型类型1,…>
注意:泛型类型必须是引用类型。
public class Student<M,N,P> { //定义一个泛型类
private M m;
private N n;
public M getM() {
return m;
}
public void setM(M m) {
this.m = m;
}
public N getN() {
return n;
}
public void setN(N n) {
this.n = n;
}
2. 泛型接口:把泛型加在接口上。
格式: public interface 接口名<泛型类型>
public interface interface1<P> {
public abstract <p> void show(P p);
}
3. 泛型方法:把泛型加在方法上。
格式: public <泛型类型> 返回类型 方法名(泛型类型 变量名)
public <p> void show(P p) {
System.out.println(p);
}
三、泛型高级之通配符:
- 泛型通配符<?>: 任意类型,如果没有明确,那么就是Object以及任意的Java类了。
- ? extends E: 向下限定,E及其子类。
- ? super E: 向上限定,E及其父类。
ArrayList<?> list1 = new ArrayList<Animal>(); //?匹配任意类,如果没有明确,那么就是Object以及任意的J
ArrayList<?> list2 = new ArrayList<Cat>();
ArrayList<?> list3 = new ArrayList<Dog>();
System.out.println("-----------------------");
ArrayList<? super Cat> list4 = new ArrayList<Cat>(); //向上限定,Cat及其父类
ArrayList<? super Cat> list5 = new ArrayList<Animal>();
ArrayList<? super Cat> list6 = new ArrayList<Object>();
ArrayList<? super Cat> list6 = new ArrayList<Dog>(); 报错
System.out.println("-----------------------");
ArrayList<? extends Dog> list7 = new ArrayList<Dog>(); //向下限定,Dog及其子类
ArrayList<? extends Dog> list8 = new ArrayList<DogJ>();
ArrayList<? extends Cat> list9 = new ArrayList<Animal>();报错
理解:当需求分析我们不知道明确的类型操作时候,使用通配符?就是让我们告诉JVM(java虚拟机),我们也不清楚此时需要什么类型,所以先默认这个类,接口,方法,集合等等,可以接受所有类型。但是一般情况最好不要这么用,因为我们用泛型的初衷就是指定唯一类型,这与开始相互矛盾。
四、可变参数的概述和使用:
可变参数概述: 定义方法的时候不知道该定义多少个参数
格式: 修饰符 返回值类型 方法名(数据类型… 变量名){}
private static int sum(int...a){ //此处相当于int a, int b ,int c等等
int sum = 0;
for (int ele:a
) {
sum+=ele;
}
return sum;
}
注意:这里的变量其实是一个数组。
可变参数使用说明:可变参作为单独的参数使用,或者如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是位于最后一个。
private static int sum(int b,int...a){ //语法:修饰符 返回值类型 方法名(数据类型… 变量名){}
int sum = 0;
int b = 0;
for (int ele:a
) {
sum+=ele;
}
b+= sum;
return sum;
}
五、常用注意事项:
1.从泛型类派生的子类或者实现泛型接口时候,当使用这些接口和父类时不能包含类型形参
//定义类A继承Apple类 Apple类不能跟类型形参
public class A extends Apple<T>{...} //错误
public class A extends Apple<String> //正确
public class A extends Apple //正确
2.静态方法,静态初始化块,静态变量的声明和初始化不允许使用类型形参。
public class R<T>
{
//下面代码错误 不能在静态变量声明里使用类型形参
static T info;
T age;fan
public void foo(T msg){}
//下面代码错误 不能在静态方法里使用类型形参
public static void bar(T msg){}
}
六、泛型和类型通配符的使用区别:
//类型通配符
public interface Collection<E>{
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
...
}
//泛型方法
public interface Collection<E>
{
<T> boolean containsAll(Collection<T> c);
<T exteands E > boolean addAll(Collection<T> c);
}
1.大多数情况使用泛型来代替类型通配符。
2.上面两种方式中:在泛型方法里类型形参只使用了一次,类型形参T产生的唯一效果就是可以在不同的调用点传入不同的实际类型。对于这种情况应该使用通配符:通配符就是被设计用来支持灵活的子类化的。
3.泛型方法允许类型形参被用来表示方法的一个或多个参数之间的类型依赖关系,或者方法返回值与参数之间的类型依赖关系。如果没有这样的类型依赖关系,就不应该使用泛型方法。
4.类型通配符和泛型方法一个显著的区别:类型通配符既可以在方法签名中定义形参的类型,也可以用于定义变量的类型;但泛型方法中的类型形参必须在对应的方法中显示声明。
上一篇: 数制转换 - 九度教程第44题