JAVA泛型

一、什么是泛型

Java的泛型 (generics) 是在JDK5中推出的新概念,在泛型推出之前,程序员需要构建一个元素为Object的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要程序员明确知道存储每个元素的数据类型,否则会发生ClassCastException (类转换异常)

而泛型提供了编译时类型安全监测机制,允许我们在编译时检测到非法的类型数据结构,它的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数 (形参),

以ArrayList举例子来说,通过查看ArrayList源码可以看到,ArrayList中可以存放任意的类型是因为有一个泛型<E>,当new一个ArrayList并在泛型中放任意的类型之后此时这个ArrayList就只能存泛型中存放的这个类型的对象,这就是泛型的作用

泛型的好处就在于可以让类型的存放更安全并且可以避免强制类型的转换不会报ClassCastException

二、泛型类

1、语法定义

class 类名<泛型标识, 泛型标识, ...>{

private 泛型标识 变量名;

.....

}

使用语法

类名<具体数据类型> 对象名 = new 类名<具体数据类型>();

java1.7之后,后面的<>中的具体的数据类型可以省略不写

类名<具体的数据类型> 对象名 = new 类名<>();

注意事项:

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

<具体数据类型> 泛型中只能存放包装类

泛型类在逻辑上可以看成是多个不同的类型,但实际上都是相同类型

例:

public class Test1<T> {

private T key;

public T getKey() {

return key;

}

public void setKey(T key) {

this.key = key;

}

}

public class MainMethod {

public static void main(String[] args) {

Test1<String> test1 = new Test1<>();

test1.setKey("abc");

System.out.println("test1存的key为:" + test1.getKey());

System.out.println("test1的类型为:" + test1.getClass().getSimpleName());

System.out.println("test1存的key的类型为:" + test1.getKey().getClass().getSimpleName());

}

}

同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型

public class MainMethod {

public static void main(String[] args) {

Test1<String> test1 = new Test1<>();

test1.setKey("abc");

System.out.println("test1的类型为:" + test1.getClass());

Test1<Integer> test2 = new Test1<>();

test2.setKey(100);

System.out.println("test2的类型为:" + test2.getClass());

System.out.println(test1.getClass() == test2.getClass());

}

}

多个泛型

public class Test1<T,V> {

private T key;

private V value;

public T getKey() {

return key;

}

public void setKey(T key) {

this.key = key;

}

public V getValue() {

return value;

}

public void setValue(V value) {

this.value = value;

}

}

public class MainMethod {

public static void main(String[] args) {

Test1<String,Integer> test1 = new Test1<>();

test1.setKey("number");

test1.setValue(100);

System.out.println(test1.getKey() + ":" + test1.getValue());

}

}

2、常用的泛型标识: T、E、K、V、?

T (type) 表示具体的一个java类型 常用在定义单个对象或者单个方法时

E (element) 代表元素 常在集合中使用

K V 分别代表java键值中的Key和Value 常用在类似于map的集合中

?表示不确定的 java 类型 常在上下限中使用

三、泛型类派生子类

1、语法定义

子类也是泛型类,子类和父类的泛型类型要一致

class Children<T> extends Father<T>

子类不是泛型类,父类要明确泛型的数据类型

class Children extends Father<具体类型>

2、使用场景

可以看出使用instanceof之后调用的是children的属性

要是父类.属性调用的就是父类的

四、泛型接口

1、语法定义

interface 接口名<泛型标识,泛型标识, ...>{

泛型标识 方法名();

.....

}

2、泛型接口的使用

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

实现类也是泛型类,实现类和接口的泛型类型要一致

例:

public interface InMethod<T> {

T getKey(T t);

}

//如果此时实现接口后泛型中不指定具体类型那么重新接口的方法和派生子类一样是Object

public class claMethod implements InMethod{

@Override

public Object getKey(Object o) {

return null;

}

}

//如果此时实现接口后泛型中指定具体的类型那么重写接口方法之后返回的就是定义的类型

public class claMethod implements InMethod<Integer>{

@Override

public Integer getKey(Integer integer) {

return null;

}

}

实现接口之后重写一下接口中的方法

public class ClaMethod implements InMethod<Integer>{

@Override

public Integer getKey(Integer integer) {

return integer;

}

}

public class MainMethod {

public static void main(String[] args) {

ClaMethod claMethod = new ClaMethod();

Integer num = claMethod.getKey(100);

System.out.println(num.getClass().getSimpleName());

}

}

类实现接口并使用了接口中的方法后因为类没有定义泛型所以使用的类型是接口的类型

//接口中的泛型是实现类中泛型的其中一个就可以

public class ClaMethod<T,K,E> implements InMethod<K>{

@Override

public K getKey(K k) {

return null;

}

}

五、泛型方法

1、语法定义

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

方法体 ...

}

【注意】

· public 与 返回值中间<T> 非常重要,可以理解为声明此方法为泛型方法。

· 只有声明了<T>的方法才是泛型方法,泛型类中 使用了泛型的成员方法并不是泛型方法

· <T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T

· 与泛型类的定义一样,此处T可以随便写为任意标识,如 T、E、K、V等形式的参数常用于表示 泛型

例:

public class ClaMethod<T,K,E>{

public <T> T getGeneric(T t){

return t;

}

}

public class MainMethod {

public static void main(String[] args) {

ClaMethod claMethod = new ClaMethod();

String str = "abc";

System.out.println(claMethod.getGeneric(str).getClass().getSimpleName());

}

}

//要是调用的不是void方法 可以传多个类型 return的和上边返回的类型要一致

public <T,K> K GG(K k){

return k;

}

2、静态的泛型方法

public class ClaMethod<T,K,E>{

//静态的泛型方法采用多个泛型类型

public static <T,K,E> void getGenericType(T t,K k){

System.out.println(t+"\t"+t.getClass().getSimpleName());

System.out.println(k+"\t"+k.getClass().getSimpleName());

}

}

public class MainMethod {

public static void main(String[] args) {

//static使用类名.方法名

ClaMethod.getGenericType("abc",100);

}

}

3、泛型方法与可变参数

public <E> void print(E... e){

for(E date : e){

System.out.println(date);

}

}

public class ClaMethod{

public<E> void printE(E... e){

for (E data : e) {

System.out.println(data);

}

}

}

public class MainMethod {

public static void main(String[] args) {

ClaMethod claMethod = new ClaMethod();

claMethod.printE("a","b","c");

}

}

4、泛型方法和泛型类的区别

泛型类,是在实例化类的时候指明泛型的具体类型

泛型方法,是在调用方法的时候指明泛型的具体类型

5、泛型方法总结

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

泛型可以使用多个,要是没有void 就return其中一个泛型,要是有void那么就正常输出就好

静态的泛型方法和普通泛型方法的区别是 静态的泛型方法是在泛型前多加一个static

六、泛型数组

1、泛型数组的创建

可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象

可以通过java.lang.reflect.Array的newInstance(Class<T> ,int) 创建T[]数组

例:

这么写是错误的 ,正确的写法如下图

或者可以是如下写法

区别在于没有把原生对象暴露出来而是采用了直接将匿名对象赋给泛型数组

【注意】new ArrayList 后边没有<> 证明这是ArrayList类型的数组而不是ArrayList集合数组

public class MainMethod {

public static void main(String[] args) {

//错误

ArrayList<String>[] arrayList = new ArrayList<String>[5];

//正确

ArrayList<String>[] arrayList1 = new ArrayList[5];

}

}

2、对象中创建泛型数组

public class StrClass<T> {

private T[] array = new T[5];

}

这种方式是错误的因为我们不知道传的类型是什么类型,万一如上边一样传一个ArrayList<String>那么一定会报错的

正确的方式如下

使用java中Array类的newInstance方法利用反射创建一个对象放在构造器当中从而创建一个数组

public class StrClass<T> {

private T[] array;

public StrClass(Class<T> strClass,int length){

array = (T[])Array.newInstance(strClass,length);

}

public void setArray(T[] array) {

this.array = array;

}

public T[] getArray() {

return array;

}

}

public class MainMethod {

public static void main(String[] args) {

StrClass<String> strClass = new StrClass<>(String.class,10);

String[] str = {"a","b","c"};

strClass.setArray(str);

//调用Arrays.toString方法输出setArray的值

System.out.println(Arrays.toString(strClass.getArray()));

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值