什么是泛型?
Java泛型(generics)是JDK 5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。可以理解为在创建对象时,对类中成员的数据类型进行限定。
定义泛型
泛型可以定义在类、方法和接口上,定义泛型方法的规则有以下几条:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(如int,double,char等)。
public class 类名<泛型, 泛型........>{
private 泛型标识 变量名;
}
//创建泛型对象时,可以使用具体的数据类型代替泛型
类名<数据类型> 对象名=new 类名<>();
泛型通配符
无边界的通配符(Unbounded Wildcards)
通配符采用 <?> 的形式,比如 List<?>,无边界的通配符的主要作用就是让泛型能够接受未知类型的数据。
固定上边界的通配符(Upper Bounded Wildcards)
使用固定上边界的通配符的泛型,就能够接受指定类及其子类类型的数据。要声明使用该类通配符,采用 <? extends E> 的形式,这里的 E 就是该泛型的上边界。
这里虽然用的是 extends 关键字,却不仅限于继承了父类 E 的子类,也可以代指实现了接口 E 的类。
声明对象: 类名称<? extends 类1> 对象名称 = new 类名称<类2>();
定义类: [访问权限] 类名称<泛型标识 extends 类>{}
固定下边界的通配符(Lower Bounded Wildcards)
使用固定下边界的通配符的泛型,就能够接受指定类及其父类类型的数据。要声明使用该类通配符,采用 <? super E> 的形式,这里的 E 就是该泛型的下边界。
可以为一个泛型指定上边界或下边界,但是不能同时指定上下边界。
声明对象: 类名称<? super 类1> 对象名称 = new 类名称<类2>();
定义类: [访问权限] 类名称<泛型标识 super 类>{}
泛型接口
接口子类同样声名泛型
直接在子类后声明泛型,但需要注意的是子类的泛型标识名称要与接口的泛型标识名称保持一致。
public class 类名<泛型标识...> implements 接口<泛型标识...>{
代码块
}
子类指定接口的泛型类型
在子类实现接口时,直接指明接口的泛型类型。
public class 类名 implements 接口<泛型类型>{
代码块
}
泛型方法
在类中可以定义泛型化的方法,泛型方法的定义与其所在的类是否是泛型类无关,其语法为:[访问权限] <泛型标识> 泛型标识 方法名称(泛型标识 参数名称)。
public <T> T generic(T t) {
return t;
}
课后作业
- 第一题:开发一个泛型Apple类,要求有一个重量属性weight在测试类中。实例化不同的泛型对象,要求对象a1的这一属性是String类型,对象a2的这一属性是Integer型,a3的这一属性是Double型。分别为a1,a2,a3的重量属性赋值为:”500克”,500,500.0,在测试类中通过对象调用访问器得到属性值并输出。
public class work01 {
public static void main(String[] args) {
Apple<String> apple1 = new Apple<>("500克");
System.out.println(apple1.getWeight());
Apple<Integer> apple2 = new Apple<>(500);
System.out.println(apple2.getWeight());
Apple<Double> apple3 = new Apple<>(500.0);
System.out.println(apple3.getWeight());
}
}
class Apple<E> {
private E weight;
public Apple(E weight) {
this.weight = weight;
}
public E getWeight() {
return weight;
}
public void setWeight(E weight) {
this.weight = weight;
}
}
- 第二题:自己定义一个泛型接口,其中有一个eat方法。用一个Person类实现这个接口,传入的泛型实参是String类型,实现的方法内容自己定义,最后在main中调用eat方法。
public class work02 {
public static void main(String[] args) {
Person<String> person = new Person<>();
person.eat("吃丸子");
}
}
interface Myin<T> {
void eat(T t);
}
class Person<T> implements Myin<T> {
@Override
public void eat(T t) {
System.out.println("嘉然今天吃什么," + t);
}
}
- 第三题:定义个泛型类 DAO,在其中定义一个 Map 成员变量,Map 的键为 String 类型,值为 T 类型。分别创建以下方法:
public void save(String id,T entity): 保存 T 类型的对象到 Map 成员变量中
public T get(String id):从 map 中获取 id 对应的对象
public void update(String id,T entity):替换 map 中 key 为 id 的内容,改为 entity 对象
public List list():返回 map 中存放的所有 T 对象
public void delete(String id):删除指定 id 对象
定义一个 User 类:该类包含:private 成员变量(int 类型) id,age;(String 类型)name。
定义一个测试类:
创建 DAO 类的对象, 分别调用其 save、get、update、list、delete 方法来操作 User 对象,并进行测试。
public class work03 {
public static void main(String[] args) {
user user1 = new user(1, 18, "张三");
user user2 = new user(2, 19, "李四");
user user3 = new user(3, 22, "王五");
user user4 = new user(4, 21, "赵六");
DAO<user> dao = new DAO<>(new HashMap<>());
//存入元素
dao.save("1", user1);
dao.save("2", user2);
dao.save("3", user3);
//获取指定元素
System.out.println(dao.get("3"));
//更新指定元素
dao.update("3", user4);
//返回所有value
System.out.println(dao.list());
//删除指定元素
dao.delete("1");
}
}
class DAO<T> {
private HashMap<String, T> hashMap;
public void save(String id, T entity) {
hashMap.put(id, entity);
}
public T get(String id) {
return hashMap.get(id);
}
public void update(String id, T entity) {
this.save(id, entity);
}
public List<T> list() {
return new ArrayList<>(hashMap.values());
}
public void delete(String id) {
hashMap.remove(id);
}
public HashMap<String, T> getHashMap() {
return hashMap;
}
public DAO(HashMap<String, T> hashMap) {
this.hashMap = hashMap;
}
}
class user {
private int id;
private int age;
private String name;
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
public user(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
}
- 第四题:ArrayList 请你模拟ArrayList自己创建一个集合类。底层就是OBject[]数组,并处理数组的扩容问题。
public class work04 {
public static void main(String[] args) {
user user1 = new user(1, 18, "张三");
user user2 = new user(2, 19, "李四");
user user3 = new user(3, 22, "王五");
user user4 = new user(4, 21, "赵六");
MyArrayList<user> arrayList = new MyArrayList<>(new user[2]);
arrayList.add(user1);
arrayList.add(user2);
arrayList.add(user3);
arrayList.add(user4);
arrayList.show();
}
}
class MyArrayList<T> {
private T[] objects;
//真实长度
private int realLength = -1;
//如果数组存满,则扩容1.5倍
public void add(T t) {
if (++realLength >= objects.length) {
objects = Arrays.copyOf(objects, (int) (objects.length * 1.5));
}
objects[realLength] = t;
}
public void show() {
for (T object : objects) {
System.out.println(object);
}
}
public MyArrayList(T[] objects) {
this.objects = objects;
}
}