- 概念
- 具体概念
- 那么为什么要有泛型呢
- 在集合中使用泛型之前的情况
- 泛型的使用
- 自定义泛型结构
- 自定义泛型类、泛型接口
- 泛型方法
- 泛型类和泛型方法的使用情境
泛型:标签
- 举例:
- 中药店,每个抽屉外面贴着标签
- 超市购物架上很多瓶子,每个瓶子装的是什么,有标签
- 泛型的设计背景
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。
因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时 把元素的类型设计成一个参数,这个类型参数叫做泛型。 Collection,List,ArrayList 这个就是类型参数,即泛型。
所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。
- 从JDK1.5以后,Java引入了“参数化类型(Parameterized type)”的概念,允许我们在创建集合时再指定集合元素的类型
正如:List,这表明该List只能保存字符串类型的对象。 - JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参。
那么为什么要有泛型呢,直接Object不是也可以存储数据吗?
- 解决元素存储的安全性问题,好比商品、药品标签,不会弄错。
- 解决获取数据元素时,需要类型强制转换的问题,好比不用每回拿商品、药品都要辨别。
Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
ArrayList list = new ArrayList(); //需求:存放学生的成绩 list.add(78); list.add(76); list.add(89); list.add(88); // 问题一:类型不安全 // list.add("Tom"); for(Object score : list){ // 问题二:强转时,可能出现ClassCastException int stuScore = (Integer) score; System.out.println(stuScore);泛型的使用
- jdk 5.0新增的特性
- 在集合中使用泛型:
总结:
① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
② 在实例化集合类时,可以指明具体的泛型类型
③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。
比如:add(E e) —>实例化以后:add(Integer e)
④ 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
⑤ 如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。 - 如何自定义泛型结构:泛型类、泛型接口;泛型方法。
ArrayListlist = new ArrayList (); list.add(78); list.add(87); list.add(99); list.add(65); //编译时,就会进行类型检查,保证数据的安全 // list.add("Tom"); //方式一: // for(Integer score : list){ // 避免了强转 *** 作 // int stuScore = score; // System.out.println(stuScore); // } //方式二: Iterator iterator = list.iterator(); while(iterator.hasNext()){ int stuScore = iterator.next(); System.out.println(stuScore); }
// Map自定义泛型结构 自定义泛型类、泛型接口map = new HashMap (); //jdk7新特性:类型推断 Map map = new HashMap<>(); map.put("Tom",87); map.put("Jerry",87); map.put("Jack",67); // map.put(123,"ABC"); //泛型的嵌套 Set > entry = map.entrySet(); Iterator > iterator = entry.iterator(); while(iterator.hasNext()){ Map.Entry e = iterator.next(); String key = e.getKey(); Integer value = e.getValue(); System.out.println(key + "----" + value); } }
Order.java
public class Order{ String orderName; int orderId; //类的内部结构就可以使用类的泛型 T orderT; public Order(){ //编译不通过 // T[] arr = new T[10]; //编译通过 T[] arr = (T[]) new Object[10]; }; public OrderTest(String orderName,int orderId,T orderT){ this.orderName = orderName; this.orderId = orderId; this.orderT = orderT; } public T getOrderT(){ return orderT; } public void setOrderT(T orderT){ this.orderT = orderT; } //静态方法中不能使用类的泛型。 // public static void show(T orderT){ // System.out.println(orderT); // } public void show(){ //编译不通过 // try{ // }catch(T t){ // } } @Override public String toString() { return "Order{" +"orderName='" + orderName + ''' +", orderId=" + orderId +", orderT=" + orderT +'}'; }
- 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:
- 泛型类的构造器如下:public GenericClass(){}。
而下面是错误的:public GenericClass< E >(){} - 实例化后, *** 作原来泛型位置的结构必须与指定的泛型类型一致。
- 泛型不同的引用不能相互赋值。
ArrayListlist1 = null; ArrayList list2 = new ArrayList (); //泛型不同的引用不能相互赋值。 // list1 = list2; Person p1 = null; Person p2 = null; p1 = p2;
尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中。
- 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型要使用一路都用。要不用,一路都不要用。
- 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
- jdk1.7,泛型的简化 *** 作:ArrayList< Fruit > flist = new ArrayList<>();
- 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
- 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。
但在静态方法中不能使用类的泛型。 - 异常类不能是泛型的
//异常类不能声明为泛型类 //public class MyExceptionextends Exception{ //}
- 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]
参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。 - 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
class Father{}
- 子类不保留父类的泛型:按需实现
- 没有类型 擦除
class Son1 extends Father {}
class Son1 extends Father{}
等价于class Son extends Father - 具体类型
class Son2 extends Father{}
class Son2 extends Father{}
- 没有类型 擦除
- 子类保留父类的泛型:泛型子类
- 全部保留
class Son3extends Father {}
class Son3extends Father {} - 部分保留
class Son4extends Father {}
class Son4extends Father {}
- 全部保留
- 方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
- 泛型方法的格式:
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
public staticList copyFromArrayToList(E[] arr) throws Exception{} - 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
- 换句话说,泛型方法所属的类是不是泛型类都没有关系。
- 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
public class Order泛型类和泛型方法的使用情境{ public Order(){ T[] arr = (T[]) new Object[10]; } public static List copyFromArrayToList(E[] arr){ ArrayList list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } } @Test public void test(){ Order order = new Order<>(); Integer[] arr = new Integer[]{1,2,3,4}; //泛型方法在调用时,指明泛型参数的类型。 List list = order.copyFromArrayToList(arr); System.out.println(list); }
数据访问对象DAO-Data(base) Access Object
定义数据库的通用 *** 作
DAO.java
public class DAO{//表的共性 *** 作的DAO //添加一条记录 public void add(T t){ } //删除一条记录 public boolean remove(int index){ return false; } //修改一条记录 public void update(int index,T t){ } //查询一条记录 public T getIndex(int index){ return null; } //查询多条记录 public List getForList(int index){ return null; } //泛型方法 //举例:获取表中一共有多少条记录?获取最大的员工入职时间? public E getValue(){ return null; } }
Customer.java
public class Customer { //此类对应数据库中的customers表}
CustomerDAO.java
public class CustomerDAO extends DAO
Student.java
public class Student {}
StudentDAO.java
public class StudentDAO extends DAO
DAOTest.java
public class DAOTest { public static void main(String[] ages){ CustomerDAO dao1 = new CustomerDAO(); dao1.add(new Customer()); Listlist = dao1.getForList(10); StudentDAO dao2 = new StudentDAO(); Student student = dao2.getIndex(1); Long Value = dao2.getValue(); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)