Java教程

JAVA 泛型

本文主要是介绍JAVA 泛型,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

JAVA泛型

泛型的好处

  1. 编译器的检查(类型安全)
  2. 减少了数据类型转换(消除了强制类型转换)

泛型类

泛型类如果没有指定类型,就要按照Object类型来操作;

泛型类不支持基本数据类型,只支持包装类;在编译器的时候,我们会将泛型转换成Object,然后再使用成员的时候,在适当的时候将Object 转换为我们传进来的类型;基本数据类型 不是继承自Object,所以在编译的过程中,底层没办法将int转换成Object 类型来处理。

同一泛型类根据不同的数据类型创建的对象,本质上是同一类型。(内存地址一样)

  • 定义泛型类的语法
package com.hrkj.main.common;

/**
 * 泛型类
 * @param <T> 泛型标识 - 类型参数形参
 */
public class Generic<T> {
    // T 是外部使用类的时候来指定
    private T key;

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }

    @Override
    public String toString() {
        return "Generic{" +
                "key=" + key +
                '}';
    }
}

  • 泛型类的使用
类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();
注意:在java1.7之后,后面<>中的数据类型可以省略不写;
类名<具体的数据类型> 对象名 = new 类名<>();

泛型类注意事项

泛型类,如果没有指定具体的数据类型,此时操作类型是Object

泛型类的类型参数只能是类类型,不能是基本数据类型

泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同类型(内存地址是一样的)

泛型类派生子类

  • 子类也是泛型类,子类和父类的泛型类型要一致;(子类泛型可以扩展)

    class GhildGeneric<T> extends Generic<T>
    // 扩展为
    class GhildGeneric<T,K,V> extends Generic<T> // 但是一定要存在T
    
  • 子类不是泛型类,父类要明确泛型的数据类型

    class GhildGeneric extends Generic<String>
    

泛型接口

泛型接口的使用

  • 实现类不是泛型类,接口需要明确数据类型

    // 泛型接口
    public interface Generate<T>{
    	T getKey();
    }
    
    // 接口实现类不是泛型类,需要明确实现泛型接口的数据类型
    public class Apple implements Generate<String>{ 
    	@Override
        public String getKey(){
            return "hello!";
        }
    }
    
    // 接口实现类是泛型类,要保证实现接口的泛型类泛型标识包含泛型接口的泛型标识(可以扩展)
    public class Pair<T,K> implements Generate<T>{
       private T key;
       private K value;
        public Pair(T key,E value){
            this.key = key;
            this.value = value;
        }
        
        @Override
        public T getKey(){
            return key;
        }
        @Override
        public K getValue(){
            return value;
        }
    }
    
    
    
  • 实现类也是泛型类,实现类和接口的泛型类型要一致

泛型方法

语法结构

​ 修饰符 <T,E,...> 返回值类型 方法名(形参列表){

​ 方法体....

​ }

  • public 与返回值中间的<T>非常重要,可以理解为声明此方法为泛型方法
  • 只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
  • <T> 表明该方法将使用泛型类型 T 此时才可以在方法中使用泛型类型T
  • 与泛型类的定义一样,此处T可以随便写为任意标识,常见的如:T、E、K、V等形式的参数常用于表示泛型
// 定义一个泛型方法;list泛型参数;E泛型标识,具体类型由调用方法的时候来指定
public <E> E getProduct(ArrayList<E> list){
    return list.get(1);
}

即使定义的泛型方法的泛型标识和泛型类的泛型标识是一致的,在使用过程中,这两者是没有任何关系的,是独立存在的。

普通的成员方法如果采用了类的泛型,是不能被声明成静态方法的;如果是泛型方法,可以被声明成静态

// 成员方法使用了类的泛型,不能被定义成静态的 会编译报错
public static T getProduct(ArrayList<T> list){
    return list.get(0);
}
// 泛型方法声明成静态方法,是允许的
public static <T> T getProduct(ArrayList<T> list){
    return list.get(0);
}
//静态的泛型方法,采用多个泛型类型
public static <T,E,K> void printType(T t,E e,K k){
    System.out.println(t+"\t" + t.getClass.getSimpleName());
    System.out.println(e+"\t" + e.getClass.getSimpleName());
    System.out.println(k+"\t" + k.getClass.getSimpleName());
}
// 调用 测试
类名.printType(100,"java",true);

//泛型可变参数的定义
public static <E> void print(E... e){
    for(int i=0;i<e.length;i++){
        System.out.println(e[i]);
    }
}
// 调用 测试
类名.print(1,2,3,4,5,6,7,8);

泛型方法总结:

​ 1: 泛型方法能使方法独立于类而产生变化

​ 2: 如果static方法要使用泛型能力,就必须使其成为泛型方法

类型通配符

什么是类型通配符?

​ 类型通配符一般是用 “?” 来代替具体的类型实参。

​ 所以 类型通配符是类型实参,而不是类型形参。

​ 类对象中的泛型类型不能用多态和继承的思想去理解;比如 Integer extends Number 申明的泛型是Number时 不能传入Integer。使用泛型通配符来定义就可以传入任意类型。

// 使用类型通配符来 配置,可以传入任意类型
public static void act(Person<?> person){
    // 方法体
}
这篇关于JAVA 泛型的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!