泛型
泛型的基本概念
泛型是JDK1.5以后增加的,它可以帮助我们建立类型安全的集合。
泛型的本质就是“数据类型的参数化”,处理的数据类型不是固定的,而是可以作为参数传入。我们可以把“泛型”理解为数据类型的一个占位符(类似形式参数),即告诉编译器,在调用泛型时必须传入实际类型,这种参数类型可以在类,接口和方法中,分别被称泛型类、泛型接口、泛型方法。
参数化类型:
1.把类型当作是参数一样传递
2.<数据类型> 只能是引用类型
泛型的好处:
- 代码可读性更好(不需要强制转换)
- 程序更加安全(只要编译时期没有警告,运行时期就不会出现ClassCastException异常)
类型擦除
编码时采用泛型写的类型参数,编译器会在编译时去掉,这称之为“类型擦除”。
泛型主要用于编译阶段,编译后生成的字节码class文件不包含泛型中的类型信息,涉及类型转换任然是普通的强制类型转换。类型参数在编译后会被替代成Object,运行时虚拟机并不知道泛型。
泛型的使用
定义泛型
泛型字符可以是任何标识符,一般采用几个标记:E、T、K、V、N、?
泛型类
泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来。泛型类的具体使用方法是在类的名称后添加一个或多个类型参数声明,如<T><T,K,V>
语法块:
public class 类名 <泛型表示符号>{
}
package com.bjsxt;
public class Generic<T > {
private T flag;
public void setFlag(T flag){
this.flag=flag;
}
public T getFlag(){
return this.flag;
}
}
package com.bjsxt;
import java.awt.*;
public class Text {
public static void main(String[] args) {
Generic<String> graphics=new Generic<String>();
graphics.setFlag("admin");
String flag=graphics.getFlag();
System.out.println(flag);
Generic<Integer> generic1=new Generic<>();
generic1.setFlag(100);
Integer flag1=generic1.getFlag();
System.out.println(flag1);
}
}
泛型接口
泛型接口与泛型类的声明方式一致。泛型接口的具体类型需要在实现类中进行声明。
语法块:
public interface 接口名<泛型表示符号>{
}
package com.bjsxt;
public interface Igeneric <T>{
T getName(T name);
}
package com.bjsxt;
public class Igenericmpl implements Igeneric<String>{
@Override
public String getName(String name) {
return name;
}
}
package com.bjsxt;
public class Text2 {
public static void main(String[] args) {
Igenericmpl igenericmpl = new Igenericmpl();
String name = igenericmpl.getName("wjh");
System.out.println(name);
Igeneric<String> igeneric1 = new Igenericmpl();
igeneric1.getName("WJH");
}
}
泛型方法
泛型方法是指将方法的参数类型定义成泛型,以便在调用时接受不同类型的参数。类型参数可以有多个,用逗号隔开,如<K,V>。定义时,类型参数一般放到返回值的前面。
调用泛型方法中,不需要像泛型类那样告诉编译器是什么类型,编译器可以自动推断出类型来。
语法块:
public <泛型表示符号> void getName (泛型表示符号 name ){
}
public<泛型表示符号> 泛型表示符号 getName (泛型表示符号 name){
}
泛型的静态方法
静态方法中使用泛型时有一种情况需要注意一下,那就是静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
语法块:
public static <泛型表示符号i> void getName (泛型表示符号 name){
}
public static <泛型表示符号> 泛型表示符号 getName(泛型表示符号 name){
}
泛型方法与可变参数
在泛型方法中,泛型也可以定义可变参数类型
语法块:
public <泛型表示符号> void showMsg (泛型表示符号...agrs){
}
package com.bjsxt;
public class MethodGeneric {
public <T> void setName(T name){
System.out.println(name);
}
public <T> T getName(T name ){
return name;
}
public static <T> void setFlag(T flag)
{
System.out.println(flag);
}
public static <T> T getFlag(T flag){
return flag;
}
public <T> void method(T...args){
for (T t:args) System.out.println(t);
}
}
package com.bjsxt;
import java.security.MessageDigest;
public class Tesr3 {
public static void main(String[] args) {
MethodGeneric methodGeneric=new MethodGeneric();
methodGeneric.setName("NB");
methodGeneric.setName(123);
MethodGeneric methodGeneric1=new MethodGeneric();
String name=methodGeneric1.getName("WJHNB");
Integer name1=methodGeneric1.getName(123);
System.out.println(name1);
System.out.println(name);
}
}
package com.bjsxt;
public class Test5 {
public static void main(String[] args) {
MethodGeneric methodGeneric=new MethodGeneric();
String [] arr =new String[] {"a","b","c"};
Integer[] arr2=new Integer[] {1,2,3};
methodGeneric.method(arr);
methodGeneric.method(arr2);
}
}
无界通配符
“ ? ”表示类型通配符,用于替代具体的类型,它只能在“<>”中使用。可以解决当具体类型不确定的问题。
语法块:
public void showFlag(Generic<?> generic){
}
package com.bjsxt;
public class ShowMag {
public void showFlag(Generic<? extends Number> generic){
System.out.println(generic.getFlag());
}
}
package com.bjsxt;
public class Texst6 {
public static void main(String[] args) {
ShowMag showMag=new ShowMag();
Generic<Integer> generic=new Generic<>();
generic.setFlag(20);
showMag.showFlag(generic);
Generic<Number> generic1=new Generic<>();//泛型不会考虑继承问题
showMag.showFlag(generic1);
}
}
通配符的上限与下限限定
上限限定表示通配符的类型是T类以及T类的子类或者T接口以及T接口的子接口,该方法同样适用于泛型的上限限定。
语法块:
public void showFlag (Generic <? extends Number> generic){
}
下限限定表示通配符的类型是T类以及T类的父类或者T接口以及T接口的父接口(不适用泛型类)
语法块:
public void showFlag (Generic <? super Integer> generic){
}