JAVA泛型深入学习理解

1、为什么要有泛型                                                           

集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的 对象,所以在JDK1.5   前只能把元素类型设计为ObjectJDK1.5之后使用泛型来 解决。因为这个时候除了元素的类型不确定, 其他的部分是确定的,例如关于 这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计 成一个 参数,这个类型参数叫做泛型。  Collection ListArrayList 这个就 是类型参数,即泛型。

在集合中, Java加上泛型就可以让元素类型更安全,避免出现异常ClassCastException

1.1 什么是泛型

所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类 型或者是某个方法的返回值 及参数类型。这个类型参数将在使用时(例如,   继承或实现这个接口,用这个类型声明变量、创建对象 时)确定(即传入实 际的类型参数,也称为类型实参)。

2、使用泛型

我们在前面接触到泛型,都是用的是集合中的泛型,没有其余的地方使用到泛型

2.1 在集合中使用泛型                                                                      

  在集合中使用泛型

    public void test1() {
        List<String> list = new ArrayList<String>();
        list.add("String"); // 安全类型    
        list.add(123); // 编译错误,类型不一致
    }

  Map中使用泛型

public void test2() {
        Map<String, Human> map = new HashMap<String, Human>();
        map.put("String", new Huamn("Hello", 123));
        map.put("String", new Obejct());  // 会发生错误,类型不一致,数据安全 
            }

3、泛型自定义

3.1 自定义泛型                                                                                

3.1.1 泛型的声明                                                                                                   

  jdk8举例

// List
public interface List<E> extends Collection<E>{}
// Map
public interface Map<K,V> {}

说明,其中E K V 都是代表一个类型,不是具体类型,只要是变量就可以 

3.1.2 泛型的实例化                                                                                               

  在类名后面指定类型参数(泛型)

List<Sting> list=new ArrayList<String>();
Set<String> set=new HashSet();//1.7之后加的

    说明,  <> 一对尖括号中只能放置引用数据类型,非基本数据类型

3.2 定义泛型类/接口                                                                        

3.2.1 特点说明和举例                                                                                            

  泛型类可以有多个参数,放在同一个尖括号内,用" " 隔开

/*
    L,U 类型参数
**/
 public class Calculator<L,U> {
    }

构造方法不含有尖括号

public class Order<E> {
    List<E> productions = new ArrayList<>();
    public void setProductions(List<E> productions) {
    this.productions = productions;
    }

public List<E> getProductions() {
    return productions;
}

public Order() {
    }
}

创建对象之后,泛型位置要和指定的泛型一致

public void test4() {
        Order<Computer> order = new Order<>();
        List<String> list = new ArrayList<>();
        order.setProductions(list); // 这个位置会发生错误
    }

泛型之间不能互相赋值

public void test5() {
    Order<Computer> order=new Order<>();
    Order<Human< order1=new Order<>();
  //order=order1; 会发生错误
    Order<Human> humanOrder = new Order<>();
    Order<Student> studentOrder = new Order<>();
 //    humanOrder = studentOrder; // 会发生错误
       Order<Student> studentOrder1 = new Order<>();
       studentOrder1 = studentOrder; // 没有错误,赋值的时候,需要保持泛型一致
       Human student = new Student();
}

若不指定泛型则会被擦除(不指定泛型,就会Object)

public void test6() {
        List<Integer> list = new ArrayList<>();
        list.add(123);
        List llist1 = new ArrayList(); //
        llist1.add(new Object()); // 如果不指定类型就会将泛型位置的类型变为Object                                   llist1.add(new Human());// 向上转型
//  Employee[] employees = new Employee[10];
// employees[0] = new GeneralEmployee(); // 向上转型,在泛型中也同样适用
    }

泛型结构若是抽象的,则不可以创建对象(实例)

public void test7() {
        Employee<Computer> employee = new Employee<Computer>() {
        // new Employee<Computer>()
        // 这个位置的Computer不能被省略
    };
InterGeneric<Computer> interGeneric = new InterGeneric<Computer>() {};
// 匿名泛型类不可以省略泛型的内容,也就是不能使用菱形语法
// 但是可以完全省略泛型
    }

简化操作<>

1.7 之后可以使用菱形语法

  创建对象时,不能放基本数据类型

  在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态 属性的类型、非静

态方法的参数类型、非静态方法的返回值类型。但在静态方法 中不能使用类的泛型。

// 泛型类或接口在使用静态方法时,不允许指定泛型
// 只有在创建对象时才可以指定泛型

  异常不能带泛型

不能使用new E[]。但是可以:  E[] elements = (E[])new Object[capacity]; Object[] elementData;

public List<E> getProductions() {
        new E[123]; // 有错误
        new E();// 有错误


        E[] es = (E[])new Computer[123]; // 没有错误
        E e = (E) new Computer(); // 没有错误
        E e1 = (E) new Object(); // 没有错误

        return productions;
}

  父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:

              子类不保留父类的泛型:按需实现

                  没有类型 擦除

                  具体类型

  子类保留父类的泛型:泛型子类

                  全部保留,要注意,保留的泛型写法上字母要和父类的一致

                  部分保留

  结论:子类除了指定或保留父类的泛型,还可以增加自 己的泛型

3.3 定义泛型方法                                                                             

  单独一个方法也可以被泛型化,无论此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛

型参数,此时,参数的类型就是传入数据的类型。

  泛型方法的格式:

   [访问权限] <泛型> 返回类型 方法名([泛型 参数名称]) 抛出的异常

  举例

代码

public static <T> List<T> arrayToList(T[] array) {
         List<T> list = new ArrayList<>();
            for (T t : array) {
            list.add(t);
                }
            return list;
    }

4、继承

说明:泛型是泛型,类是类,泛型类是泛型类

  @Test
  public void test1() {
      List<Human> humanList = new ArrayList<>();
      List<Student> students = new ArrayList<>(); 5      /*
             List<Human> 和List<Student>都是List, 这两个之前没有继承关系
             humanList = students 是错误的 8       */
      }

5、通配符

?父类类型,只读,返回 Object ,不能写入对象,但能写入 null
List<?> List List 的父类类型
public void test2() { 
     List<?> list = new ArrayList<>();
     List<Human> humanList = new ArrayList<>();
     List<Student> students = new ArrayList<>(); 
     list = humanList; // 正确 list = students; // 正确
 // list.add(new Student()); 错误
 // list.add(new Object()); 错误 
    int size = list.size();
     System.out.println("size = " + size); 
     list.add(null); size = list.size();
     System.out.println("size = " + size); }
    public static void test(List<?> list) { 
        // List<?> 只读状态,不能插入元素,但可以插入null 
        // List<?> 其实就相当于List<任意一个类型>的父类了 
        }
上限
上限 extends :使用时指定的类型必须是继承某个类,或者实现某个接口,即 <=
下限
下限 super :使用时指定的类型不能小于操作的类,即 >=
注意:添加元素的时候,考虑的是多少的问题,赋值的时候,考虑父子关系
public static void testExtends(List<? extends Person> list) { 
    Person human = list.get(0); 
}
public static void testSuper(List<? super Person> list) {
    Object object = list.get(0);
 }
@Test
 public void test2() { 
         List<? super Person> list = new ArrayList<>();
         list.add(new Person()); 
         list.add(new Student());
         List<Human> humanList = new ArrayList<>();
         humanList.add(new Human());
         humanList.add(new Human()); 
         humanList.add(new Human()); 
         testSuper(humanList);
}
@Test 
public void test1() {
     List<? extends Human> list = new ArrayList<>();
     // (-∞, Human]
     list.add(null); 

     List<Person> personList = new ArrayList<>();
     List<Student> studentList = new ArrayList<>();

     testExtends(personList);
     testExtends(studentList); 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值