在之前学过的集合框架中,List和Map都使用了泛型技术来确认其内容的数据类型。
如果不使用泛型,在程序运行阶段,会带来数据类型转型的错误风险。
List<String> list = new ArrayList<String>();
list.add("tom");
for (int i = 0; i < list.size(); i++) {
String obj = list.get(i);
System.out.println(obj);
}
List list2 = new ArrayList();
list2.add("helen");
list2.add(2); // 自动装箱成Integer
list2.add(true); // 自动装箱成Boolean
for (int i = 0; i < list2.size(); i++) {
String obj = (String)list2.get(i); // 此处是有风险的
}
在Java中,使用变量之前,必须要先定义变量的数据类型,存在一种特殊的现象,就是多态(数据类型是父类,实现对象是子类),变量赋值不一定要完全和数据类型一致,可以赋予子类对象给它。
public class Client2 {
public static void main(String[] args) {
Point point = new Point();
point.x = "东经102°";
point.y = "北纬32°";
point.x = 102;
point.y = 32;
String s = (String) point.x;
point.print();
}
}
class Point {
Object x;
Object y;
public void print() {
System.out.println(x + "" + y);
}
}
向下转型会带来数据风险的(ClassCastException)
不使用泛型的缺点:需要强制转换;可向集合中添加任意类型的对象,存在风险
泛型的使用:在接口/类名后的尖括号内加上类型,如 List list=new ArrayList();
同时,变量声明时的泛型类和其实现类时的泛型类必须相同,即“=”前后的尖括号中的类型需要一致
class Animal{}
class Cat extends Animal {}
List<Animal> list = new ArrayList<Cat>();
这样是不允许的。变量声明的类型必须匹配传递给实际对象的类型
泛型作为方法参数
泛型作为方法参数
案例: 定义一个抽象类Goods,包含抽象方法sell(); 分别定义各类商品Book,Clothes和Shoes继承Goods,并实现sell()方法,输出一句话,如sell books 定义一个商品销售类GoodsSeller,模拟销售,包括方法:public void sellGoods(List goods),循环调用list对象的sell() 方法
public abstract class Goods {
public abstract void sells();
}
public class Books extends Goods{
@Override
public void sells() {
System.out.println("sell books");
}
}
public class Clothes extends Goods {
@Override
public void sells() {
System.out.println("sell clothes");
}
}
public class Shoes extends Goods {
@Override
public void sells() {
System.out.println("sell shoes");
}
}
public class GoodsSeller {
//代表只要goods参数保存的元素是Goods或者Goods的子类,都可以
public void sellGoods(List<? extends Goods> goods) {
//调用集合中的sell方法
for(int i = 0; i < goods.size(); i++) {
Goods g = goods.get(i);
g.sells();
}
}
}
public class Test {
public static void main(String[] args) {
//定义books相关的list
List<Books> bookLst = new ArrayList<Books>();
bookLst.add(new Books());
bookLst.add(new Books());
//定义Shoes相关的list
List<Shoes> shoesLst = new ArrayList<Shoes>();
shoesLst.add(new Shoes());
shoesLst.add(new Shoes());
//定义Clothes相关的list
List<Clothes> clothesLst = new ArrayList<Clothes>();
clothesLst.add(new Clothes());
clothesLst.add(new Clothes());
GoodsSeller gdSeller = new GoodsSeller();
gdSeller.sellGoods(bookLst);
}
}
自定义泛型类
public class Demo {
public static void main(String[] args) {
Point<Integer, Integer> p = new Point<Integer, Integer>();
p3.x = 1;
p3.x = 2;
}
}
public class Point<T1, T2> {
T1 x;
T2 y;
}
类的泛型在className之后定义,只有定义的泛型类型才能在类中使用。
即我们定义只有先定义类名后的泛型标志符的时候,才能使该泛型类使用泛型定义方法和成员变量。
自定义泛型方法
泛型方法不一定要写在泛型类中
/**
* 定义泛型方法
**/
public class GenericMethod {
//定义泛型方法的时候需要将泛型放在访问修饰符和返回值中间
public <T extends Number> void print(T t) {
System.out.println(t.toString());
}
public static void main(String[] args) {
GenericMethod gm = new GenericMethod();
//可以通过泛型方法实现一个方法传递不同的参数
//gm.print("123");规定泛型的继承限定之后,该行语句就是错误的了
gm.print(123);
gm.print(123f);
}
}
泛型一般使用于框架设计,在实际的应用开发中较少运行
Java泛型中的标记符含义:
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型<K,V>
就是代表键值对的泛型