文章目录
1.为什么要有泛型
集合容器类在设计阶段/声明阶段不能确定这个容器到底存的是什么类型的对象,所以 在JDK1.5之前只能把元素类型设计Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时 把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection<E>,List<E>,ArrayList<E> 这个<E>就是类型参数,即泛型
泛型相比Object,能解决元素存储的安全性问题;解决获取数据元素时,需要类型强制转换的问题
public class Main {
public static void main(String[] args){
ArrayList list = new ArrayList();
list.add(67);
list.add(89);
list.add(64);
list.add(99);
// 问题一:类型不安全
list.add("78");
for (Object o : list) {
int score = (Integer) o;
System.out.println(score);
}
}
}
2.在集合中使用泛型
1.集合接口或集合类在 jdk5.0时都修改为带泛型的结构
2.在实例化集合类时,可以指明具体的泛型类型
3.指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(方法、构造器、属性、内部类等)使用到类的泛型的位置,都指定完实例化时的类型,如: ArrayList<Integer> list = new ArrayList<Integer>(); list.add(E e) --> list.add(Integer integer)
4.泛型的类型必须是类,不能是基本数据类型。需要用到基本数据用包装类型替换
5.如果实例化时,没有指明泛型的类型,则默认为:java.lang.Object类型。
public class Main{
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(67);
list.add(89);
list.add(64);
list.add(99);
// list.add("67"); 编译时就会进行类型检查
for (Integer integer : list) {
System.out.println(integer); // 无需做类型强制转换
}
}
}
public class Main{
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>(); // jdk8新特性,类型推断
map.put("张三",56);
map.put("李四",67);
map.put("小红",89);
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
3.自定义泛型结构
自定义泛型类、泛型接口、泛型方法
(子类继承父类的泛型时指定类型, extends person<Integer>,子类实例化不用指定类型)
(子类继承父类的泛型时没有指定类型, extends person<T>,此时子类仍然是泛型类)
说明:
1.泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
2.泛型类的构造器如下:public GenericClass()。而这种是错误的:public GenericClass<E>(). 而是实例化时加上<>,person<Integer> p = new person<>();
3.实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
4.泛型不同的引用不能相互赋值。
5.泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型要使用一路都用。要不用,一路都不要用
6.静态结构中不能使用泛型,异常类中也不能使用泛型
7.不能够 T[] arr = new T[10],可以改为: T[] arr = (T[ ])new Object[10] ,new了Object数组,但是只能放T类型的数据
8.父类有泛型,子类可以选择保留、部分保留(Object)或不保留泛型(Object)也可以选择指定泛型类型
3.1 泛型类与接口
// 泛型类,泛型接口与泛型类相似。实现接口指定类型
class person<T> {
int id;
T t;
String name;
public person(int id, T t, String name) {
this.id = id;
this.t = t;
this.name = name;
}
public void setT(T t) {
this.t = t;
}
}
public class Main{
public static void main(String[] args){
person p1 = new person(); //若实例化时没有指定,则为Object类型
p1.setT(123);
p1.setT("we");
person<Integer> p2 = new person<>(); // 实例化时指明类的泛型
p2.setT(45);
}
}
3.2 泛型方法
boolean add(E e)不是泛型方法;<T> T[] toArray(T[] a)才是泛型方法,使用了不同的符号(T),与所在类是否带泛型结构无关 (方法形参类型不确定,在调用时指定类型)
并且在 返回类型前加上 <T>标识 此T不是类中的T,而是方法形参中的T
public class Main<E>{
E e;
public Main(E e){
this.e = e;
}
public E get(){ // 不是泛型方法
return e;
}
public static <T> List<T> v(T[] arr){ // 是泛型方法(可以是静态的,此T在调用时确定,不是是在对象实例化时确定)
ArrayList<T> list = new ArrayList<>();
...
return list;
}
public static void main(String[] args){
Integer[] arr = new Integer[]{1,2,3,4};
List<Integer> v = v(arr); // 调用时指明类型,并返回相应类型的list
System.out.println(v);
}
}
4.泛型在继承上的体现
虽然类A是类B的父类,但G<A>和G<B>二者不具备父类关系,二者是并列关系(A<G>是B<G>的父类)
public class Main{
public static void main(String[] args){
Object obj = null;
String str= null;
obj = str; // 可以
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2; // 可以
List<Object> list1 = null;
List<String> lsit2 = null;
lsit1 = list2; // 不可以,list1与 list2并没有子父类关系,都是 List类型。
// AbStractList<String> list;
List<String> list1 = null;
ArrayList<String> list2 = null;
list1 = list2; // 可以(继承或实现接口的关系都可以)
// List<String> list = new ArrayList<>();
}
}
5.通配符的使用
5.1 通配符 ?
? 【此时 list<?>相当于作为 List<String>和 List<Object>的父类使用】
public class Main{
public static void main(String[] args){
List<String> list1 = null;
List<Object> list2 = null;
List<?> list = null;
list = list1;
list = list2;
print_list(list1);
print_list(list2);
}
public void print_list(List<?> list){
for (Object o : list) {
System.out.println(o);
}
}
}
5.2 List<?>的读取
对于List<?>,不能够向其添加数据( ?不确定添加什么数据,但是什么对象都可以添加 null,所以可以添加null )
使用 Object o 读取 List<?>中的数据
public class Main{
public static void main(String[] args){
List<?> list = null;
List<String> list1 = new ArrayList<>();
list = list1;
list.add("abc"); // 编译不通过
}
}
5.3 含限制条件的通配符(<? extends/super class>)
1.通配符指定上限
上限extends: 使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
2.通配符指定下限
下限super: 使用时指定的类型不能小于操作的类,即>=
举例
<? extends person>: 只允许泛型为 person及 person的子类的引用调用
<? super person>: 只允许泛型为 person及 person的父类的引用调用
<? extends person>: 只允许泛型为实现 Comparetor接口的实现类的引用调用
添加:
<? extends person>: 表示接受的类型小于等于person(负无穷到person中的一个),无法添加数据
<? super person>: 表示接受的类型大于等于person(person到正无穷中的一个),多态性可以添加person的及person的子类的数据
class person{
}
class student extends person{
}
public class Main{
// 往下:最大范围是student ,要求使用student或以上的类型接受数据
public void v(List<? extends student> list){
for (student student : list) {
System.out.println(student);
}
}
// 往上:最大范围是Object,用Object类型接受,也只能用Object
public void v1(List<? super student> list){
for (Object o : list) {
System.out.println(o);
}
}
}
6.泛型应用举例
public class BasicDao<T> {
private QueryRunner qr = new QueryRunner();
// DML操作方法的通用方法
public int update(String sql, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtils.getConnection();
int update = qr.update(connection, sql, parameters);
return update;
} catch (SQLException e) {
throw new RuntimeException();
} finally {
JDBCUtils.close(null, null, connection);
}
}
}
public class carDao extends BasicDao<car> {
// 添加车辆
public int addCar(car c) {
String sql = "insert into car values (?,?,?,?,?,?,?)";
return super.update(sql, c.getC_id(), c.getModel(), c.getColor(),
c.getPrice(), c.getFactoryDate(), c.getManufacturer(), c.getState().toString());
}
// 删除车辆
public int delCar(String c_id) {
String sql = "delete from car where c_id = ?";
return super.update(sql, c_id);
}
}
public class customerDao extends BasicDao<customer>{
// 添加客户
public int addCustomer(customer cu){
String sql = "insert into customer(cu_name,cu_telephone,level) values (?,?,?)";
return super.update(sql, cu.getCu_name(), cu.getCu_telephone(), cu.getLevel().toString());
}
// 删除客户
public int deleteCustomer(String cu_id){
String sql = "delete from customer where cu_id = ?";
return super.update(sql, cu_id);
}
}