学习笔记-泛型

泛型基础知识

泛型类

  • 类签名中包含泛型的类

  • 位置:类名后

  • 注意:

    1. 泛型只能使用引用类型,不能使用基本类型
    2. 不能再静态属性上使用泛型声明
    泛型类
    
    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) {
    		//使用时指定类型(引用类型)
    		Studentstu=new Student();
    		//1,安全:指定类型之后,在编译期间会自动检查类型,排除类型错误
    		stu.setJavaScore("优秀");
    		//2,省心:优化掉强制转换的步骤
    		int it=stu.getOracleScore();
    	}
    }

泛型接口

  • 签名中包含泛型的接口
  • 位置:接口名后
  • 不能将静态属性声明为泛型,而接口内的属性默认为静态属性
  • 接口只在方法上应用泛型
泛型接口

public interface Comparator {
	//接口不能采用泛型属性
	//T a=2;
	void compare(T t);
}

泛型方法

  • 签名中包含泛型的方法

  • 位置:返回类型前

  • 注意

    1. 编写泛型方法时,泛型未指定,该类型默认为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类型的方法
        	}
    2. 或者给泛型设定边界,该类型默认为该边界

      • 有边界泛型
        
            public staticvoid 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对待

  • 规则:

    1. 要么同时擦除,要么子类多于等于父类的类型,
    2. 不能子类擦除,父类泛型

属性类型

  1. 在父类中定义,随父类而定
  2. 在子类中定义,随子类而定

方法重写

  • 随被重写的方法所在类而定/随父类而定

泛型擦除

泛型的擦除,即统一为Object对待

  • 继承|实现声明不指定类型
  • 使用时不指定类型
  1. 编译器警告时可以用Object来消除,不过很多余
  2. 不完全等同于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

    1. 可以用在声明类型及声明方法参数上,不能用在声明类上

      • 只能用在声明类型上,使用(实例化)时不能使用
        • 左边声明时可以使用问号,实例化时不能使用问号
          Student<?>stu=new Student<String>();
    2. ?可以接收泛型的任意类型

      • //报错,适配?extends Fruit的所有类型都适配通配符--->?
        public static void test(Student<?>stu) {}
        public static void test(Student<? extends Fruit>stu) {}
        
    3. ? extends 泛型上限<=

    4. ? 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

泛型嵌套

  1. 声明:嵌套使用泛型
    • A<B> a=new A<B>();
  2. 使用:从外到内,一层层拆分
    • 稍微复杂一些,与调用没有任何的关系,只是确定了类型而已
    • 话句话说就是泛型里面用了泛型,在实例化的时候需要一一指定。
    • 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<>();
posted @ 2021-03-30 17:59  破晓云鸿  阅读(45)  评论(0编辑  收藏  举报