首页 > 代码库 > 泛型详解
泛型详解
泛型详解
泛型概述
泛型概述:限定集合存储的数据类型,Collection<E>其中E代表引用数据类型,如果加上了该引用数据类型,表示该集合中只能存储改类型对象,或者该类型的子类对象
泛型用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数传递。
泛型是数据类型的一部分,我们将类名与泛型合并一起看做数据类型。
泛型的由来
当没有指定泛型时,默认类型为Object类型。Object代表任意的数据类型(所有类都是object的子类),(返回值类型是object类型,所以用object接收,要存成其他,需要强转,代码繁琐)objext什么都可以接受,
泛型定义格式
1)泛型类:
概述
在类上定义泛型,类名后<泛型变量> class A<E> 使用:
定义格式
public class 类名<泛型类型1,…>
确定泛型
创建对象时确定具体的类型
2)泛型方法:
概述:
在方法上定义泛型.
定义格式
要在权限修饰符后面返回值类型的前面<泛型变量>
public <泛型类型> 返回类型 方法名(泛型类型 变量名)
public <T> void method(){使用T}
确定泛型
调用方法时,确定具体的数据类型
案例:
- public class Tool<Q> {//在类上定义了泛型Q,Q什么时候有值,当你用这个类时,指定了泛型是什么,Q就代表什么
- private Q q;
- public Q getObj() {
- return q;
- }
- public void setObj(Q q) {
- this.q = q;
- }
- public void write(Q q){ //write方法使用类上定义的泛型
- System.out.println(q);
- }
- public <T> void show(T t) { //方法泛型最好与类的泛型一致
- System.out.println(t); //如果不一致,需要在方法上声明该泛型
- }
- public static<W> void print(W w) { //静态方法必须声明自己的泛型
- System.out.println(w);
- }
- }
- import com.kailing.bean.Student;
- import com.kailing.bean.Tool;
- import com.kailing.bean.Worker;
- public class Demo3_Generic {
- public static void main(String[] args) {
- Tool<String> t = new Tool<>();
- //t.write("abc");
- t.show(true);
- }
- }
静态方法与非静态方法泛型:
非静态方法,对类的泛型可用可不用.
静态方法, 不能使用类的泛型,想使用泛型,必须定义自己的泛型.
因为静态方法随着类的加载而加载,在类加载后,可能还没有创建对象呢,所以此时静态方法上的泛型可能没值
在调用该静态方法时被赋值
3)泛型接口
概述
把泛型定义在接口上 如: interface B<T>{使用T完成接口定义}
定义格式:
public interface 接口名<泛型类型>
确定泛型:
1、子类在实现接口的同时,直接给出具体的泛型
- class Cat implements Fly<String> {
- public void fly(String t) {
- }
- }
2、子类继续沿用接口的泛型(其实子类就变成泛型类了),在创建子类对象的时候确定泛型
- class Cat<T> implements Fly<T> {
- public void fly(T t) {
- }
- }
泛型好处
提高安全性
将运行期的错误转换到编译期
省去强转的麻烦
优化程序设计
注意事項
泛型基本使用
<>中放的必须是引用数据类型
前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性菱形泛型)
案例一
- 泛型类:
- public class DemoType02<T> {//T是泛型变量
- //使用泛型定义成员变量
- private T field;
- public T getField() {//方法中使用到类中的泛型不是泛型方法
- return field;
- }
- public void setField(T field) {//方法中使用到类中的泛型
- this.field = field;
- }
- public static void main(String[] args) {
- 泛型类的使用过程
- //创建对象,确定泛型类型,通过对象,操作对应的数据类型
- DemoType02<String> dt2 = new DemoType02<String>();
- dt2.setField("abc");
- String field2 = dt2.getField();
- System.out.println(field2);
- }
- //泛型方法
- public <E> void method(E e) {
- System.out.println(e);
- }
- dt2.method(100);//调用后方法是integer类型
- 泛型只能是引用类型
- }
案例二
- 定义接口泛型:接口名<泛型变量>
- public interface MyInterface<T> {
- public abstract T method();
- public abstract void method(T t);
- }
- 泛型接口在定义子类时,直接指定类型
- public class MyClass4Interface implements MyInterface<String> {
- public void method(String t) {
- System.out.println("参数是字符串"+t);
- }
- }
- 泛型接口在定义子类时,没有确定数据类型.(定义了泛型子类)
- public class MyClass4Inter face2<T> implements MyInterface<T> { public void method(T t) {
- System.out.println(t);
- }
- }
- public class DemoType03 {
- public static void main(String[] args) {
- //当泛型接口在定义类时,已经确定了数据类型,则创建对象时,直接使用即可
- MyClass4Interface mc4i = new MyClass4Interface();
- mc4i.method("abc");
- 泛型使用2
- //当泛型接口在定义类时,没有确定数据类型,则创建对象时,仍需指定泛型类型
- MyClass4Interface2<Integer> mc4i2 = new MyClass4Interface2<Integer>();
- mc4i2.method(100);
- }
- }
泛型的通配符
1)概述:
泛型通配符:英文半角状态下的 ?
泛型通配符代表任意数据类型,不能像泛型一样作为某一种数据类型单独使用
2)使用场景:
? extends E
叫法:固定上边界(向下限定);
作用:代表只要是E类型的子类即可
? super E
叫法:固定下边界(向上限定)
作用:代表只要是E类型的父类即可
? 代表传进来的参数的泛型 E 代表调用方法对象的泛型
案例三
- import java.util.ArrayList;
- //public ArrayList(ArrayList<? extends E> c) 通过参数,创建新的集合
- public class DemoType04 {
- public static void main(String[] args) {
- ArrayList<String> list = new ArrayList<String>();
- list.add("abc");
- list.add("abc2");
- list.add("abc3");
- list.add("abc4");
- //传入的参数其泛型String 是创建对象的泛型Object类型的 子类 符合泛型规定? extends E
- ArrayList<Object> list2 = new ArrayList<Object>(list);
- System.out.println(list2);
- }
- }
泛型详解