Java基础-泛型
来源:互联网 发布:three.js 阴影 锯齿 编辑:程序博客网 时间:2024/05/16 02:12
- 一泛型概述
- 定义泛型
- 从泛型类派生子类
- 并不存在泛型类
- 二类型通配符
- 设定类型通配符的上限
- 设定类型形参的上限
- 三泛型方法
- 泛型方法和类型通配符的区别
- 泛型构造器
- 设定通配符下限
一、泛型概述
所谓泛型,就是允许在定义类、接口、方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,也可以称为类型实参)
定义泛型
不仅仅集合类可以用泛型,可以为任何类、接口增加泛型声明
下面定义一个Apple类,包含一个泛型声明:
public class Apple<T> { private T info; public Apple(){} // 下面方法中使用T类型形参来定义构造器 public Apple(T info) { this.info = info; } public void setInfo(T info) { this.info = info; } public T getInfo() { return this.info; } public static void main(String[] args) { // TODO Auto-generated method stub Apple<String> a1 = new Apple<>("红富士"); System.out.println(a1.getInfo()); Apple<Double> a2 = new Apple<>(12.3); System.out.println(a2.getInfo()); }}
从泛型类派生子类
当创建了带泛型声明的接口、父类之后,可以为该接口创建实现类,或从该父类派生子类,需要指出的是,当使用这些接口、父类时,不能再包含类型形参。
- 定义类、接口、方法时可以声明数据形参
- 使用类、接口、方法时必须为这些数据形参传入实际的数据
//错误,Apple类不能跟类型形参public class A extends Apple<T>{} //正确public class A entends Apple<String>{} //正确,与调用方法不同,使用类接口时也可以不为类型形参传入实际的类型参数public class A entends Apple{}
下面的代码示范了第一种正确的定义方式,从子类继承到String getInfo() 和void setInfo(String Info)两个方法:
public class A1 extends Apple<String>{ //返回值与父类相同 public String getInfo(){ return "子类" + super.getInfo(); }}
下面的代码示范了第二种正确的定义方式,Java编译器可能发出警告,此时系统会把父类中的T当成Object类型处理:
public class A2 extends Apple{ public String getInfo(){ //super.getInfo()返回值是Object类型,加toString()返回String return super.getInfo().toString(); }}
并不存在泛型类
public class test { public static void main(String[] args) { Apple<String> a1 = new Apple<>(); Apple<Double> a2 = new Apple<>(); //返回true System.out.println(a1.getClass() == a2.getClass()); }}
不管为泛型的类型形参传入哪一种类型实参,对于Java来说,它们依然被当成同一个类处理,在内存中也只占用一块内存空间。
静态方法、静态初始化块或静态变量的声明和初始化中不允许使用类型形参。
由于系统中并不会真正生产泛型类,所以instanceof运算符后面不能使用泛型类。
二、类型通配符
定义一个方法,该方法里有一个集合形参,集合形参的元素类型是不确定的,可以用到类型通配符。类型通配符是一个问号。
import java.util.ArrayList;import java.util.List;public class ListTest { public void test(List<?> c){ for(int i=0;i<c.size();i++){ System.out.println(c.get(i)); } } public static void main(String[] args) { // TODO Auto-generated method stub List<String> l1 = new ArrayList<>(); l1.add("Generic"); l1.add("Socket"); l1.add("Exception"); List<Double> l2 = new ArrayList<>(); l2.add(12.34); l2.add(3.14); ListTest lt = new ListTest(); lt.test(l1); lt.test(l2); }}
设定类型通配符的上限
若不希望?表示任何类型的父类,而是某一类的父类,可以设定类型通配符的上限。
public abstract class Shape { public abstract void draw(Canvas c);}
public class Circle extends Shape{ public void draw(Canvas c){ System.out.println("在" + c + "上画一个圆"); }}
public class Rectangle extends Shape{ public void draw(Canvas c) { System.out.println("在" + c + "上画一个矩形"); }}
import java.util.ArrayList;import java.util.List;public class Canvas { //此处的?一定是Shape的子类型 public void drawAll(List<? extends Shape> shapes){ for(Shape s : shapes){ s.draw(this); } } public static void main(String[] args){ List<Circle> circleList = new ArrayList<Circle>(); Circle circle1 = new Circle(); circleList.add(circle1); Circle circle2 = new Circle(); circleList.add(circle2); Canvas c = new Canvas(); c.drawAll(circleList); }}
设定类型形参的上限
Java泛型不仅允许在使用通配符形参时设定上限,而且可以在定义形参时设定上限
public class Apple<T extends Number>{ T col; public static void main(String[] args){ Apple<Integer> ai = new Apple<>(); Apple<Double> ad = new Apple<>(); // 下面代码将引起编译异常,下面代码试图把String类型传给T形参 // 但String不是Number的子类型,所以引发编译错误 Apple<String> as = new Apple<>(); }}
在更极端的情况下,程序需要为类型形参设定多个上限(至多有一个父类上限,可以有多个接口上限)
public class Apple<T extends Number & java.io.Serializable>{ ......}
三、泛型方法
泛型方法的语法格式如下:
修饰符 <T,S> 返回值类型 方法名(形参列表){ //方法体}
import java.util.ArrayList;import java.util.Collection;public class GenericMethodTest { static <T> void fromArrayToCollection(T[] a,Collection<T> c){ for(T t:a){ c.add(t); } } public static void main(String[] args) { Object[] oa = new Object[100]; Collection<Object> co = new ArrayList<>(); // 下面代码中T代表Object类型 fromArrayToCollection(oa, co); Integer[] ia = new Integer[100]; Float[] fa = new Float[100]; Number[] na = new Number[100]; Collection<Number> cn = new ArrayList<>(); // 下面代码中T代表Number类型 fromArrayToCollection(ia, cn); // 下面代码中T代表Number类型 fromArrayToCollection(fa, cn); // 下面代码中T代表Number类型 fromArrayToCollection(na, cn); }}
泛型方法和类型通配符的区别
大多数时候都可以使用泛型方法来代替类型通配符。
使用类型通配符:
public interface Collection<E>{ boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); ......}
使用泛型方法:
public interface Collection<E>{ <T> boolean containsAll(Collection<T> c); <T extends> boolean addAll(Collection<T> c); ......}
下面例子中,没必要使用泛型方法:
public class Collections{ public static <T,S extends T> void copy(List<T> dest,List<S> src){}}
因为S仅使用了一次,其他参数类型、方法返回值的类型都不依赖它,可以写成如下形式:
public class Collections{ public static <T> void copy(List<T> dest,List<? extends T> src){}}
泛型构造器
Java允许在构造器签名中声明类型形参
class Foo{ public <T> Foo(T t) { System.out.println(t); }}public class GenericConstructor{ public static void main(String[] args) { // 泛型构造器中的T参数为String。 new Foo("疯狂Java讲义"); // 泛型构造器中的T参数为Integer。 new Foo(200); // 显式指定泛型构造器中的T参数为String, // 传给Foo构造器的实参也是String对象,完全正确。 new <String> Foo("疯狂Android讲义"); // 显式指定泛型构造器中的T参数为String, // 但传给Foo构造器的实参是Double对象,下面代码出错 new <String> Foo(12.3); }}
设定通配符下限
Java允许设定通配符下限,如下面代码所示:
import java.util.ArrayList;import java.util.Collection;import java.util.List;public class MyUtils { public static <T> T copy(Collection<? super T> dest, Collection<T> src){ T last = null; for (T ele : src) { last = ele; dest.add(ele); } return last; } public static void main(String[] args) { List<Number> ln = new ArrayList<>(); List<Integer> li = new ArrayList<>(); li.add(5); // 此处可准确的知道最后一个被复制的元素是Integer类型 // 与src集合元素的类型相同 Integer last = copy(ln , li); System.out.println("last = " + last + ",ln = " + ln); }}
- Java基础 Java 泛型
- Java语言基础:泛型
- java基础加强--泛型
- Java基础加强---泛型
- Java基础_泛型
- java基础---->泛型
- java基础:泛型
- Java基础复习:泛型
- java基础11 泛型
- 基础---java 泛型
- java基础<泛型>
- java基础_10_泛型
- java基础__泛型
- Java基础:泛型
- Java基础 - 泛型
- java基础加强:泛型
- java基础-泛型
- java基础学习-泛型
- rman blockrecover ORA-600 [kcrrge.cannotread_inc.1] oracle bug 处理方式
- 程序员遇到bug怎么面对?
- 11.2编程总结
- 【bzoj 1102】[POI2007]山峰和山谷Grz(BFS)
- python--re模块--黑科技
- Java基础-泛型
- 请编写一个C函数,该函数可以实现将一个整数转为任意进制的字符串输出
- 数据库:数据定义和单表查询
- linux学习总结(2)
- winform 嵌入 外部 exe窗体
- 利用python做数据分析 札记(二)
- 11.3模拟赛总结
- c语言数据结构之顺序表静态链表的创建及功能函数
- laplacian,degree,adjacency and oriented incidence matrix, differential and laplacian coordinates