`

java泛型

 
阅读更多

          java泛型是JDK1.5以后出现的新特性,泛型的简单使用(例如在集合中的使用)本文不做讲解,这里主要讲解一下泛型的设计。

         一、泛型类设计

         在定义泛型类时,使用尖括号来指定泛型类型参数,泛型类型参数与方法参数不同,方法类型参数传入的是值,而泛型类型参数传入的是类的class类型。请看以下代码:

 

// 父类animal
abstract class Animal{
	public abstract void eat();
}

// 子类cat
class Cat extends Animal{
	@Override
	public void eat() {
		System.out.println("eat fish");
	}
}

// 子类dog
class Dog extends Animal{
	@Override
	public void eat() {
		System.out.println("eat bone");
	}
}

// 泛型类Generic
class Generic<T>{
	private T t;
	
	public Generic(T t){
		this.t = t;
	}
	
	public void doEat(){
		if (t instanceof Dog){
			Dog d = (Dog)t;
			d.eat();
		} else if(t instanceof Cat){
			Cat c = (Cat)t;
			c.eat();
		}
	}
}

       

        此时,如果调用

                Generic<Cat> c = new Generic<Cat>(new Cat());

                c.doEat();

        那么输出结果肯定是 “eat  fish”,但是如果调用

                Generic<Cat> c = new Generic<Cat>(new Dog());

        肯定会编译出错,因为Generic的泛型参数为Cat,因此通过设置泛型参数,可以实现对方法参数类型的限定。那么有人会说,限定方法参数,看不出有什么优势,而且直接在Generic的doEat方法参数中,改成Cat(public void doEat(Cat c))就可以了。这样确实也限制了,但是如果我们此时期望Generic传入Dog类型的对象,或者其他(例如String)类型的对象,那么这种解决方案就无效了,此时只能通过泛型来解决,例如要传入Dog类型的参数,则:

                 Generic<Dog> c = new Generic<Dog>(new Dog());

                 c.doEat();

         

         说到这里,问题又来了,如果此时我期望传入的类型只能是Dog和Cat,不能其它类型,该如何解决?

那么就说道另一个知识点,泛型类型的限定,代码如下:

 

class Generic<T extends Animal>{
	private T t;
	
	public Generic(T t){
		this.t = t;
	}
	
	public void doEat(){
		if (t instanceof Dog){
			Dog d = (Dog)t;
			d.eat();
		} else if(t instanceof Cat){
			Cat c = (Cat)t;
			c.eat();
		}
	}
}

         通过extends关键字,我们将T的类型限定为Animal的子类,又因为Dog和Cat继承自Animal,所以目前Ceneric的泛型类型只能传入Dog和Cat,如果我们传入其他类型,例如String

 

         Generic<String> c = new Generic<String>(new String());

          那么这行代码将会编译出错,因为String不是animal的子类。这种限定泛型参数的技巧常用在泛型DAO的设计中,众所周知,j2ee项目中,我们会有很多张表的数据交互,不论有什么样的复杂业务,总少不了单表的增删改查,所以我们会将单表的增、删、该、查的基础方法抽取出来放入一个父类DAO,然后其他业务模块的DAO继承父类DAO,在没有使用泛型之前,他们的类图如下:



        通过类图,大致可以了解,为了将共有的增删改查方法抽取出来,必须将save方法的参数和load方法的返回值设置成Object,一旦设置成Object,那么代码中就会充斥着大量的类型判断和类型强转的内容,因此才使用泛型解决这一问题(泛型DAO设计常用有两种方式,本文先介绍其中一种),泛型DAO代码如下:

 

public interface BaesDAO<T extends BaseEntity>{
    /*
     *  通过ID查询对象
     */
    public T Load(Integer id);
    /*
     *  新增
     */
    public void save(T entity);
    /*
     *  修改
     */
    public void udate(T entity);
    /*
     *  删除
     */
    public void delete(Integer id);
}

 

/* 
 * 这里类似伪代码,大家能明白意思就好
 */
public class BaseDAOImpl<T extends BaseEntity> implements IBaseDAO<T extends BaseEnt>{
    public T load(Integer id){
    }
    public void save(T entity){
    }
    public void update(T entity){
    }
    public void delete(integer id){
    }
}

         重点看具体业务模块的DAO

 

  

public interface IUserDAO extends IBaseDAO<UserEntity>{
    public List<UserEntity> findUserByCompany(String companyId);
}


public class UserDAOImpl extends BaseDAOImpl<UserEntity> implements IUserDAO{
    public List<UserEntity> findUserByCompany(String companyId){

    }    
}

         在UserDAOImpl中,当继承BaseDAOImpl时传入的泛型为UserEntity,由于UserEntity继承BaseEntity,所以可以传入,又由于传入的是UserEntity,所以在BaseDAOImpl的save方法中,存入的就是UserEntity对象,同样load返回的对象就是UserEntity,通过泛型,减少了对象类型的判断以及类型强制转换,简化了代码,增强了可读性。

 

         二、泛型方法设计

         泛型方法设计,主要是针对方法参数和返回值进行泛型的设计,请看以下代码:

public List<Animal> test(List<Animal> list){
     return null;
}

         先看该方法的参数,要求传入一个List<Animal> list,但如果此时我期望传入一个List<Cat> list该怎么办?也许你会有一些误解,认为Cat是Animal的子类,所以我们可以传入一个List<Cat> list(即new ArrayList<Cat>() 传进去),这是完全错误的,请看在eclipse中的代码:


        为了解决以上问题,又涉及到了新的知识点,通配符。通配符有两个关键字extends
和super,先看extends,extends表示类型向下限制,请看代码:


        通过代码我们可以理解,之所以extends叫向下限制,是因为?表示要初始化的泛型类型必须是extends后面类型的子类型,所以我们可以在GenericMethodTest的方法里面参数改为List<? extends Animal>,这样我们就可以传入List<Cat>或者List<Dog>了。请看代码:


         此时,不会在编译报错了。同理,对于方法的返回值,如果我们也期望返回的List泛型为Animal的子类,那么我们只需要把返回类型声明为List<? extends Animal>,请看代码:


        

        最后,我们再说一下super,super和extends相反,表示对泛型类型的向上类型限制,例如:

        List<? super Animal> list = new ArrayList<Object>();

        List<? super Animal> list2 = new ArrayList<Animal>();

        List<? super Animal> list3 = new ArrayList<Cat>();// 此处会编译出错

        如果我们在声明时使用? super Animal,那么?就表示必须是super关键字后面类类型的父类型或本身自己的类型。那super的主要使用场景在哪里?例如我有一个list,即想存入Cat,也想存入Dog,那么我的List的泛型类型必须是Cat和Dog的父类,例如Animal或者Object,请看代码:


        通过上面代码,我们得知,如果想一个list即存入dog,也存入cat,那么该list的泛型至少是一个animal,那此时,就可以通过List<? super Animal> 来实现。那么在方法设计中,有时候我们的业务逻辑需要返回的结果集中即包含Dog,也包含Cat,那么我们就可以把方法的返回值设置为List<? super Animal>,请看代码:


          通过对泛型方法设计的讲解,我们再对泛型通配符super和extends进行总结。在上面提到的三个类,Animal,Dog和Cat,他们的类关系如下,


       
           虽然这三个类有如上继承关系,但是不代表他们的泛型有继承关系,请看下图:

           

          但是一旦使用了通配符extends,那么泛型之间可以看似有继承关系(记住,只是看似有),请看下图:

          
         如果使用了super,那么表示当前泛型对象是super后面类型的父类型,也可以看似有继承关系,请看下图:

         
 

 
          泛型的类设计和方法设计大致介绍到这里,还有一些泛型的高级应用后续在补充。

        

         

        

 

 

 

 

  • 大小: 17.4 KB
  • 大小: 29.3 KB
  • 大小: 27.6 KB
  • 大小: 20.5 KB
  • 大小: 25.4 KB
  • 大小: 20.5 KB
  • 大小: 28.6 KB
  • 大小: 4 KB
  • 大小: 8 KB
  • 大小: 8.6 KB
  • 大小: 6.7 KB
分享到:
评论

相关推荐

    Java泛型的用法及T.class的获取过程解析

    Java泛型的用法及T.class的获取过程解析 Java泛型是Java编程语言中的一种重要特性,它允许开发者在编写代码时指定类型参数,从而提高代码的灵活性和可读性。本文将详细介绍Java泛型的用法 及T.class的获取过程解析...

    Java泛型三篇文章,让你彻底理解泛型(super ,extend等区别)

    Java 泛型详解 Java 泛型是 Java SE 5.0 中引入的一项特征,它允许程序员在编译时检查类型安全,从而减少了 runtime 错误的可能性。泛型的主要优点是可以Reusable Code,让程序员编写更加灵活和可维护的代码。 ...

    Java泛型应用实例

    Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...

    很好的Java泛型的总结

    Java泛型机制详解 Java泛型是Java语言中的一种机制,用于在编译期检查类型安全。Java泛型的出现解决了Java早期版本中类型安全检查的缺陷。Java泛型的好处是可以在编译期检查类型安全,避免了运行时的...

    java 泛型类的类型识别示例

    综上所述,虽然Java泛型在编译后会进行类型擦除,但通过上述技巧,我们仍然能够在运行时获得关于泛型类实例化类型的一些信息。在实际开发中,这些方法可以帮助我们编写更加灵活和安全的代码。在示例文件`GenericRTTI...

    java泛型技术之发展

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

    SUN公司Java泛型编程文档

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入。这个特性极大地提高了代码的类型安全性和可读性,减少了在运行时出现ClassCastException的可能性。SUN公司的Java泛型编程文档,包括...

    java 泛型接口示例

    下面我们将详细探讨Java泛型接口的相关知识点。 1. **泛型接口的定义** 泛型接口的定义方式与普通接口类似,只是在接口名之后添加了尖括号`&lt;T&gt;`,其中`T`是一个类型参数,代表某种未知的数据类型。例如: ```java...

    java 泛型方法使用示例

    下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...

    java泛型的内部原理及更深应用

    Java泛型是Java编程语言中的一个强大特性,它允许在定义类、接口和方法时使用类型参数,从而实现参数化类型。这使得代码更加安全、可读性更强,并且能够减少类型转换的必要。在“java泛型的内部原理及更深应用”这个...

    JAVA泛型加减乘除

    这是一个使用JAVA实现的泛型编程,分为两部分,第一部分创建泛型类,并实例化泛型对象,得出相加结果。 第二部分用户自行输入0--4,选择要进行的加减乘除运算或退出,再输入要进行运算的两个数,并返回运算结果及...

    Java 泛型擦除后的三种补救方法

    Java 泛型是一种强大的工具,它允许我们在编程时指定变量的类型,提供了编译时的类型安全。然而,Java 的泛型在运行时是被擦除的,这意味着在运行时刻,所有的泛型类型信息都会丢失,无法直接用来创建对象或进行类型...

    java泛型学习ppt

    "Java 泛型学习" Java 泛型是 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的...

    Java泛型使用详细分析.pdf

    Java 泛型使用详细分析 Java 泛型是 Java 语言中的一种类型系统特性,允许开发者在编译期检查类型安全,以避免在运行时出现类型相关的错误。在本文中,我们将详细介绍 Java 泛型的使用方法和实现原理。 一、泛型的...

    Java泛型技术之发展.pdf

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

    Java泛型类型擦除后的补偿

    本文将深入探讨Java泛型类型擦除的概念,并介绍在类型擦除后,为了保持泛型的安全性和便利性,Java设计者所采取的一些补偿机制。 1. **类型擦除**: - 在编译期间,所有的泛型类型信息都会被替换为它们的实际类型...

Global site tag (gtag.js) - Google Analytics