Java之泛型
来源:互联网 发布:无影无踪软件下载 编辑:程序博客网 时间:2024/04/30 04:25
jdk中的K,V,T,E等泛型名称很多人以为是固定写法,其实这些名称是可以改的,比如改成zhangsan,lisi都可以,jdk为了容易看懂,所以用K表示键,V表示值,T表示type类型,E表示enum枚举,其实这四个都只是符号,都是表示泛型名称,下面的例子的T全部可以换成E,也可以换成K,V,zhangsan,都没关系。
class Point<T>{ // 此处可以随便写标识符号,T是type的简称。如果这里定义aaaa,则下方的T也要改为aaaa private T var ; // var的类型由T指定,即:由外部指定。 如果上面class Point<T>写成class Point<aaaa>,则这里的类型T也要改为aaaa,下同。 public T getVar(){ // 返回值的类型由外部决定 return var ; } public void setVar(T var){ // 设置的类型也由外部决定 this.var = var ; } };
定义泛型类、接口:
类型形参可以在整个接口、类体内当成普通类型使用,集合所有可使用普通类型的地方都可以使用类型形参,例如:
定义泛型构造器:泛型的构造器还是类名本身,不用使用菱形语法,例如
!定义构造器无需MyGeneric<T>(...) { ... }了,只有在new的时候需要用到菱形语法;泛型在定义的时候必须使用形参(虚拟参数,用户自己随意命名),但是在使用泛型的时候(比如定义泛型引用、继承泛型)就必须使用实参
1) 泛型定义的时候使用形参,例如:public class MyGeneric<T> { ... } // T就是一个自己随意命名的类型形参
2) 使用泛型的时候必须传入实参:
3) 继承之后,父类/接口中的所有方法中的类型参数都将变成具体的类型,你在子类中覆盖这些方法的时候一定要用具体的类型,不能继续使用泛型的类型形参了,例如:
泛型参数继承:
1) 上面派生出来的类不是泛型,是一个实体类型,因为其继承的泛型是具有类型实参的。
Java还支持一种特殊的语法,可以让你从泛型继续派生出泛型,而泛型的类型参数可以继续传承下去。语法如下:
即子泛型可以传承父泛型的泛型参数,那么在子类中泛型参数T就和父类的完全相同,还是照常使用(和父类一样正常使用);因此以下三种情况全部错误(全部发生编译报错):必须全部使用和父类定义相同的类型参数名(T)!才行,这是Java语法的特殊规定;示例1:使用泛型
//T,V都是随便定义的东西,注意:它们不会关联到其他类,只是在本类中通用,只是告诉我们new的时候要加入泛型
class hello<T, V> {
private T name;
private V age;
hello() {
}
public T getName(){
return name;
}
public void setName(T name){
this.name = name;
}
public V getAge(){
return age;
}
public void setAge(V age){
this.age = age;
}
public static void main(String[] args){
hello<String, Integer> he = new hello<String, Integer>();
he.setAge(10);
he.setName("Rollen Holt");
System.out.println(he.getName() + " " + he.getAge());
}
}
/**
* 示例2:泛型类的构造方法定义
*/
class hello<T, V> {
private T name;
private V age;
hello(T name, V age){
this.age = age;
this.name = name;
}
public T getName(){
return name;
}
public V getAge(){
return age;
}
public static void main(String[] args){
hello<String,Integer> he =new hello<String,Integer>("Rollen", 12);
System.out.println(he.getName()+" "+he.getAge());
}
}
/**
* 示例3:使用通配符
*/
class info<T> {
private T name;
info(T name) {
this.name = name;
}
}
class hello{
public static void function(info<?> temp){
System.out.println("内容: "+temp);
}
public static void main(String[] args){
info<String> demo = new info<String>("Rollen");
function(demo);
}
}
/**
* 示例4:泛型上限
*/
class info<T> {
private T age;
info(T age) {
this.age=age;
}
}
class hello {
public static void function(info<? extends Number>temp) {
System.out.println("内容"+ temp);
}
public static void main(String[] args) {
info<Integer> demo = new info<Integer>(1);
function(demo);
}
}
/**
* 示例5:泛型下限
*/
class info<T> {
private T age;
info(T age) {
this.age=age;
}
}
class hello{
public static void function(info<? super String> temp) {
System.out.println("内容"+ temp);
}
public static void main(String[] args){
// 此处只能使用String 或者Object
info<String> demo = new info<String>("Rollen");
function(demo);
}
}
/**
* 泛型和子类继承的限制
*/
class info<T> {
}
class hello {
public static void main(String[] args){
info<String> demo1=new info<String>();
info<Object> demo2=new info<Object>();
//demo2=demo1; 此处错误
}
}
/**
* 上面的例子说明,一个类的子类可以通过多态性被其父类实例化
* 但是在泛型操作中,子类的泛型类型是无法被其父类的泛型类型实例化的。
*/
如果允许上面的条语句的话,会出现:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Type mismatch: cannot convert from info<String> to info<Object>
at hello.main(hello.java:12)
泛型接口的两种实现:
/**
* 泛型接口的实现1
*/
interface info<T> {
public void say();
}
// 直接在子类之后声明泛型
class hello<T> implements info<T>{
public static void main(String[] args){
info<String> demo = new hello<String>();
demo.say();
}
public void say(){
System.out.println("hello");
}
}
/**
* 泛型接口的实现2
*/
interface info<T> {
public void say();
}
// 在子类实现的接口中明确给出泛型类型
class hello implements info<String>{
public static void main(String[] args){
info<String> demo = new hello();
demo.say();
}
public void say(){
System.out.println("hello");
}
}
/**
* 使用泛型统一传入参数的类型
*/
class info<T> {
private T var;
public T getVar(){
return var;
}
public void setVar(T var){
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
class hello{
public static void main(String[] args){
info<String> demo1=new info<String>();
info<String> demo2=new info<String>();
demo1.setVar("Rollen");
demo2.setVar("Holt");
printAdd(demo1, demo2);
}
// 此处传递的都是同一个String类型的
public static <T> void printAdd(info<T> demo1, info<T> demo2){
System.out.println(demo1.getVar()+" "+demo2.getVar());
}
}
否则的话如下所示:出现错误:
/**
* 使用泛型统一传入参数的类型
*/
class info<T> {
private T var;
public T getVar(){
return var;
}
public void setVar(T var){
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
class hello{
public static void main(String[] args){
info<String> demo1=new info<String>();
info<Integer> demo2=new info<Integer>();
demo1.setVar("Rollen");
demo2.setVar(30);
//此处调用错误
printAdd(demo1, demo2);
}
// 此处传递的都是同一个String类型的
public static <T> void printAdd(info<T> demo1, info<T> demo2){
System.out.println(demo1.getVar()+" "+demo2.getVar());
}
}
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method printAdd(info<T>, info<T>) in the type hello is not applicable for the arguments (info<String>, info<Integer>)
at hello.main(hello.java:26)
普通泛型
- class Point<T>{ // 此处可以随便写标识符号,T是type的简称。如果这里定义aaaa,则下方的T也要改为aaaa
- private T var ; // var的类型由T指定,即:由外部指定。 如果class Point<T>写成class Point<aaaa>,则这里的类型T也要改为aaaa
- public T getVar(){ // 返回值的类型由外部决定
- return var ;
- }
- public void setVar(T var){ // 设置的类型也由外部决定
- this.var = var ;
- }
- };
- public class GenericsDemo06{
- public static void main(String args[]){
- Point<String> p = new Point<String>() ; // 里面的var类型为String类型
- p.setVar("it") ; // 设置字符串
- System.out.println(p.getVar().length()) ; // 取得字符串的长度
- }
- };
- ----------------------------------------------------------
- class Notepad<K,V>{ // 此处指定了两个泛型类型
- private K key ; // 此变量的类型由外部决定
- private V value ; // 此变量的类型由外部决定
- public K getKey(){
- return this.key ;
- }
- public V getValue(){
- return this.value ;
- }
- public void setKey(K key){
- this.key = key ;
- }
- public void setValue(V value){
- this.value = value ;
- }
- };
- public class GenericsDemo09{
- public static void main(String args[]){
- Notepad<String,Integer> t = null ; // 定义两个泛型类型的对象
- t = new Notepad<String,Integer>() ; // 里面的key为String,value为Integer
- t.setKey("汤姆") ; // 设置第一个内容
- t.setValue(20) ; // 设置第二个内容
- System.out.print("姓名;" + t.getKey()) ; // 取得信息
- System.out.print(",年龄;" + t.getValue()) ; // 取得信息
- }
- };
通配符
- class Info<T>{
- private T var ; // 定义泛型变量
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- public String toString(){ // 直接打印
- return this.var.toString() ;
- }
- };
- public class GenericsDemo14{
- public static void main(String args[]){
- Info<String> i = new Info<String>() ; // 使用String为泛型类型
- i.setVar("it") ; // 设置内容
- fun(i) ;
- }
- public static void fun(Info<?> temp){ // 可以接收任意的泛型对象
- System.out.println("内容:" + temp) ;
- }
- };
受限泛型
- class Info<T>{
- private T var ; // 定义泛型变量
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- public String toString(){ // 直接打印
- return this.var.toString() ;
- }
- };
- public class GenericsDemo17{
- public static void main(String args[]){
- Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象
- Info<Float> i2 = new Info<Float>() ; // 声明Float的泛型对象
- i1.setVar(30) ; // 设置整数,自动装箱
- i2.setVar(30.1f) ; // 设置小数,自动装箱
- fun(i1) ;
- fun(i2) ;
- }
- public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子类
- System.out.print(temp + "、") ;
- }
- };
- ----------------------------------------------------------
- class Info<T>{
- private T var ; // 定义泛型变量
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- public String toString(){ // 直接打印
- return this.var.toString() ;
- }
- };
- public class GenericsDemo21{
- public static void main(String args[]){
- Info<String> i1 = new Info<String>() ; // 声明String的泛型对象
- Info<Object> i2 = new Info<Object>() ; // 声明Object的泛型对象
- i1.setVar("hello") ;
- i2.setVar(new Object()) ;
- fun(i1) ;
- fun(i2) ;
- }
- public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型
- System.out.print(temp + "、") ;
- }
- };
泛型无法向上转型
- class Info<T>{
- private T var ; // 定义泛型变量
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- public String toString(){ // 直接打印
- return this.var.toString() ;
- }
- };
- public class GenericsDemo23{
- public static void main(String args[]){
- Info<String> i1 = new Info<String>() ; // 泛型类型为String
- Info<Object> i2 = null ;
- i2 = i1 ; //这句会出错 incompatible types
- }
- };
泛型接口
- interface Info<T>{ // 在接口上定义泛型
- public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型
- }
- class InfoImpl<T> implements Info<T>{ // 定义泛型接口的子类
- private T var ; // 定义属性
- public InfoImpl(T var){ // 通过构造方法设置属性内容
- this.setVar(var) ;
- }
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- };
- public class GenericsDemo24{
- public static void main(String arsg[]){
- Info<String> i = null; // 声明接口对象
- i = new InfoImpl<String>("汤姆") ; // 通过子类实例化对象
- System.out.println("内容:" + i.getVar()) ;
- }
- };
- ----------------------------------------------------------
- interface Info<T>{ // 在接口上定义泛型
- public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型
- }
- class InfoImpl implements Info<String>{ // 定义泛型接口的子类
- private String var ; // 定义属性
- public InfoImpl(String var){ // 通过构造方法设置属性内容
- this.setVar(var) ;
- }
- public void setVar(String var){
- this.var = var ;
- }
- public String getVar(){
- return this.var ;
- }
- };
- public class GenericsDemo25{
- public static void main(String arsg[]){
- Info i = null; // 声明接口对象
- i = new InfoImpl("汤姆") ; // 通过子类实例化对象
- System.out.println("内容:" + i.getVar()) ;
- }
- };
泛型方法
- class Demo{
- public <T> T fun(T t){ // 可以接收任意类型的数据
- return t ; // 直接把参数返回
- }
- };
- public class GenericsDemo26{
- public static void main(String args[]){
- Demo d = new Demo() ; // 实例化Demo对象
- String str = d.fun("汤姆") ; // 传递字符串
- int i = d.fun(30) ; // 传递数字,自动装箱
- System.out.println(str) ; // 输出内容
- System.out.println(i) ; // 输出内容
- }
- };
通过泛型方法返回泛型类型实例
- class Info<T extends Number>{ // 指定上限,只能是数字类型
- private T var ; // 此类型由外部决定
- public T getVar(){
- return this.var ;
- }
- public void setVar(T var){
- this.var = var ;
- }
- public String toString(){ // 覆写Object类中的toString()方法
- return this.var.toString() ;
- }
- };
- public class GenericsDemo27{
- public static void main(String args[]){
- Info<Integer> i = fun(30) ;
- System.out.println(i.getVar()) ;
- }
- public static <T extends Number> Info<T> fun(T param){//方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定
- Info<T> temp = new Info<T>() ; // 根据传入的数据类型实例化Info
- temp.setVar(param) ; // 将传递的内容设置到Info对象的var属性之中
- return temp ; // 返回实例化对象
- }
- };
使用泛型统一传入的参数类型
- class Info<T>{ // 指定上限,只能是数字类型
- private T var ; // 此类型由外部决定
- public T getVar(){
- return this.var ;
- }
- public void setVar(T var){
- this.var = var ;
- }
- public String toString(){ // 覆写Object类中的toString()方法
- return this.var.toString() ;
- }
- };
- public class GenericsDemo28{
- public static void main(String args[]){
- Info<String> i1 = new Info<String>() ;
- Info<String> i2 = new Info<String>() ;
- i1.setVar("HELLO") ; // 设置内容
- i2.setVar("汤姆") ; // 设置内容
- add(i1,i2) ;
- }
- public static <T> void add(Info<T> i1,Info<T> i2){
- System.out.println(i1.getVar() + " " + i2.getVar()) ;
- }
- };
泛型数组
- public class GenericsDemo30{
- public static void main(String args[]){
- Integer i[] = fun1(1,2,3,4,5,6) ; // 返回泛型数组
- fun2(i) ;
- }
- public static <T> T[] fun1(T...arg){ // 接收可变参数
- return arg ; // 返回泛型数组
- }
- public static <T> void fun2(T param[]){ // 输出
- System.out.print("接收泛型数组:") ;
- for(T t:param){
- System.out.print(t + "、") ;
- }
- }
- };
泛型的嵌套设置
- class Info<T,V>{ // 接收两个泛型类型
- private T var ;
- private V value ;
- public Info(T var,V value){
- this.setVar(var) ;
- this.setValue(value) ;
- }
- public void setVar(T var){
- this.var = var ;
- }
- public void setValue(V value){
- this.value = value ;
- }
- public T getVar(){
- return this.var ;
- }
- public V getValue(){
- return this.value ;
- }
- };
- class Demo<S>{
- private S info ;
- public Demo(S info){
- this.setInfo(info) ;
- }
- public void setInfo(S info){
- this.info = info ;
- }
- public S getInfo(){
- return this.info ;
- }
- };
- public class GenericsDemo31{
- public static void main(String args[]){
- Demo<Info<String,Integer>> d = null ; // 将Info作为Demo的泛型类型
- Info<String,Integer> i = null ; // Info指定两个泛型类型
- i = new Info<String,Integer>("汤姆",30) ; // 实例化Info对象
- d = new Demo<Info<String,Integer>>(i) ; // 在Demo类中设置Info类的对象
- System.out.println("内容一:" + d.getInfo().getVar()) ;
- System.out.println("内容二:" + d.getInfo().getValue()) ;
- }
- };
泛型方法不一定要通过参数来确定泛型准确类型,可以只通过返回值,比如:
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<E>();
}
public List<PrepaidHistory> queryHistories(Long skyid,PrepaidHistoryType type, Date from, Date end) {
。。。
return Lists.newArrayList();
}
这样Lists.newArrayList();
智能的知道返回类型为PrepaidHistory
假如我们现在要定义一个类来表示坐标,要求坐标的数据类型可以是整数、小数和字符串,例如:
x = 10、y = 10
x = 12.88、y = 129.65
x = "东京180度"、y = "北纬210度"
针对不同的数据类型,除了借助方法重载,还可以借助自动装箱和向上转型。我们知道,基本数据类型可以自动装箱,被转换成对应的包装类;Object 是所有类的祖先类,任何一个类的实例都可以向上转型为 Object 类型,例如:
int --> Integer --> Object
double -->Double --> Object
String --> Object
public class Demo { public static void main(String[] args){ Point p = new Point(); p.setX(10); // int -> Integer -> Object p.setY(20); int x = (Integer)p.getX(); // 必须向下转型 int y = (Integer)p.getY(); System.out.println("This point is:" + x + ", " + y); p.setX(25.4); // double -> Integer -> Object p.setY("东京180度"); double m = (Double)p.getX(); // 必须向下转型 double n = (Double)p.getY(); // 运行期间抛出异常 System.out.println("This point is:" + m + ", " + n); }}class Point{ Object x = 0; Object y = 0; public Object getX() { return x; } public void setX(Object x) { this.x = x; } public Object getY() { return y; } public void setY(Object y) { this.y = y; }}
上面的代码中,生成坐标时不会有任何问题,但是取出坐标时,要向下转型,在 Java多态对象的类型转换 一文中我们讲到,向下转型存在着风险,而且编译期间不容易发现,只有在运行期间才会抛出异常,所以要尽量避免使用向下转型。运行上面的代码,第12行会抛出 java.lang.ClassCastException 异常。
那么,有没有更好的办法,既可以不使用重载(有重复代码),又能把风险降到最低呢?
有,可以使用泛型类(Java Class),它可以接受任意类型的数据。所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。
public class Demo { public static void main(String[] args){ // 实例化泛型类 Point<Integer, Integer> p1 = new Point<Integer, Integer>(); p1.setX(10); p1.setY(20); int x = p1.getX(); int y = p1.getY(); System.out.println("This point is:" + x + ", " + y); Point<Double, String> p2 = new Point<Double, String>(); p2.setX(25.4); p2.setY("东京180度"); double m = p2.getX(); String n = p2.getY(); System.out.println("This point is:" + m + ", " + n); }}// 定义泛型类class Point<T1, T2>{ T1 x; T2 y; public T1 getX() { return x; } public void setX(T1 x) { this.x = x; } public T2 getY() { return y; } public void setY(T2 y) { this.y = y; }}
运行结果:
This point is:10, 20
This point is:25.4, 东京180度
与普通类的定义相比,上面的代码在类名后面多出了 <T1, T2>,T1, T2 是自定义的标识符,也是参数,用来传递数据的类型,而不是数据的值,我们称之为类型参数。在泛型中,不但数据的值可以通过参数传递,数据的类型也可以通过参数传递。T1, T2 只是数据类型的占位符,运行时会被替换为真正的数据类型。
传值参数(我们通常所说的参数)由小括号包围,如 (int x, double y),类型参数(泛型参数)由尖括号包围,多个参数由逗号分隔,如 <T> 或 <T, E>。
类型参数需要在类名后面给出。一旦给出了类型参数,就可以在类中使用了。类型参数必须是一个合法的标识符,习惯上使用单个大写字母,通常情况下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型。
泛型类在实例化时必须指出具体的类型,也就是向类型参数传值,格式为:
className variable<dataType1, dataType2> = new className<dataType1, dataType2>();
也可以省略等号右边的数据类型,但是会产生警告,即:className variable<dataType1, dataType2> = new className();
因为在使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险,比本文一开始介绍的自动装箱和向上转型要更加实用。
注意:
泛型是 Java 1.5 的新增特性,它以C++模板为参照,本质是参数化类型(Parameterized Type)的应用。
类型参数只能用来表示引用类型,不能用来表示基本类型,如 int、double、char 等。但是传递基本类型不会报错,因为它们会自动装箱成对应的包装类。
泛型方法
除了定义泛型类,还可以定义泛型方法,例如,定义一个打印坐标的泛型方法:public class Demo { public static void main(String[] args){ // 实例化泛型类 Point<Integer, Integer> p1 = new Point<Integer, Integer>(); p1.setX(10); p1.setY(20); p1.printPoint(p1.getX(), p1.getY()); Point<Double, String> p2 = new Point<Double, String>(); p2.setX(25.4); p2.setY("东京180度"); p2.printPoint(p2.getX(), p2.getY()); }}// 定义泛型类class Point<T1, T2>{ T1 x; T2 y; public T1 getX() { return x; } public void setX(T1 x) { this.x = x; } public T2 getY() { return y; } public void setY(T2 y) { this.y = y; } // 定义泛型方法 public <T1, T2> void printPoint(T1 x, T2 y){ T1 m = x; T2 n = y; System.out.println("This point is:" + m + ", " + n); }}
运行结果:
This point is:10, 20
This point is:25.4, 东京180度
上面的代码中定义了一个泛型方法 printPoint(),既有普通参数,也有类型参数,类型参数需要放在修饰符后面、返回值类型前面。一旦定义了类型参数,就可以在参数列表、方法体和返回值类型中使用了。
与使用泛型类不同,使用泛型方法时不必指明参数类型,编译器会根据传递的参数自动查找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。
public static <V1, V2> void printPoint(V1 x, V2 y){ V1 m = x; V2 n = y; System.out.println("This point is:" + m + ", " + n);}
泛型接口
在Java中也可以定义泛型接口,这里不再赘述,仅仅给出示例代码:public class Demo { public static void main(String arsg[]) { Info<String> obj = new InfoImp<String>("www.csdn.net"); System.out.println("Length Of String: " + obj.getVar().length()); }}//定义泛型接口interface Info<T> { public T getVar();}//实现接口class InfoImp<T> implements Info<T> { private T var; // 定义泛型构造方法 public InfoImp(T var) { this.setVar(var); } public void setVar(T var) { this.var = var; } public T getVar() { return this.var; }}
运行结果:
Length Of String: 18
类型擦除
如果在使用泛型时没有指明数据类型,那么就会擦除泛型类型,请看下面的代码:public class Demo { public static void main(String[] args){ Point p = new Point(); // 类型擦除 p.setX(10); p.setY(20.8); int x = (Integer)p.getX(); // 向下转型 double y = (Double)p.getY(); System.out.println("This point is:" + x + ", " + y); }}class Point<T1, T2>{ T1 x; T2 y; public T1 getX() { return x; } public void setX(T1 x) { this.x = x; } public T2 getY() { return y; } public void setY(T2 y) { this.y = y; }}运行结果:
This point is:10, 20.8
因为在使用泛型时没有指明数据类型,为了不出现错误,编译器会将所有数据向上转型为 Object,所以在取出坐标使用时要向下转型,这与本文一开始不使用泛型没什么两样。
限制泛型的可用类型
在上面的代码中,类型参数可以接受任意的数据类型,只要它是被定义过的。但是,很多时候我们只需要一部分数据类型就够了,用户传递其他数据类型可能会引起错误。例如,编写一个泛型函数用于返回不同类型数组(Integer 数组、Double 数组、Character 数组等)中的最大值:public <T> T getMax(T array[]){ T max = null; for(T element : array){ max = element.doubleValue() > max.doubleValue() ? element : max; } return max;}上面的代码会报错,doubleValue() 是 Number 类的方法,不是所有的类都有该方法,所以我们要限制类型参数 T,让它只能接受 Number 及其子类(Integer、Double、Character 等)。
通过 extends 关键字可以限制泛型的类型,改进上面的代码:
public <T extends Number> T getMax(T array[]){ T max = null; for(T element : array){ max = element.doubleValue() > max.doubleValue() ? element : max; } return max;}<T extends Number> 表示 T 只接受 Number 及其子类,传入其他类型的数据会报错。这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的 extends 已经不是继承的含义了,应该理解为 T 是继承自 Number 类的类型,或者 T 是实现了 XX 接口的类型。
注意:一般的应用开发中泛型使用较少,多用在框架或者库的设计中,这里不再深入讲解。
class
hello<T, V> {
hello(){
}
public
T getName(){
return
name;
}
public
void
setName(T name){
this
.name = name;
}
public
V getAge(){
return
age;
}
public
void
setAge(V age){
this
.age = age;
}
private
T name;
private
V age;
public
static
void
main(String[] args){
hello<String, Integer> he =
new
hello<String, Integer>();
he.setAge(
10
);
he.setName(
"Rollen Holt"
);
System.out.println(he.getName() +
" "
+ he.getAge());
}
}
/**
* @author Rollen-Holt 泛型类的构造方法定义
*/
class
hello<T, V> {
hello(T name, V age){
this
.age = age;
this
.name = name;
}
public
T getName(){
return
name;
}
public
V getAge(){
return
age;
}
private
T name;
private
V age;
public
static
void
main(String[] args){
hello<String,Integer> he=
new
hello<String,Integer>(
"Rollen"
,
12
);
System.out.println(he.getName()+
" "
+he.getAge());
}
}
/**
* @author Rollen-Holt 使用通配符
*/
class
info<T> {
info(T name){
this
.name = name;
}
private
T name;
}
class
hello{
public
static
void
function(info<?> temp){
System.out.println(
"内容: "
+temp);
}
public
static
void
main(String[] args){
info<String> demo=
new
info<String>(
"Rollen"
);
function(demo);
}
}
/**
* @author Rollen-Holt 泛型上限
*/
class
info<T>{
info(T age){
this
.age=age;
}
private
T age;
}
class
hello{
public
static
void
function(info<?
extends
Number> temp){
System.out.println(
"内容"
+ temp);
}
public
static
void
main(String[] args){
info<Integer> demo=
new
info<Integer>(
1
);
function(demo);
}
}
/**
* @author Rollen-Holt 泛型下限
*/
class
info<T>{
info(T age){
this
.age=age;
}
private
T age;
}
class
hello{
public
static
void
function(info<?
super
String> temp){
System.out.println(
"内容"
+ temp);
}
public
static
void
main(String[] args){
// 此处只能使用String 或者Object
info<String> demo=
new
info<String>(
"Rollen"
);
function(demo);
}
}
/**
* @author Rollen-Holt 泛型和子类继承的限制
*/
class
info<T>{
}
class
hello{
public
static
void
main(String[] args){
info<String> demo1=
new
info<String>();
info<Object> demo2=
new
info<Object>();
//demo2=demo1; 此处错误
}
}
/**
* 上面的例子说明,一个类的子类可以通过多态性被其父类实例化
* 但是在泛型操作中,子类的泛型类型是无法被其父类的泛型类型实例化的。
*/
如果允许上面的条语句的话,会出现:
Exception in thread
"main"
java.lang.Error: Unresolved compilation problem:
Type mismatch: cannot convert from info<String> to info<Object>
at hello.main(hello.java:
12
)
泛型接口的两种实现:
/**
* @author Rollen-Holt 泛型接口的实现1
*/
interface
info<T> {
public
void
say();
}
// 直接在子类之后声明泛型
class
hello<T>
implements
info<T>{
public
static
void
main(String[] args){
info<String> demo =
new
hello<String>();
demo.say();
}
public
void
say(){
System.out.println(
"hello"
);
}
}
/**
* @author Rollen-Holt 泛型接口的实现2
*/
interface
info<T> {
public
void
say();
}
// 在子类实现的接口中明确给出泛型类型
class
hello
implements
info<String>{
public
static
void
main(String[] args){
info<String> demo =
new
hello();
demo.say();
}
public
void
say(){
System.out.println(
"hello"
);
}
}
/**
* @author Rollen-Holt 使用泛型通一传入参数的类型
*/
class
info<T> {
private
T var;
public
T getVar(){
return
var;
}
public
void
setVar(T var){
this
.var = var;
}
public
String toString(){
return
this
.var.toString();
}
}
class
hello{
public
static
void
main(String[] args){
info<String> demo1=
new
info<String>();
info<String> demo2=
new
info<String>();
demo1.setVar(
"Rollen"
);
demo2.setVar(
"Holt"
);
printAdd(demo1, demo2);
}
// 此处传递的都是同一个String类型的
public
static
<T>
void
printAdd(info<T> demo1, info<T> demo2){
System.out.println(demo1.getVar()+
" "
+demo2.getVar());
}
}
否则的话如下所示:出现错误:
/**
* @author Rollen-Holt 使用泛型通一传入参数的类型
*/
class
info<T> {
private
T var;
public
T getVar(){
return
var;
}
public
void
setVar(T var){
this
.var = var;
}
public
String toString(){
return
this
.var.toString();
}
}
class
hello{
public
static
void
main(String[] args){
info<String> demo1=
new
info<String>();
info<Integer> demo2=
new
info<Integer>();
demo1.setVar(
"Rollen"
);
demo2.setVar(
30
);
//此处调用错误
printAdd(demo1, demo2);
}
// 此处传递的都是同一个String类型的
public
static
<T>
void
printAdd(info<T> demo1, info<T> demo2){
System.out.println(demo1.getVar()+
" "
+demo2.getVar());
}
}
Exception in thread
"main"
java.lang.Error: Unresolved compilation problem:
The method printAdd(info<T>, info<T>) in the type hello is not applicable
for
the arguments (info<String>, info<Integer>)
at hello.main(hello.java:
26
)
- java之泛型
- java之泛型
- Java 之泛型
- Java之泛型
- java之泛型
- Java之泛型
- Java之泛型
- JAVA之泛型
- Java之泛型
- Java之泛型
- java之泛型
- Java之泛型
- Java之泛型
- java之泛型
- Java之泛型
- java之泛型
- java之泛型
- java基础-Java之泛型
- js获取 type=radio 值的方法
- C语言中格式转换问题
- shell提取字符串指定的内容
- linux网络命令--3--ping -- traceroute -- arp
- 教你透彻了解红黑树---第一篇
- Java之泛型
- openstack 安装手册
- 开发错误总结
- [投资与建设]未来10年的IT投资热点
- 全面解析9i以后Oracle Latch闩锁原理
- 用python写一个进程
- UWP入门教程1——UWP的前世今生
- layout animation
- 软件包安装