就像垃圾分类一样,垃圾箱上写着什么类型,就往里面丢什么类型的垃圾。泛型是String类型的,就只能填String类型的数据。
GenericTest.java
package com.atguigu.java;
import org.junit.Test;
import java.util.*;
public class GenericTest {
//在集合中使用泛型之前的情况:
@Test
public void test1(){
ArrayList list = new ArrayList();
//比如需求:存放学生的成绩
list.add(78);
list.add(76);
list.add(89);
list.add(88);
//问题一:类型不安全,加成绩时也能加进 Tom这个名字
list.add("Tom");
for(Object score : list){
//问题二:强转时,可能出现ClassCastException(出现了一些不是成绩的,其他类型的变量,比如Tom, Tom转换不成Integer。)
int stuScore = (Integer) score;//Integer自动拆箱赋给int
System.out.println(stuScore);
}
}
//在集合中使用泛型的情况:以ArrayList为例
@Test
public void test2(){
//在使用泛型时,泛型是一个类型,泛型不能是基本数据类型,所以这里不能用int。
//凡是在类声明的时候指定了的数据类型,比如ArrayList指定了Integer,那么这个类中所有用到泛型的地方都被指定为Integer类型。
ArrayList list = new ArrayList();
list.add(78);
list.add(87);
list.add(99);
list.add(65);
//编译时,就会进行类型检查,保证数据的安全,Tom不属于Integer,所以在编译时查出错误。
// list.add("Tom");
//方式一:
// for(Integer score : list){
// //避免了强转操作
// int stuScore = score;//Integer自动拆箱
//
// System.out.println(stuScore);
//
// }
//方式二:
//list.iterator()返回值是Iterator类型的。
// Iterator指明Integer了,它的类里面E next();也指定了Integer next();
Iterator iterator = list.iterator();// ↓
while(iterator.hasNext()){// ↓
int stuScore = iterator.next();//所以这里就返回Integer,不用强转类型了。
System.out.println(stuScore);
}
}
//在集合中使用泛型的情况:以HashMap为例
@Test
public void test3(){
//key是String类型的,value是Interger类型的
//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");//这里不匹配泛型,报错
//泛型的嵌套
// entrySet()的返回值是 Set>
//Set<>的泛型是,Entry<> 的泛型是
// 因为Entry是个内部接口,所以这里用Map.Entry.
// 如果上面导入了import java.util.Map.*;这里可以直接用Entry
Set> entry = map.entrySet();
//idea 调用方法赋给变量 – 快捷键 ctrl+alt+v
//Iterator < >放的是遍历的数据是什么类型的,此处应该是>类型的。
Iterator> iterator = entry.iterator();
//此处我理解为Set是一个容器,里面的数据类型是Map.Entry ;
// 迭代器Iterator要遍历的,要指向的数据也是Map.Entry 类型的,所以迭代器Iterator的泛型也是Map.Entry 类型的。
//即如果迭代器Iterator没有指定泛型,那么这个迭代器可以迭代任意的数据,如果指定了泛型,其指针就只能指向Map.Entry 类型的对象,只能遍历这个类型的对象。
while(iterator.hasNext()){
Map.Entry e = iterator.next();
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key + "----" + value);
}
}
}
自定义泛型类和泛型方法举例
泛型类
第二条:声明构造器的时候不用加泛型<>,
new对象的时候加泛型<>。new Order。
第三条:就是 实例化后,原来泛型T的地方,比如T name,在指定泛型为String类型后,就要按String name;使用。
第四条:见GenericTest1.java中的test3。
第九条:见GenericTest1.java中的test4,和Order.java的static show()方法。
第十条:见 MyException.java和Order.java的public void show()。
boolean add(E e);不是泛型方法;
泛型方法是格外的有一个新的标识,如果类用,泛型方法的新的标识可以用比如。
泛型方法是针对于方法来讲的,和泛型方法所在的类是否是泛型的无所谓。
泛型方法的测试在 Order.java中的
public static List copyFromArrayToList(E[] arr)方法
和在GenericTest1.java中的test4中测试中。
package com.atguigu.java; import java.util.ArrayList; import java.util.List; public class OrderSubOrder.java{ String orderName; int orderId; //类的内部结构就可以使用类的泛型 T orderT;//声明T类型的变量 public Order(){ //编译不通过 // T[] arr = new T[10];//new 后边这个T要求是具体是指明的,不能是泛型T //编译通过 T[] arr = (T[]) new Object[10]; //先new Object[]类的数组,再强转为T[]。 //到时候如果new对象,如果前面是Order类型的,那么后边的要new Order或者其子类对象类型的。 // 不能真new Object[],不然强转会发生错误。 } public Order(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; } @Override public String toString() { return "Order{" + "orderName='" + orderName + ''' + ", orderId=" + orderId + ", orderT=" + orderT + '}'; } //静态方法中不能使用类的泛型。 //类的泛型是实例化的时候指定的,而静态结构早于对象的创建,相当于类型还没指定了,静态方法就要用了,这不行。 // public static void show(T orderT){ // System.out.println(orderT); // } public void show(){ //编译不通过 // try{ // // // }catch(T t){//这里的T不能写,写T会出错,因为如果T这不是一个异常类型,那么这段代码就过不去了,跑不了了。 // // } } //★泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。 //换句话说,泛型方法所属的类是不是泛型类都没有关系。 //泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。 //public List copyFromArrayToList(E[] arr) 会被系统误认为E可能是一个类。为了表示这是泛型,要在前面价格 . //本方法目的是是将数组arr中的取出来放在List中,然后将List返回。 public static List copyFromArrayToList(E[] arr){ //这个 是在我调用的时候确定的,调用时不管是类调用的还是对象调用的,调用的时候告诉方法是什么类型就行,所以可以是static 的。 ArrayList list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; //在GenericTest1.java中的test4中测试 } }
package com.atguigu.java; import java.util.ArrayList; import java.util.List; public class SubOrder extends OrderSubOrder1.java{//SubOrder:不是泛型类,因为已经指明了Integer。 //这个SubOrder不是泛型类,同样能有泛型方法。 public static List copyFromArrayToList(E[] arr){ ArrayList list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } }
package com.atguigu.java; public class SubOrder1MyException.javaextends Order { //继承父类时并没有指明泛型类是什么 // 一般来说,如果指定了父类的泛型,那么子类就只能单一的new那一种泛型类的对象了, // 如果向子类仍然能new很多泛型类的对象,那么就在子类对象后边添一个泛型,此时 //SubOrder1 :仍然是泛型类 }
package com.atguigu.java; //异常类不能声明为泛型类 //public class MyExceptionGenericTest1.javaextends Exception{ //}
package com.atguigu.java;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class GenericTest1 {
@Test
public void test1(){
//如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
//要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。
Order order = new Order();
order.setOrderT(123);
order.setOrderT("ABC");
//建议:实例化时指明类的泛型
Order order1 = new Order("orderAA",1001,"order:AA");
order1.setOrderT("AA:hello");
}
@Test
public void test2(){
SubOrder sub1 = new SubOrder();
//由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
//子类指定泛型是了,那么从父类继承过来的方法也是Interger的
sub1.setOrderT(1122);
SubOrder1 sub2 = new SubOrder1<>();
sub2.setOrderT("order2...");//此时sub2.setOrderT(参数是String类型)
}
@Test
public void test3(){
ArrayList list1 = null;
ArrayList list2 = new ArrayList();
//泛型不同的引用不能相互赋值。
//list1 = list2;//不能这样赋值,报错。
}
//测试泛型方法,泛型方法的调用
@Test
public void test4(){
Order order = new Order<>();
Integer[] arr = new Integer[]{1,2,3,4};
//泛型方法在调用时,指明泛型参数的类型。
//List的Interger是由放进order.copyFromArrayToList(arr)的数组arr决定的。
// arr数组的元素类型是Interger的,所以集合List中装的也是Interger类型。
List list = order.copyFromArrayToList(arr);
System.out.println(list);
//[1, 2, 3, 4]
}
}
举例泛型类和泛型方法的使用情景
DAO.java
package com.atguigu.java1; import java.util.List; public class DAOCustomer.java{//此类是表的共性操作的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; } }
package com.atguigu.java1;
public class Customer { //此类对应数据库中的customers表
}
CustomerDAO.java
package com.atguigu.java1; public class CustomerDAO extends DAOStudentDAO.java{//只能操作某一个表的DAO // 此处泛型填了Customer,DAO中的方法就具体了,此类只能操作Customer。 }
package com.atguigu.java1; public class StudentDAO extends DAODAOTest.java{//只能操作某一个表的DAO }
package com.atguigu.java1;
import org.junit.Test;
import java.util.List;
public class DAOTest {
@Test
public void test1(){
CustomerDAO dao1 = new CustomerDAO();
dao1.add(new Customer());//由于CustomerDAO指定了泛型为Customer,此时add只能添加Customer类型的数据。
List list = dao1.getForList(10);
StudentDAO dao2 = new StudentDAO();
Student student = dao2.getIndex(1);//返回的也是Student,即指定的泛型的
}
}
泛型在继承方面的体现
见GenericTest.java中test1和test2。
通配符的使用 和 使用通配符后数据的读取和写入要求见GenericTest.java中test3
有限制条件的通配符的使用见GenericTest.java中test4
package com.atguigu.java2;
public class Person {
}
Student.java
package com.atguigu.java2;
public class Student extends Person {
}
GenericTest.java
package com.atguigu.java2;
import org.junit.Test;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest {
@Test
public void test1(){
Object obj = null;
String str = null;
obj = str;//多态,子类赋给父类
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;//也是多态,如果之后赋值后,数组每个对象都是多态
//List
自定义泛型类练习
User.java
package com.atguigu.exer1;
public class User {
private int id;
private int age;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + ''' +
'}';
}
// 此题key是String类型 ,User是value。只是key需要equals和hashCode方法,是map中的键才要,值不需要。
// 所以本题不用重写equals()和hashcode()方法
// @Override
// public boolean equals(Object o) {
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
//
// User user = (User) o;
//
// if (id != user.id) return false;
// if (age != user.age) return false;
// return name != null ? name.equals(user.name) : user.name == null;
// }
//
// @Override
// public int hashCode() {
// int result = id;
// result = 31 * result + age;
// result = 31 * result + (name != null ? name.hashCode() : 0);
// return result;
// }
}
DAO.java
package com.atguigu.exer1; import java.util.*; public class DAODAOTest.java{ private Map map = new HashMap (); //保存 T 类型的对象到 Map 成员变量中 public void save(String id,T entity){ map.put(id,entity); } //从 map 中获取 id 对应的对象 public T get(String id){ return map.get(id); } //替换 map 中key为id的内容,改为 entity 对象 public void update(String id,T entity){ if(map.containsKey(id)){ map.put(id,entity); } } //返回 map 中存放的所有 T 对象 public List list(){ //错误的: // Collection values = map.values(); //父类型可以转化为子类型,前提是就是子类转上去的,可以再转下来.这返回值就是Collection 类型的, // return (List ) values;//强转为List ,太勉强了 //正确的: ArrayList list = new ArrayList<>(); Collection values = map.values(); //遍历容器Collection中每一个 T类型的数据,然后装入list当中。 for(T t : values){ list.add(t); } return list; } //删除指定 id 对象 public void delete(String id){ map.remove(id); } }
package com.atguigu.exer1;
import java.util.List;
public class DAOTest {
public static void main(String[] args) {
DAO dao = new DAO();
dao.save("1001",new User(1001,34,"周杰伦"));//存储一个数据
dao.save("1002",new User(1002,20,"昆凌"));
dao.save("1003",new User(1003,25,"蔡依林"));
dao.update("1003",new User(1003,30,"方文山"));//更新一个数据
dao.delete("1002");//删除一个数据
List list = dao.list();//调用list()方法,返回 map 中存放的所有 T 对象
//System.out.println(list);//输出list
list.forEach(System.out::println);//遍历list
//User{id=1003, age=30, name='方文山'}
//User{id=1001, age=34, name='周杰伦'}
}
}



