java 3y 泛型就这么简单

泛型方法

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的T)。
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
     
//定义泛型方法, 类型参数声明部分在方法返回类型之前
public <T> void show(T t) {
    System.out.println(t);
}

//多个类型参数
public class testooo {
    public static <T, V> void s(T t, V v, int a) {
        System.out.println(t);
        System.out.println(v);
    }

    public static void main(String[] args) {
        testooo.s(1, 2, 3);
    }
}

 

泛型类是拥有泛型这个特性的类,它本质上还是一个Java类,那么它就可以被继承

那它是怎么被继承的呢??这里分两种情况

  1. 子类明确泛型类的类型参数变量
  2. 子类不明确泛型类的类型参数变量
     

子类明确泛型类的类型参数变量

/*
    把泛型定义在接口上
 */
public interface Inter<T> {
    public abstract void show(T t);

}
/**
 * 子类明确泛型类的类型参数变量:
 */

public class InterImpl implements Inter<String> {
    @Override
    public void show(String s) {
        System.out.println(s);

    }
}

 

子类不明确泛型类的类型参数变量

当子类不明确泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在实现类上需要定义出类型参数变量
 

/**
 * 子类不明确泛型类的类型参数变量:
 *      实现类也要定义出<T>类型的
 *
 */
public class InterImpl<T> implements Inter<T> {

    @Override
    public void show(T t) {
        System.out.println(t);

    }
}
public static void main(String[] args) {
    //测试第一种情况
    //Inter<String> i = new InterImpl();
    //i.show("hello");

    //第二种情况测试
    Inter<String> ii = new InterImpl<>();
    ii.show("100");
}

 

1.实现类的要是重写父类的方法,返回值的类型是要和父类一样的
2.类上声明的泛形只对非静态成员有效,这一点说明如下
 

#1.泛型类中的静态方法不能使用类的泛型,而应该将该方法定义为泛型方法
1.错误示范:

class demo<T>{
    public static T show(T temp) {
        return temp;
    }
}
2.正确示范:

class demo<T>{
    public static <T> T show(T temp) {
        return temp;
    }
}
3.原因:

   在java中泛型只是一个占位符,必须在传递类型后才能使用。就泛型类而言,类实例化时才能传递真正的类型参数,
由于静态方法的加载先于类的实例化,也就是说类中的泛型还没有传递真正的类型参数时,静态方法就已经加载完成。
显然,静态方法不能使用/访问泛型类中的泛型。

这和静态方法不能调用普通方法/访问普通变量类似,都是因为静态申明与非静态申明的生命周期不同。

 

#2.不能定义静态泛型变量
1.原因:

由于静态变量在java程序一运行时就已经被载入内存,而此时它的类型无法确定,而开辟空间必须知道类型,两者矛盾。
————————————————
版权声明:本文为CSDN博主「SWEENEY_HE」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/SWEENEY_HE/article/details/88615836

   

类型通配符

 

public void test(List<Object> list){
   for(int i=0;i<list.size();i++){
       System.out.println(list.get(i));
   }
}

该test()方法只能遍历装载着Object的集合!!!
泛型中的<Object>并不是像以前那样有继承关系的,也就是说List<Object>和List<String>是毫无关系的

 
改为?

public void test(List<?> list){
    for(int i=0;i<list.size();i++){
        System.out.println(list.get(i));
    }
}

 
?号通配符表示可以匹配任意类型,任意的Java类都可以匹配…..
现在非常值得注意的是,当我们使用?号通配符的时候:就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。
记住,只能调用与对象无关的方法,不能调用对象与类型有关的方法。
 

设定通配符上限

现在,我想接收一个List集合,它只能操作数字类型的元素【Float、Integer、Double、Byte等数字类型都行】,怎么做???
我们学习了通配符,但是如果直接使用通配符的话,该集合就不是只能操作数字了。因此我们需要用到设定通配符上限 

List<? extends Number>

设定通配符下限

//传递进来的只能是Type或Type的父类
<? super Type>

 

使用中

  • 大多时候,我们都可以使用泛型方法来代替通配符的
  • 如果参数之间的类型有依赖关系,或者返回值是与参数之间有依赖关系的。那么就使用泛型方法
  • 如果没有依赖关系的,就使用通配符,通配符会灵活一些.
     

泛型擦除

  • 泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
  • JDK5提出了泛型这个概念,但是JDK5以前是没有泛型的。也就是泛型是需要兼容JDK5以下的集合的。
  • 当把带有泛型特性的集合赋值给老版本的集合时候,会把泛型给擦除了。
     
    值得注意的是:它保留的就类型参数的上限。
List<String> list = new ArrayList<>();
//类型被擦除了,保留的是类型的上限,String的上限就是Object
List list1 = list;
如果我把没有类型参数的集合赋值给带有类型参数的集合赋值,这又会怎么样??
List list = new ArrayList();
List<String> list2 = list;
它也不会报错,仅仅是提示“未经检查的转换
posted @ 2020-03-29 21:30  种树人  阅读(250)  评论(0编辑  收藏  举报