Java基础泛型篇一
来源:互联网 发布:js定义一个json数组 编辑:程序博客网 时间:2024/06/06 17:13
泛型基础
1.定义
Java的的泛型是从Java的jdk1.5之后出现的,一种参数化的复杂数据类型。泛型的出现是由当前的需求所迫。 java泛型的应用可以提高的代码的复用性,同时泛型提供了类型检查,减少了数据的类型转换,同时保证了类型安全。看下面这这种情况;
List list = new ArrayList();list.add("好人一生平安");//可以通过编译list.add(new Integer(1));//可以通过编译for(Object object : list){ LogUtil.log("输入值",object + "");//运行的时候报这个异常ClassCastException}这个很明显是因为java的类型之间的数据转换异常,是将Integer类型的对象转换为String的时候抛出异常了。
如果在java5之后,我们采用泛型的方式就可以避免出现这个问题。
List<String> list = new ArrayList();list.add("好人一生平安");//可以通过编译list.add(new Integer(1));//不能编译for(Object object : list){ LogUtil.log("输入值",object + "");}看到第三行代码了吗,直接不能通过编译,因为我们将这个集合的类型定义成了String类型,你不能给String 类型的集合中添加Integer类型的数据,所以编译的时候直接报错。我们可以看看List的源码如下:
/** * A {@code List} is a collection which maintains an ordering for its elements. Every * element in the {@code List} has an index. Each element can thus be accessed by its * index, with the first index being zero. Normally, {@code List}s allow duplicate * elements, as compared to Sets, where elements have to be unique. */public interface List<E> extends Collection<E> { /** * Inserts the specified object into this {@code List} at the specified location. * The object is inserted before the current element at the specified * location. If the location is equal to the size of this {@code List}, the object * is added at the end. If the location is smaller than the size of this * {@code List}, then all elements beyond the specified location are moved by one * position towards the end of the {@code List}. * * @param location * the index at which to insert. * @param object * the object to add. * @throws UnsupportedOperationException * if adding to this {@code List} is not supported. * @throws ClassCastException * if the class of the object is inappropriate for this * {@code List}. * @throws IllegalArgumentException * if the object cannot be added to this {@code List}. * @throws IndexOutOfBoundsException * if {@code location < 0 || location > size()} */ public void add(int location, E object);看到没有这个接口提供了是采用泛型的方式来定义的,继承自Collection<E>采用也是泛型的形式,一直到Iterable<E>。
* Methods marked with (optional) can throw an * {@code UnsupportedOperationException} if the underlying collection doesn't * support that method. */public interface Collection<E> extends Iterable<E> {
所以采用泛型的就会在编译的时候提示你异常,而不会再运行时才提示你,这样保证了数据的一致性。
泛型的分类。泛型分为三种,泛型方法,泛型类,泛型接口三种。
2.泛型类
创建一个普通的类。然后调用它的方法
public class Book { private Object object; public Object getObject() { return object; } public void setObject(Object object) { this.object = object; }
Book book = new Book();book.setObject("好好学习,天天向上");String value = (String) book.getObject();//运行时会在这里会抛出异常,不能将对象转成String;
这种原始的使用方式和上面的相似,没有使用泛型的时候,在程序运行阶段报出异常。我们看看类的泛型使用。
*/public class Book<T> { private T object; public T getObject() { return object; } public void setObject(T object) { this.object = object; }
Book<String> book1 = new Book<>();book1.setObject("这个是String类型");//book1.setObject(12);//这里直接在编译的时候报错。String result = book1.getObject();LogUtil.log("泛型",result);Book book = new Book();book.setObject("好好学习,天天向上");String value = (String) book.getObject();//在这里就不会输出错误LogUtil.log("输入信息==",value);book.setObject(7);int value_int = (int) book.getObject();//在这里就不会输出错误LogUtil.log("输入信息==",value_int + "");
现在看,book1对象定义为String类型,所以不能输入Integer类型的数据,因为定义为泛型就再不需要强制转换了。book对象没有定义为那种类型,因为是泛型,我们可以在下面设置String 和Int都不会报错,这样的话还是要进行强制转换。这个就是泛型类的简单实用。
3.泛型接口
泛型接口的定义很简单,
public interface FanInterface<T> { void setValue(T t); T getT();}实现接口的时候要定义泛型的类型,不然不能使用。
public class GetVauleImpl implements FanInterface<Integer> { @Override public void setValue(Integer o) { } @Override public Integer getT() { return null; }}
当创建了带泛型声明的接口或者实现类时,可以为接口创建相应的实现类,或者从父类派生子类,但是在使用这些接口或者父类时不能再包含类型形参。指定一个类型,或者不指定,但是不能写<T>。
4.类型通配符
4.1通配符的定义
通配符:是指可以指定任何的类型,对于数据类型不确定的值的时候我们就可以采用通配符。
例如:下面的代码。
public class TongPeiFu { public void invoke(List<Object> list){//函数参数 int count=list.size(); for(int i=0;i<count;i++){ System.out.println(list.get(i)); } } void task(){ List<String> list=new ArrayList<String>(); list.add("a"); invoke(list);//编译的时候就报错了,因为List<String>不是List<Object>的子类, }}如上代码编译的时候就报错了,因为函数的参数形式是List<Object>类型的,而实参是List<String>类型的,但是需要注意的一点是List<String >的不是List<Object>的子类,所以编译的时候操作了,所以在函数参数不确定的情况,就引出了通配符的使用。java中类型通配符用“?”标示;类型通配符是所有泛型List的父类。在定义的使用用?标示参数就行,上面代码改成这样就不会报错了;
*/public class TongPeiFu { public void invoke(List<?> list){//函数参数 int count=list.size(); for(int i=0;i<count;i++){ System.out.println(list.get(i)); } } void task(){ List<String> list=new ArrayList<String>(); list.add("a"); invoke(list);//不会报错, }}当直接采用List<?>的话,默认就是所有List的父类。
还有如下实例:
//采用通配符 public static void getData(Box<?> data) { System.out.println("data :" + data.getT()); }
Box<String> box = new Box<>("测试泛型");LogUtil.log("返回的数据结构===", box.getT());Box<Number> box_number = new Box<Number>(123);LogUtil.log("返回的数据==", box_number.getT() + "");Box<Integer> box_int = new Box<>(456);LogUtil.log("返回的数据==", box_int.getT() + "");getData(box);getData(box_number);getData(box_int);//这种就是在使用的时候才设定他实参的类型。
4.2通配符的上限
上限是指这定子类是以特定父类下面的泛型。采用如下:<T extends superclass>标示
// 这个是extend的用法,指定上限。 public static void getSubNumberData(Box<? extends Number> data) { System.out.println("data :" + data.getT()); }这个是指定上限为Number数字类型,所以在使用的时候要
Box<Number> box_number = new Box<Number>(123);LogUtil.log("返回的数据==", box_number.getT() + "");Box<Integer> box_int = new Box<>(456);LogUtil.log("返回的数据==", box_int.getT() + "");这样就指定了上限是Number,实参使用的时候只要是Number或者是其子类的话都不会报错。但是采用String类型的就会报错。getSubNumberData(box_number);getSubNumberData(box_int);//不会出现编译异常getSubNumberData(box);//出现编译异常
采用这种方式也会出现问题。
// 这个是extend的用法,指定上限。上限为Integer的时候。
public static void getSubNumberData(Box<? extends Integer> data) { System.out.println("data :" + data.getT()); }
Box<Number> box_number = new Box<Number>(123);LogUtil.log("返回的数据==", box_number.getT() + "");Box<Integer> box_int = new Box<>(456);LogUtil.log("返回的数据==", box_int.getT() + "");getSubNumberData(box_number);//编译的时候出现异常getSubNumberData(box_int);//不会出现编译异常//看到没有当上限定义为Integer的时候的时候,设置实参类型为Number类型的话就会报错。
坦白的说通配符的上限就是制定父类的类型。
4.3 通配符下限
其实通配符的下限就是上限的反义词,指定下限意味着限定子类。使用的时候要注意。
//泛型的用法 限定下限为Integer类型 public static void getUpperNumberData(Box<? super Integer> data) { System.out.println("data :" + data.getT());}
Box<Number> box_number = new Box<Number>(123);LogUtil.log("返回的数据==", box_number.getT() + "");Box<Integer> box_int = new Box<>(456);LogUtil.log("返回的数据==", box_int.getT() + "");getUpperNumberData(box_number);getUpperNumberData(box_int);//都可以通过当改为这个时
//泛型的用法 public static void getUpperNumberData(Box<? super Number> data) { System.out.println("data :" + data.getT());}
Box<Number> box_number = new Box<Number>(123);LogUtil.log("返回的数据==", box_number.getT() + "");Box<Integer> box_int = new Box<>(456);LogUtil.log("返回的数据==", box_int.getT() + "");getUpperNumberData(box_number);getUpperNumberData(box_int);//不能通过编译了//看到没有不能通过编译了。
5. 泛型方法
上面是定义接口和类的时候声明类型参数,在该类的方法定义、变量定义和接口的方法定义、变量的定义中,该类型形参可以当作普通类型来使用。如果我们的类没有声明类型形参,但是方法却想定义类型形参数的话,那么我们就可以使用泛型方法。
//泛型方法public <E> void genericmethod(List<E> a){ for(E t:a) System.out.println(t.toString());}
List<String> list=new ArrayList<>();list.add("好好好");list.add("老司机等等我");list.add("滴,学生卡");list.add("我日等我下");fanMethod(list);List<Integer> list1=new ArrayList<>();list1.add(1);list1.add(2);list1.add(3);list1.add(4);fanMethod(list1);使用的时候就这样用。
泛型的使用简单的就这么多。但是在实际的项目中更多的使用的是符合类型的泛型。
基本的用法学习完后,觉得定义泛型的类型和通配符的类型都是不确定,假如定义了一个泛型类或者泛型方法,又如何确定能类或者方法里做什么操作呢。回想看到其他用泛型一般都是在定义抽象类或者接口的时候使用,用于子类或者实现类的扩展 。因为是一般的类中使用泛型没有任何意义,因为泛型的类型是未知的,不能做任何的操作!!!
所以说泛型的设计是要考虑的代码的扩展和复用。要不然是没有意义的。
如下面的代码:
public <T> void getData(T t1,T t2){ if(t1.contains(t2)){//编译不能通过 LogUtil.log("t1 包含t2"); }}//这样的话编译是不能通过的。但是采用这样的话就可以操作
public <T extends String> void getData(T t1,T t2){ if(t1.contains(t2)){//编译不能通过 LogUtil.log("t1 包含t2"); }}这样的话就采用通配符就可以很好的实现代码的复用了。采用通配符限定一些类型来实现相关的功能。
6.总结
泛型也算是Java比较新的知识,熟练的运用泛型能够使我们的代码更加的灵活,更加的有扩展性,也能使得代码的重用性变的更好。所以在开发过程中结合项目实际,合理使用泛型,写出优雅的代码。这个才是程序员的最大追求。
1 0
- Java基础泛型篇一
- Java基础01:基础
- Java基础:基础加强
- Java基础-基础
- java基础的基础
- JAVA基础---基础常识
- Java基础:基础加强
- [Java 基础]基础语法
- Java基础
- java基础
- java 基础
- java基础
- Java基础
- Java基础
- Java基础
- JAVA基础
- JAVA基础
- JAVA基础
- React Native第一个Demo(1)
- Java中的隐藏和覆盖
- Python 字典详解
- OPENSSL X509证书验证
- Java中 String、StringBuffer 、StringBuilder 总结
- Java基础泛型篇一
- JQuery中ajax处理跨域的三大方式
- Hibernate与Ibatis比较
- 以Yii 2.0风格加载自定义类或命名空间 [配置使用Yii autoloader] [ 2.0 版本 ]
- Python数据类型转换
- iOS笔记—NSURLConnection怎么把http改为https
- 腾正科技“护驾”来袭
- log4j详细配置
- 从零开始构建MSBuild C#项目文件