Java基础----集合(3)泛型

xiaoxiao2021-02-28  15

1、泛型的概述

        泛型是Java SE 1.5的新特性,泛型是一种特殊的类型,它把指定类型的工作推迟到客户端代码声明并实例化类或方法的时候进行。

    也被称为参数化类型,可以把类型当作参数一样传递过来,在传递过来之前我不明确,但是在使用的时候我就用明确了。

2、泛型的由来

   在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

3、泛型的好处

 * 在编译的时候检查类型安全提高了程序的安全性;

 * 将运行期遇到的问题转移到了编译期;

 * 省去了类型强转的麻烦,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

4、泛型的应用

   可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

1) 泛型类:把泛型定义在类上

   格式: public class 类名<泛型类型1,…>

   注意: 泛型类型必须是引用类型,在实例化泛型类时,必须指定 T 的具体类型。

   案例演示:

   我们先定义一个Modle类,成员变量有一个String类型的元素 elements,如下:

  

public class Model { private String elements; public void setElements(String elements){ this.elements=elements; } public String getElements(){ return this.elements; } }

   但是,如果这样写的话,Model里面现在只能装入String类型的元素,今后如果我们需要装入Integer等其他类型的元素,还必须要另外重写一个Model,代码得不到复用,使用泛型可以很好的解决这个问题。如下:

  

public class Model<T> { private T elements; public Model() { } public Model(T elements) { //泛型构造方法 this.elements = elements; } public void setElements(T elements){ this.elements=elements; } public T getElements(){ //不是一个泛型方法,只是使用了泛型类的一个变量,返回值类型为 T, return this.elements; } }

   这样,我们的Model方法就可以实现代码的复用,只需要在测试类中创建自己想要的任意类型的对象了。如下:

  

public class Test1 { public static void main(String[] args) { Model<String> model = new Model<>(); Model<Integer> model2 = new Model<>(); Model<String> stringModel = new Model<>("123"); Model<Integer> integerModel = new Model<>(123); } }

2) 泛型方法:把泛型定义在方法上

  A: 格式: public<泛型类型> 返回类型方法名(泛型类型 ...)

     注意:泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型  

  B: 说明:       (1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。       (2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。       (3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。      (4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。

    C: 几种不是泛型方法的例子

      

//这是一个泛型类 public class Model<T>{ private T elements; public Model() { } public Model(T elements) { this.elements = elements; } //1、不是泛型方法 public void setElements(T elements){ this.elements=elements; } //2、不是一个泛型方法,只是使用了泛型类的一个变量,返回值类型为 T, public T getElements(){ return this.elements; } //3、只是使用了泛型类做形参 public void showModel(Model<T> a){ System.out.println(a.elements); } //4、只是使用了泛型通配符 public void showMode2(Model<?> a){ System.out.println(a.elements); } //5、并没有在泛型类中定义 类型 E,会报错 // public E setElements(E elements){ // this.elements=elements; // } }

   D:泛型方法需要注意到的几点

  

public class Model<T> { private T elements; public Model() { } public Model(T elements) { this.elements = elements; } //1、在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。 //由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。 public <E> void show_1(E e){ System.out.println(e.toString()); } //2、在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。 public <T> void show_2(T t){ System.out.println(t.toString()); } }

  //测试类

  

public class Test { public static void main(String[] args) { Model<String> model = new Model<>(); model.show_1(123); model.show_2(false); } }

 3) 泛型接口:把泛型定义在接口上(和泛型类类似)

   格式:public  interface 接口名<泛型类型1…>

   定义一个泛型接口:

  

public interface MyInterface<M> { M set(M str); }

  定义一个泛型类,实现该泛型接口:

   

public class MyClass<M> implements MyInterface<M>{ @Override public M set(M str) { return null; } }

  注意:未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中

        即:class MyClass<M> implements MyInterface<M>{}

        如果不声明泛型,如:class MyClass implements MyInterface<M>

        编译器会报错:"Unknown class"

5、泛型的通配符号

   泛型通配符<?>: 任意类型,如果没有明确,那么就是Object以及任意的Java类了。

6、向上限定、向下限定

  1) ? extends E

     向下限定,E及其子类

  2) ? super E

     向上限定,E及其父类

 

class Animal<T>{ } class Dog extends Animal{ } class Cat extends Animal{ }

   测试类:

    

public class MyTest { public static void main(String[] args) { //泛型的通配符号 // A:泛型通配符<?>:任意类型,如果没有明确,那么就是Object以及任意的Java类了 Animal<?> animal=new Animal<Dog>(); //向上限定 // ? super E:向上限定,E及其父类 Animal<? super Dog> animal1=new Animal<Animal>(); //向下限定 // ? extends E:向下限定,E及其子类 Animal<? extends Animal> animal2=new Animal<Cat>(); } }

7、可变参数

1) 可变参数概述

   定义方法的时候不知道该定义多少个参数,可以使用可变参数。

2) 格式

   修饰符返回值类型 方法名(数据类型…  变量名){}

3) 注意:

   这里的变量其实是一个数组

   如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个

例:

 

public class MyTest2 { public static void main(String[] args) { //JDK1.5 之后有一个可变参数 int a = 1; int b = 2; double add = add(1, 3); double add1 = add(1, 3, 2); double add2 = add(2, 6, 9, 8); System.out.println(add); System.out.println(add1); System.out.println(add2); } //注意如果有多个参数 ,那可变参数放到最后 public static double add(double ... b) { //可变参数的本质是个数组 System.out.println(b.length); int sum=0; for(double num:b){ sum+=num; } return sum; } }

转载请注明原文地址: https://www.6miu.com/read-1750034.html

最新回复(0)