Java学习之泛型

泛型是实现对参数的灵活管理.使得参数由具体类型变成无形类型.也可变成约束范围内的类型.使得类,方法,接口更加的灵活多变.

泛型的使用:第一步先声明,第二步声明后就可以调用指的是在编译和运行是使用

声明规范<泛型标识:可以随便写任意标识号,标识指定的泛型的类型>

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{ 
    //key这个成员变量的类型为T,T的类型由外部指定  
    private T key;

    public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
        this.key = key;
    }

    public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
        return key;
    }
}

1,泛型类:即在类名位置声明,上面的例子就是泛型类,类中声明后,在类里面的方法中就可以使用声明的泛型标识.

2,泛型方法:即在方法返回类型前声明泛型标识

/** 
     * 这是一个真正的泛型方法。
     * 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T
     * 这个T可以出现在这个泛型方法的任意位置.
     * 泛型的数量也可以为任意多个 
     *    如:public <T,K> K showKeyName(Generic<T> container){
     *        ...
     *        }
     */
    public <E> E showKeyName(Generic<T> container){
        System.out.println("container key :" + container.getKey());
        //当然这个例子举的不太合适,只是为了说明泛型方法的特性。
        T test = container.getKey();
        return test;
    }

3,泛型接口和泛型类差不多.都是在接口名上声明

//定义一个泛型接口
public interface Generator<T> {
    public T next();
}
实现类也要继承接口的泛型类型
/**
 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
 * 即:class FruitGenerator<T> implements Generator<T>{
 * 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
 */
class FruitGenerator<T> implements Generator<T>{
    @Override
    public T next() {
        return null;
    }
}

总结:用泛型作用:

1,类型安全性(Type safety):一旦使用类型参数后,在该方法或框架中就不存在其他的数据类型,同时也避免了类型转化的需求.

2,类型多样化,使得泛型类,接口,方法,可以实现参数多样化.

3,泛型使用后,规范类型主要是通过编译过程,如果不符合泛型规范,会编译报错,在运行过程是不参与规范的.

通配符?

使用规则:通配符一般是表示容器类型参数的,只能用在方法的参数列表模块或引用类型的参数模块,接收的是一个不确定的类.

作用:与泛型的作用类型起到类型管理的规范作用,调用时在编译过程起到约束作用,不符合通配符规范会编译报错

和Object区别如果只用"?"那么它和Object是一样的,但是"?"有比Object稍微“高级”有点的用法,就是它能缩小一个不确定的范围,利用类似"? extends Test",这就意味着只接收接收Test类的继承类,是不是比Object的范围缩小了?


List<?>:无边界通配符:接收的不知道是属于什么类型的list

List<? extends  E>:上界通配符:接收的类型是继承父类E的子类的list

List<? super E>:下界通配符:接收的类型是属于E类型父类的list,E是子类

使用案例:https://www.cnblogs.com/zhenyu-go/p/5536667.html

该链接有具体的不同通配符使用案例,很详细,大家可以看看


总结:通配符就是用来修饰方法的参数类型的.当函数里调用有通配符修饰的方法时,传入的参数必须满足通配符的约束规范,否则会报编译错误;

        //通配符修饰的方法参数
	public static void addNumbers(List<? super Integer> list) {
	    for (int i = 1; i <= 10; i++) {
	        list.add(i);
	    }
	}

	public static void main(String[] args) {
	    List<Object> list1 = new ArrayList<>();
	    addNumbers(list1);
	    System.out.println(list1);
	    List<Number> list2 = new ArrayList<>();
	    addNumbers(list2);
	    System.out.println(list2);
	    List<Double> list3 = new ArrayList<>();
	    // addNumbers(list3); // 编译报错
	}


自在在学习的时候突然想到Object和泛型的区别.因为在参数设置时,参数为Object时,就意味着Java中所有类型都能被接收下面的例子可以看出是支持所有类型

//定义一个接收Object参数的方法
public static Object release(Object obj){
		return obj;
	}
               release(1);
		release("22");
		release(new HashMap());

下面是泛型的使用:泛型也使得方法内参数都支持各种类型.

public class FanxinObject<T> {
	
	public  T set(T t){
		return t;
	}
	
	public static void main(String[] args) {
		FanxinObject fo=new FanxinObject();
		fo.set(1);
		fo.set("asd");
		fo.set(new HashMap());
	}
}

通过学习自己总结出泛型之所以存在是有原因的:

1,从功能上来说object是灵活可以接收任何参数,但它却无法去规范化,应用过程中容易产生类型转化异常.而泛型是可以设定具体参数类型的,让参数约束化,可具体到某种类型也可具体到某种范围内,

public static void main(String[] args) {
		//当加入泛型规范为String时,该方法就只能传入String了
		FanxinObject<String> fo=new FanxinObject<String>();
		fo.set(1);//此处编译报错
		fo.set("asd");
		fo.set(new HashMap());//此处编译报错
	}

从举例中可以看出泛型更加灵活,且可以避免类型转化问题.




猜你喜欢

转载自blog.csdn.net/zxf_0601/article/details/80271604