Java知识点总结之Java泛型

作者:苏生 链接: https://segmentfault.com/a/1190000014824002

泛型

泛型就是参数化类型

  • 适用于多种数据类型执行相同的代码
  • 泛型中的类型在使用时指定
  • 泛型归根到底就是“模版”

优点:使用泛型时,在实际使用之前类型就已经确定了,不需要强制类型转换。

泛型主要使用在集合中

import java.util.ArrayList;
import java.util.List;

public class Demo01 {

  // 不使用泛型,存取数据麻烦
  public static void test1(){
    List  list = new ArrayList();
    list.add(100);
    list.add("zhang");
    /*
     * 从集合中获取的数据是Object类型,Object类型是所有类型的根类,但是在具体使用的时候需要
     * 类型检查,类型转化,处理类型转化异常
     * 使用麻烦
     */
    Object o = list.get(1);
    if (o instanceof String) {
     String s = (String)o;
    }
    System.out.println(o);
  }

  // 使用泛型
  public static void test2(){
    List<String> list = new ArrayList<String>();
    //list.add(100); 放数据时安全检查,100不是String类型,不能存放
    list.add("存数据安全,取数据省心");
    String s = list.get(0); //取出来的数据直接就是泛型规定的类型
    System.out.println(s);

  }

  public static void main(String[] args) {
    test1();
    test2();
  }

}

自定义泛型

泛型字母

  • 形式类型参数(formal type parameters)即泛型字母
  • 命名泛型字母可以随意指定,尽量使用单个的大写字母(有时候多个泛型类型时会加上数字,比如T1,T2) 常见字母(见名知意)
    • T Type
    • K V Key Value
    • E Element
  • 当类被使用时,会使用具体的实际类型参数(actual type argument)代替

泛型类

  • 只能用在成员变量上,只能使用引用类型

泛型接口

  • 只能用在抽象方法上

泛型方法

  • 返回值前面加上 <T>
/**
 * 自定义泛型类
 *
 * 定义"模版"的时候,泛型用泛型字母:T 代替
 * 在使用的时候指定实际类型
 *
 * @author Administrator
 * @param <T>
 */
public class Student<T> {

  private T javase;

  //private static T javaee;   // 泛型不能使用在静态属性上

  public Student() {
  }

  public Student(T javase) {
    this();
    this.javase = javase;
  }

  public T getJavase() {
    return javase;
  }

  public void setJavase(T javase) {
    this.javase = javase;
  }

}
/**
 * 自定义泛型的使用
 * 在声明时指定具体的类型
 * 不能为基本类型
 * @author Administrator
 *
 */
class Demo02 {
  public static void main(String[] args) {
    //Student<int>  Student = new Student<int>(); //不能为基本类型,编译时异常

    Student<Integer> student = new Student<Integer>();
    student.setJavase(85);
    System.out.println(student.getJavase());  
  }
}
/**
 * 自定义泛型接口
 *
 * 接口中泛型字母只能使用在方法中,不能使用在全局常量中
 *
 * @author Administrator
 * @param <T>
 */
public interface Comparator<T1,T2> {

  //public static final T1 MAX_VALUE = 100; //接口中泛型字母不能使用在全局常量中
  //T1 MAX_VALUE;
  public static final int MAX_VALUE = 100;

  void compare(T2 t);
  T2 compare();
  public abstract T1 compare2(T2 t);
}
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;


/**
 * 非泛型类中定义泛型方法
 * @author Administrator
 *
 */
public class Method {

  // 泛型方法,在返回类型前面使用泛型字母
  public static <T> void test1(T t){
    System.out.println(t);
  }

  // T 只能是list 或者list 的子类
  public static <T extends List> void test2(T t){
    t.add("aa");
  }

  // T... 可变参数   --->   T[]
  public static <T extends Closeable> void test3(T...a) {
    for (T temp : a) {
     try {
       if (null != temp) {
         temp.close();
       }
     } catch (Exception e) {
       e.printStackTrace();
     }

    }
  }

  public static void main(String[] args) throws FileNotFoundException {
    test1("java 是门好语言");
    test3(new FileInputStream("a.txt"));
  }
}

泛型的继承

/**
 * 泛型继承
 *
 * 保留父类泛型 ----》泛型子类 
 * 不保留父类泛型 -----》子类按需实现
 *
 * 子类重写父类的方法,泛型类型随父类而定 子类使用父类的属性,该属性类型随父类定义的泛型
 *
 * @author Administrator
 *
 * @param <T1>
 * @param <T2>
 */
public abstract class Father<T1, T2> {
  T1 age;

  public abstract void test(T2 name);
}

// 保留父类泛型 ----》泛型子类
// 1)全部保留
class C1<T1, T2> extends Father<T1, T2> {

  @Override
  public void test(T2 name) {

  }
}

// 2) 部分保留
class C2<T1> extends Father<T1, Integer> {

  @Override
  public void test(Integer name) {

  }
}

// 不保留父类泛型 -----》子类按需实现
// 1)具体类型
class C3 extends Father<String, Integer> {

  @Override
  public void test(Integer name) {

  }
}

// 2)没有具体类型
// 泛型擦除:实现或继承父类的子类,没有指定类型,类似于Object
class C4 extends Father {

  @Override
  public void test(Object name) {

  }

}
/**
 * 泛型擦除
 * 类似于Object,不等于Object
 * @author Administrator
 *
 */
public class Demo03 {

  public static void test(Student<Integer> student){
    student.setJavase(100);
  }

  public static void main(String[] args) {
    // 泛型擦除
    Student student = new Student();
    test(student);

    Student<Object> student2 = new Student<Object>();
    //test(student2);  //编译异常
  }

}

通配符

通配符(Wildcards)

  • T、K、V、E 等泛型字母为有类型,类型参数赋予具体的值
  • ?未知类型 类型参数赋予不确定值,任意类型
  • 只能用在声明类型、方法参数上,不能用在定义泛型类上
/**
 * 泛型的通配符 类型不确定,用于声明变量或者形参上面
 *
 * 不能使用在类上 或者  new 创建对象上
 * @author Administrator
 *
 */
public class Demo04 {

  // 用在形参上
  public static void test(List<?> list) {

   List<?> list2; // 用在声明变量上
   list2 = new ArrayList<String>();
   list2 = new ArrayList<Integer>();
   list2 = new ArrayList<Object>();

  }

  public static void main(String[] args) {
   test(new ArrayList<String>());
   test(new ArrayList<Integer>());
  }

}

extends/super

上限(extends)

指定的类必须是继承某个类,或者实现了某个接口(不是implements),即<=

  • ? extends List

下限(super)

即父类或本身

  • ? super List
import java.util.ArrayList;
import java.util.List;

/**
 * extends:泛型的上限 <= 一般用于限制操作 不能使用在添加数据上,一般都是用于数据的读取
 *
 * supper:泛型的上限 >= 即父类或自身。一般用于下限操作
 *
 * @author Administrator
 * @param <T>
 */

public class Test<T extends Fruit> {

  private static void test01() {
    Test<Fruit> t1 = new Test<Fruit>();
    Test<Apple> t2 = new Test<Apple>();
    Test<Pear> t3 = new Test<Pear>();
  }

  private static void test02(List<? extends Fruit> list) {

  }

  private static void test03(List<? super Apple> list) {

  }

  public static void main(String[] args) {

    // 调用test02(),测试 extends  <=
    test02(new ArrayList<Fruit>());
    test02(new ArrayList<Apple>());
    test02(new ArrayList<ReadApple>());
    // test02(new ArrayList<Object>()); Object 不是 Fruit 的子类 ,编译不通过


    // 调用test03() ,测试super >=
    test03(new ArrayList<Apple>());
    test03(new ArrayList<Fruit>());
    //test03(new ArrayList<ReadApple>());  ReadApple < apple,所以不能放入
  }

}

class Fruit {

}

class Apple extends Fruit {

}

class Pear extends Fruit {

}

class ReadApple extends Apple {

}

泛型嵌套

从外向里取

import java.util.Map.Entry;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 泛型嵌套
 * @author Administrator
 *
 */
public class Demo05 {


  public static void main(String[] args) {
    Student2<String> student = new Student2<String>();
    student.setScore("优秀");
    System.out.println(student.getScore());

    //泛型嵌套
    School<Student2<String>> school = new School<Student2<String>>();
    school.setStu(student);

    String s = school.getStu().getScore(); //从外向里取
    System.out.println(s);

    // hashmap 使用了泛型的嵌套
    Map<String, String> map =  new HashMap<String,String>();
    map.put("a", "张三");
    map.put("b", "李四");
    Set<Entry<String, String>> set = map.entrySet();
    for (Entry<String, String> entry : set) {
     System.out.println(entry.getKey()+":"+entry.getValue());
    }

  }
}
public class School<T> {
  private T stu;

  public T getStu() {
    return stu;
  }

  public void setStu(T stu) {
    this.stu = stu;
  }

}
public class Student2<T> {
  T score;

  public T getScore() {
    return score;
  }

  public void setScore(T score) {
    this.score = score;
  }
}

其他

import java.util.ArrayList;
import java.util.List;

/**
 * 泛型没有多态
 * 泛型没有数组
 * JDK1.7对泛型的简化
 * @author Administrator
 *
 */
public class Demo06 {

  public static void main(String[] args) {
    Fruit fruit = new Apple();  // 多态,父类的引用指向子类的对象
    //List<Fruit> list = new ArrayList<Apple>(); //泛型没有多态 
    List<? extends Fruit> list = new ArrayList<Apple>();

    //泛型没有数组
    //Fruit<String>[] fruits = new Fruit<String>[10];

    //ArrayList底层是一个Object[],它放数据的时候直接放,取数据的时候强制类型转化为泛型类型
    /*public boolean add(E e) {
          ensureCapacityInternal(size + 1);  // Increments modCount!!
          elementData[size++] = e;
          return true;
      }*/

    /*E elementData(int index) {
          return (E) elementData[index];
      }*/


    //JDK1.7泛型的简化,1.6编译通不过
    List<Fruit> list2 = new ArrayList<>();
  }
}

(完)

原文发布于微信公众号 - 精讲JAVA(toooooooozi)

原文发表时间:2018-06-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏lgp20151222

java中两个map比较

1292
来自专栏LanceToBigData

JavaSE(八)之Collection总结

  前面几篇把集合中的知识大概都详细的说了一遍,但是我觉得还是要总结一下,这样的话,可以更好的理解集合。 一、Collection接口 首先我们要一张图来说明:...

2436
来自专栏郭耀华‘s Blog

剑指offer第五天

28.数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2...

2755
来自专栏芋道源码1024

ArrayList 其实也有双胞胎,但区别还是挺大的!

这句话的意思是Collection集合类型的toArray()方法虽然声明返回值类型是Object[],但是具体调用时还真不一定就返回Onject[]类型,也有...

1284
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础(02)-15总结对象数组,集合Collection,集合List

3:集合(List)(掌握) (1)List是Collection的子接口 特点:有序(存储顺序和取出顺序一致),可重复。 package cn.itcas...

3365
来自专栏Ryan Miao

java中List对象列表去重或取出以及排序

面试碰到几次list的去重和排序。下面介绍一种做法: 1. list去重 1.1 实体类Student List<Student>容量10k以上,要求去重复。这...

8039
来自专栏java学习

Java每日一练(2017/8/17)

每日一句 学的到东西的事情是锻炼,学不到的是磨练。 查看以前的所有练习题目以及答案:https://mp.weixin.qq.com/mp/homepage?_...

2929
来自专栏java学习

Java基础总结大全(2)

四、集合框架 1:String类:字符串(重点) (1)多个字符组成的一个序列,叫字符串。 生活中很多数据的描述都采用的是字符串的。而且我们还会对其进...

3599
来自专栏LinkedBear的个人空间

唠唠SE的集合-02——Iterator迭代器

迭代时如果没有先执行next()则会抛出IllegalStateException,这就意味着必须要先检查是否还有下一个可以被迭代的元素,才能往外取。

1033
来自专栏机器学习入门

LWC 58:726. Number of Atoms

LWC 58:726. Number of Atoms 传送门:726. Number of Atoms Problem: Given a chemical ...

2585

扫码关注云+社区

领取腾讯云代金券