HIT软件构造 范型

泛型就是把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作是参数一样传递,Object<数据类型>这里面只能是引用类型不能是基本类型。比如:Object //true
Object //false为什么泛型里面数据类型不能是基本类型呢?因为虚拟机在编译时会把带泛型的转换成Object类型,而基本类型不属于Object类型,所以泛型里面数据类型不能是基本类型。为什么要使用泛型呢?Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。有一点很重要就是消除了强制类型转换,减少了出错机会,举个例子:
public class Test {
public static void main(String[] args){
List list = new ArrayList();
list.add(“1”);
list.add(1);
int i = (int)list.get(0); // java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
int j = (int)list.get(1);
}
}
上面代码在编译期没有问题,因为list的add方法是Object类型,所以在编译期没有什么问题,但是运行期的时候我们调用 list的时候并不知道list里面具体存了什么类型的参数,所以取的时候有可能就会报类型转换的错误 。如果用了泛型上面的错误就不会发生了。
public class Test {
public static void main(String[] args){
List list = new ArrayList();
list.add(“1”);
list.add(1);//在编译期就会出错,因为用了泛型,虚拟机就会在编译期的时候检查泛型类型安全。
}
}
泛型只存在于编译期。举个例子。
public class Test {
public static void main(String[] args) throws Exception{
List list = new ArrayList();
list.add(“hello”);
//list.add(23) //编译期会报错
Class c = Class.forName(“java.util.ArrayList”);
Method m = c.getMethod(“add”,Object.class);
m.invoke(list,23);
System.out.println(list); // [hello, 23]
}
}
通过上面可知,泛型只在编译期有效,为什么运行期失效了呢,这是因为泛型的擦除概念,通俗点来说就是泛型的信息不会进行运行阶段。泛型的使用泛型有三种实用方式泛型类:public class Test}{} T表示未知类型泛型接口:public interface Test{} 和定义类一样泛型方法:public void Test(T name){}泛型类的使用泛型类在java中有着很重要的地位,其中我们用的最多的就是ArrayList,HashMap,HashSet.既然是带你看懂Java泛型,肯定不能源码里面的那些容器类呀,那些容器类都已经很完善了如果要带你们看的话,肯定会越看越晕的,所以我们自己定义一个泛型类出来。//这个T可以换成随便一个字母 ,只不过我写泛型都用的T,你可以换成A,B,C…
public class Test {
T name;
public Test(T name){
this.name = name;
}
public T getName() {
return name;
}

public void setName(T name) {
    this.name = name;
}

//如果不传泛型类型的话,那么默认的就是Object型什么都可以传
Test test = new Test(“hello”);
//传入的数据类型不为基本类型,否则编译期会报错,开头我解释过为什么会报错了
Test test1 = new Test<>(418);
泛型接口的使用泛型接口的定义和泛型类的定义差不多,我们常见的泛型接口就是,List,Map,Set.首先老规矩我们自己定义一个泛型接口。public interface Test{
T getName(T name);
}

//如果实现接口的时候不传入数据类型的话,需要将泛型声明也要写到类中要不然会报错
class Test1 implements Test{

@Override
public T getName(T name) {
    return null;
}

}

//实现接口的时候传入数据类型的话,就不用把泛型声明也写到类中了
class Test2 implements Test{

@Override
public String getName(String name) {
    return name;
}

}
泛型方法的使用泛型方法的使用public void getName(T name){}
public <T,K> void getNameAndValue(T name, K value){}
public <T,K,V> void getNameAndValueAndV(T name, K value, V v){}//总的来说就是参数需要多少泛型,返回值前面就得定义几个泛型要不然编译期会出错
泛型通配符为什么要用通配符呢?java里面类和类之间是有继承关系 的,比如Cat extends Animals,那么Cat就是Animal的子类,但是集合是没有继承这个概念的,比如List catList和List animalList你不能说 animalList是catList的父类,所以很难看出来这两个类之间的联系,但是我们现在只想让list里面只加入Animals的子类怎么办呢?一种是Animals有多少个子类就定义多少个list,这种方法虽然也可以实现但是Animals如果有一百个,一千个,一万个子类呢你这种方法是不是就太耗时了呢。第二种就是用通配符来实现。比如:List animals 这个时候animals就只能添加Animals的子类了,一个list搞定。通配符的基本概念?无边界的通配符:? 举个例子,能接收所有未知类型的泛型public class Test {
public static void main(String []args){
List list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List stringList = new ArrayList<>();
stringList.add(“h”);
stringList.add(“e”);
stringList.add(“l”);
stringList.add(“l”);
stringList.add(“o”);
getList(stringList);
getList(list);
}
//无论传入什么List都会被接收
public static List getList(List<?> list){ return list; }用List声明的List 不能使用add方法,因为你不知道的类型是什么,但是list.add(null)就可以,因为null是所有类型都有的。举个例子public static List getList(List<?> list){
// list.add(1);//会报参数不匹配的错误,编译期报错
// list.add(“hello”);//会报参数不匹配的错误,编译期报错
list.add(null);//添加成功
return list;
}用get方法也只能用Object来接收,因为你不知道你的类型是什么。public static List getList(List<?> list){
int i = list.get(0); //编译期报错
String j = list.get(1); //编译期报错
Object o = list.get(3); //运行正确
return list;
}上边界通配符号:可以接收E以及E的子类型的泛型,这里面的E不止是类哦,也可以是接口,看个例子。//这个是继承了类的用法
public class Test {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
getList(list);
List strings = new ArrayList<>();
strings.add(“hello”);
getList(strings);//编译期报错
}

public static List getList(List<? extends Number> list) {
return list;
}
}

public class Test {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
getList(list);// 编译期报错
List test2s = new ArrayList<>();
getList(test2s);
}
//上边界为接口的实现,只要是实现了此接口的类都可以被当做泛型传进来
public static List getList(List<? extends Test1> list) {
return list;
}
}

interface Test1{

}
class Test2 implements Test1{}以上可知上边界就是你传入的类型必须得是E的子类,或者是实现接口的类。下边界通配符号: 就是传入的类型必须得是E以及E的父类,举个例子public class Test {
public static void main(String[] args) {
List animals = new ArrayList<>();
getList(animals);
List cats = new ArrayList<>();
getList(cats);
List dogs = new ArrayList<>();
getList(dogs);//编译出错,因为Dog不是Cat的父类

}

public static List getList(List<? super Cat> list) {
return list;
}
}
class Animals{}
class Cat extends Animals{}
class Dog extends Animals{}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值