学习笔记-泛型
泛型基础知识
泛型类
-
类签名中包含泛型的类
-
位置:类名后
-
注意:
- 泛型只能使用引用类型,不能使用基本类型
- 不能再静态属性上使用泛型声明
泛型类
public class Student
{ private T1 javaScore; private T2 oracleScore; //泛型声明时不能在静态属性上使用 //private static T1 test; public T1 getJavaScore() { return javaScore; } public void setJavaScore(T1 javaScore) { this.javaScore = javaScore; } public T2 getOracleScore() { return oracleScore; } public void setOracleScore(T2 oracleScore) { this.oracleScore = oracleScore; } public static void main(String[] args) { //使用时指定类型(引用类型) Student stu=new Student (); //1,安全:指定类型之后,在编译期间会自动检查类型,排除类型错误 stu.setJavaScore("优秀"); //2,省心:优化掉强制转换的步骤 int it=stu.getOracleScore(); } }
泛型接口
- 签名中包含泛型的接口
- 位置:接口名后
- 不能将静态属性声明为泛型,而接口内的属性默认为静态属性
- 接口只在方法上应用泛型
泛型接口
public interface Comparator {
//接口不能采用泛型属性
//T a=2;
void compare(T t);
}
泛型方法
-
签名中包含泛型的方法
-
位置:返回类型前
-
注意
-
编写泛型方法时,泛型未指定,该类型默认为Object类型,所以只能按照Ojbect类型所具备的属性和方法进行算法部署
-
无边界泛型
public class TestMethod{ static private String b="abc"; //泛型方法 public static
void test(T a) { b.indexOf(0);//字符串b可以使用String类型的方法 a.toString();//而a的类型未指定,只能使用Object类型的方法 }
-
-
或者给泛型设定边界,该类型默认为该边界
-
有边界泛型
public static
void test1(T a){ a.add(null);//可以使用Collection容器类的方法 a.remove(null);以使用Collection容器类的方法 }
-
-
泛型深入1
派生子类/实现类
-
应用情形
-
父类或者接口使用泛型都一样原理
-
父类
public abstract class Father<T,T1> { T name; public abstract void test(T t) ; }
-
-
子类/实现列指定具体的类型
-
示例
//子类声明时指定具体类型,属性类型为指定的类型,方法同理 class Child1 extends Father<String,Integer>{ @Override public void test(String t) { this.name.getClass();//已指定类型,返回String类型 } }
-
-
子类与父类|接口一样使用泛型
-
示例
//子类声明泛型,在使用时才确定类型,并且子类声明的泛型包含父类且可以比父类多 class Child2<T,T1> extends Father<T,T1>{ T1 t2;//使用时才确定类型 @Override public void test(T t) { //泛型未指定,提示name:T-Father<T,T1> this.name.getClass();//使用时才确定类型 } }
-
-
子类与父类|接口同时擦除类型
-
示例
class Child4 extends Father{ @Override public void test(Object t) { //类型擦除即默认为Object类型 this.name.getClass();//返回Object类型 } }
-
-
子类泛型,父类|接口 擦除
-
示例
//子类为泛型类,父类擦除(默认指定为Object) class Child3<T,T1> extends Father{ T1 t2; @Override public void test(Object t) { //类型擦除即默认为Object类型 this.name.getClass();//返回Object类型 } }
-
-
错误:不能子类擦除,父类|接口泛型
-
示例
//子类擦除后,在实例化的时候无法为泛型父类指定类型,造成编译错误 class Child4 extends Father<T,T1>{ @Override public void test(Object t) { this.name.getClass();//无法确定类型 } }
-
-
-
注意:擦除统一使用Object对待
-
规则:
- 要么同时擦除,要么子类多于等于父类的类型,
- 不能子类擦除,父类泛型
属性类型
- 在父类中定义,随父类而定
- 在子类中定义,随子类而定
方法重写
- 随被重写的方法所在类而定/随父类而定
泛型擦除
泛型的擦除,即统一为Object对待
- 继承|实现声明不指定类型
- 使用时不指定类型
- 编译器警告时可以用Object来消除,不过很多余
- 不完全等同于Object ,编译器不会进行类型检查
类型擦除
public static void main(String[] args) {
//使用时不指定类型--擦除,编译时不会进行类型检查,但会发出警报
Student stu1=new Student();
//通过指定类型可以消除警报,泛型编译时会进行类型检查
Student<Object>stu=new Student<Object>();
*
//擦除后,不会进行类型检查
test(stu1);
*
//stu类型为Student<Object>
//参数要求传入类型为Student<Integer>
//test(stu);//类型检查不适配,报错
*
test1(stu1);
test1(stu);
}
public static void test(Student<Integer> a) {
//要求传入参数为Student<Integer>
//拒绝Stu<Object>,因为类型检查不一致,Object不能对应Integer
//不拒绝Stu1,因为Student<Integer> a=new Student(),不声明-擦除
}
public static void test1(Student<?> a) {
//接收任意类型参数的Student
}
}
泛型深入2
泛型没有多态
-
采用某个基类为参数类型时,不能使用该基类的子类进行替代。
-
多态的两种形式
public class Fruit {}//基类 class Apple extends Fruit{}//派生类 public class FruitApp { public static void main(String[] args) { Fruit a=new Apple(); test(new Apple()); } //形参使用多态 public static void test(Fruit f) { } //返回类型使用多态 public static Fruit test2() { return new Apple(); } }
-
泛型类中尝试使用多态
public class App { public static void main(String[] args) { //A<Fruit>和A<Apple>没有继承关系,不可以使用多态 // A<Fruit>f=new A<Apple>(); A<Fruit>f=new A<Fruit>(); //test(new A<Apple>()); } //形参使用多态 public static void test(A<Fruit> f) {} //返回类型使用多态 public static A<Fruit> test2() { //return new Apple(); return null; } }
通配符
-
通配符:? extends super
-
可以用在声明类型及声明方法参数上,不能用在声明类上
- 只能用在声明类型上,使用(实例化)时不能使用
- 左边声明时可以使用问号,实例化时不能使用问号
Student<?>stu=new Student<String>();
- 左边声明时可以使用问号,实例化时不能使用问号
- 只能用在声明类型上,使用(实例化)时不能使用
-
?可以接收泛型的任意类型
-
//报错,适配?extends Fruit的所有类型都适配通配符--->? public static void test(Student<?>stu) {} public static void test(Student<? extends Fruit>stu) {}
-
-
? extends 泛型上限<=
-
? super 泛型下限>=
泛型通配符示例
public class Student
{ T score; public static void main(String[] args) { //左边声明时可以使用问号,实例化时不能使用问号 Studentstu=new Student (); test(new Student ()); test2(new Student ()); //test3(new Student ());//泛型没有多态 //test4(new Student ()); //test4(stu);//不能接收Student test4(null);// test4(new Student -
泛型嵌套
- 声明:嵌套使用泛型
- A<B
> a=new A<B >();
- A<B
- 使用:从外到内,一层层拆分
- 稍微复杂一些,与调用没有任何的关系,只是确定了类型而已
- 话句话说就是泛型里面用了泛型,在实例化的时候需要一一指定。
Jack<Student<String>>room =new Jack<Student<String>>();
泛型与数组
-
没有泛型数组,不能创建泛型数组
-
可以只有声明,可以使用?
-
示例
/* * 没有泛型数组 * 声明可以使用,但是无法创建 */ public class Array { public static void main(String[] args) { Integer[]arr=new Integer[4]; // 声明可以使用,但是实例化部分报错 // Student<String>[]arr2=new Student<String>[10]; //声明可以使用,实例化时擦除泛型才能通过编译 Student<?>[]arr2=new Student[10]; Student<String>[]arr1=new Student[10]; arr1[0]=new Student<String>(); //没有泛型数组,但是想要指定元素为某个类型时怎么办? //在类中进行强制转换 MyArrayList<String>strList=new MyArrayList<String>(); strList.add(0, "a"); String elem=strList.getEle(0); System.out.println(elem); // } } class MyArrayList<E>{ //E[] cap=new Object[10];没有泛型数组 Object[] cap=new Object[10]; public void add(int idx,E e) { cap[idx]=e; } @SuppressWarnings("unchecked") public E[] getAll() {//返回数组 return (E[]) cap; } @SuppressWarnings("unchecked") public E getEle(int idx){ return (E)cap[idx]; } }
JDK7泛型改进
- 在声明是使用了泛型,实例化时可以省略表达式
List<String>list=new List<>();
低维所布之火种,即我升维之觉醒。