一.泛型的架构
1.泛型的整体架构
2.泛型的的概述
①泛型的简介
/*
1.泛型的简介
–为什么出现泛型?
因为在实际使用中,集合可以存储不同类型的变量,但是我们需要存储同一类型的变量,故此时加入泛型
2.自定义泛型
泛型类,泛型方法
泛型类:在类声明时定义,即在属性,方法,构造器结构中需要使用T类型则直接使用即可
泛型方法:在方法声明时定义,然后再传入形参时确定M的类型,在方法内部可以使用M类型
3.泛型的注意点
子类继承父类,显式声明父类的泛型,则子类不是泛型
子类继承父类,保留父类泛型中的一个,则子类也是泛型
注意:异常类不使用泛型
注意:泛型不同但具有子父类关系而类相同的引用不可以赋值
注意:泛型相同而类具有子父类关系的可以赋值
注意:静态方法不可以使用类泛型,因为类.方法在实例化之前可以使用
注意:静态方法可以使用方法泛型,因为类.方法即可确定泛型方法
注意:不能写new T[],此时识别不了是类还是泛型,故需要(T[])new object[10]。即数组的类型不能是泛型。可以理解为数组new则需要分配空间,如若T则不清楚分配什么。
*/
②通配符
/*
1.通配符概述
通配符可以解决 类相同而泛型不同不能赋值的问题
2.通配符使用
通配符?可以使得上述可以赋值,但是只能看不能写
3.限制条件通配符
理解条件通配符:即设用了一个?extends A,和?super A分别代表了A的子类和A的父类
A的子类:可以赋值给A和A的子类,此时只能读不能写,因为写有可能遇到同级或者更小的子类(不一定有的属性)
A的父类:可以赋值给A和A的父类,此时可以读可以写,因为此时只有可能是父类或自己写数据(肯定有的属性)
*/
二.泛型的代码
1.泛型的简介
/*
1.泛型的简介
--为什么出现泛型?
因为在实际使用中,集合可以存储不同类型的变量,但是我们需要存储同一类型的变量,故此时加入泛型
2.自定义泛型
泛型类,泛型方法
泛型类:在类声明时定义<T>,即在属性,方法,构造器结构中需要使用T类型则直接使用即可
泛型方法:在方法声明时定义<M>,然后再传入形参时确定M的类型,在方法内部可以使用M类型
3.泛型的注意点
子类继承父类,显式声明父类的泛型,则子类不是泛型
子类继承父类,保留父类泛型中的一个,则子类也是泛型
注意:异常类不使用泛型
注意:泛型不同但具有子父类关系而类相同的引用不可以赋值
注意:泛型相同而类具有子父类关系的可以赋值
注意:静态方法不可以使用类泛型,因为类.方法在实例化之前可以使用
注意:静态方法可以使用方法泛型,因为类.方法即可确定泛型方法
注意:不能写new T[],此时识别不了是类还是泛型,故需要(T[])new object[10]。即数组的类型不能是泛型。可以理解为数组new则需要分配空间,如若T则不清楚分配什么。
*/
public class Test1 {
//泛型的简介
@Test
public void test0(){
//存储年龄
Collection array = new ArrayList();
array.add(10);
array.add("123");//此时也能存储成功,即不满足我们的要求
ArrayList<Integer> array1 = new ArrayList<Integer>();
///array1.add("123");此时会报错,即需要int类型而不是String类型
HashMap<String, Integer> map = new HashMap<>();
map.put("小花",12);
Set<Map.Entry<String, Integer>> entry = map.entrySet();
Iterator<Map.Entry<String, Integer>> iter = entry.iterator();
Map.Entry<String,Integer> entry1 = iter.next();
String a = entry1.getKey();
Integer b = entry1.getValue();
System.out.println(a);
System.out.println(b);
}
//自定义泛型类
@Test
public void test(){
Cat<String> kitty = new Cat<>("我很肥");
System.out.println(kitty.Show());
System.out.println(kitty.eat("我爱吃鱼"));
}
//泛型的继承
public void test2(){
ArrayList<Object> a = new ArrayList<>();
ArrayList<String> b = new ArrayList<>();
//a = b ;类相同泛型具有父子类关系也不可赋值
List<String> c = new ArrayList<>();
ArrayList<String> d = new ArrayList<>();
c = d;//泛型相同类具有父子类关系的可以赋值
}
}
//自定义泛型类
class Cat<T>{
T exp;
//T[] b = new T[10];这种泛型的数组定义出错,因为不清楚是泛型还是实际的类(相对于new结构来说,引用无所谓)
T[] b = (T[])new Object[10];
Cat(T a){
exp = a;
}
public T Show(){
return exp;
}
//自定义泛型方法
public<M> String eat(M a){
return a + "";
}
//静态方法使用类的泛型
//会报错,即不能通过类.方法名来访问方法,确定不了泛型类型
// public static void walk(T a){
// return;
// }
//静态方法使用方法泛型
//不会报错:通过类.方法名访问方法时可以确定泛型方法的泛型
public static<M> M walk(M str){
return str;
}
}
2.通配符
/*
1.通配符概述
通配符可以解决 类相同而泛型不同不能赋值的问题
2.通配符使用
通配符?可以使得上述可以赋值,但是只能看不能写
3.限制条件通配符
理解条件通配符:即设用了一个?extends A,和?super A分别代表了A的子类和A的父类
A的子类:可以赋值给A和A的子类,此时只能读不能写,因为写有可能遇到同级或者更小的子类(不一定有的属性)
A的父类:可以赋值给A和A的父类,此时可以读可以写,因为此时只有可能是父类或自己写数据(肯定有的属性)
*/
public class Test2 {
public void test0(){
List<?> a = new ArrayList<>();
List<String> b = new ArrayList<>();
a = b;//此时可以赋值,a不能添加元素,只能读取元素
List<? extends Hashtable> list1 = null;
List<? super Hashtable> list2 = null;
List<Properties> list3 = null;
List<Hashtable> list4 = null;
List<Map> list5 = null;
list1 = list3;
list1 = list4;
//list1 = list5;赋值失败,说明可以赋值其本身或者子类,此时不能写数据,因为可能有比起更小的子类
//list2 = list3;赋值失败,说明可以赋值其本身或者其父类,此时可以写数据,因为最小都是本身
list2 = list4;
list2 = list5;
}
}