泛型
一、泛型概述和基本使用
-
A:泛型概述:java泛型其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
-
B:泛型好处
- 提高安全性(将运行期的错误转换到编译期)
- 省去强转的麻烦
-
C:泛型基本使用
- <>中放的必须是引用数据类型
-
D:泛型使用注意事项
- 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性菱形泛型)
1、我们举一个例子来看一下泛型的好处:
我们有一个Person实体类,属性是name跟age。
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("张三", 23));
list.add(new Person("李四", 24));
Iterator<Person> it = list.iterator();
while(it.hasNext()) {
//next方法只能调用一次,如果调用多次会将指针向后移动多次
Person p = it.next();
System.out.println(p.getName() + "..." + p.getAge()); //输出张三23,李四24
}
}
2、我们举一个例子来看一下前后的泛型必须一致:
public static void main(String[] args) {
//ArrayList<Object> list = new ArrayList<Person>(); //集合的泛型要保证前后的数据类型一致
//ArrayList<Object> list = new ArrayList<>(); //1.7版本的新特性,菱形泛型,前面写了,后面可以不写
ArrayList<Object> list = new ArrayList<>(); //泛型最好不要定义成Object,没有意义
list.add("aaa");
list.add(true);
}
二、ArrayList存储字符串和自定义对象并遍历泛型版
1、存储字符串遍历
/**
* * A:案例演示
* ArrayList存储字符串并遍历泛型版
*/
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>(); //创建集合对象
list.add("a");
list.add("b");
list.add("c");
list.add("d");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next()); //输出a,b,c,d
}
}
2、存储自定义对象遍历
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("张三", 23));
list.add(new Person("李四", 24));
list.add(new Person("王五", 25));
list.add(new Person("赵六", 26));
Iterator<Person> it = list.iterator();
while(it.hasNext()) {
Person p = it.next(); //将集合中的每一个元素用Person记录
System.out.println(p.getName() + "..." + p.getAge()); //输出是上面添加的四个person
}
}
三、泛型类的概述及使用
- A:泛型类概述
- 把泛型定义在类上
- B:定义格式
- public class 类名<泛型类型1,…>
- C:注意事项
- 泛型类型必须是引用类型
创建一个Person类
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
创建一个Student类,继承Person
public class Student extends Person {
public Student() {
}
public Student(String name, int age) {
super(name, age);
}
}
接着重头戏,创建一个泛型类
// 一般呢我们要求泛型是一个字符,大写的,如果给其他的字母,小写的也是可以的
// T代表的的是类型,E代表的元素,没有任何意义,随便来个Q也是可以的
// 这个Q什么时候有值呢?当我们用Tool这个工具类去创建对象的时候,就去指定泛型,指定泛型是什么,那么这个Q就是什么。
public class Tool<Q> {
private Q q;
public Q getObj() {
return q;
}
public void setObj(Q q) {
this.q = q;
}
}
我们测试一下
public static void main(String[] args) {
Tool<Student> t = new Tool<>(); //创建工具类对象Tool,指定泛型是Student
t.setObj(new Student("张三",23));
}
四、泛型方法的概述和使用
- A:泛型方法概述
- 把泛型定义在方法上
- B:定义格式
- public <泛型类型> 返回类型 方法名(泛型类型 变量名)
1、第一种方式:
接着我们上面的 泛型类的概述及使用 ,我们在Tool工具类中添加一个泛型方法。
public void show(Q q) {
System.out.println(q);
}
我们测试一下
public static void main(String[] args) {
Tool<String> t = new Tool<>();
t.show("abc"); //输出abc
}
2、第二种方式:
我们再在Tool工具类中添加另外一个泛型方法,这个方法泛型跟类的泛型不一致
public<T> void showone(T t) { //方法泛型最好与类的泛型一致
System.out.println(t); //如果不一致,需要在方法上声明该泛型,等于这个方法拥有了属于自己的泛型
}
我们测试一下
public static void main(String[] args) {
Tool<String> t = new Tool<>();
t.show(true); //输出true
}
3、第三种方式:
我们再在Tool工具类中添加另外一个静态泛型方法
//静态方法必须声明自己的泛型,静态泛型方法如果不声明自己的泛型,就会报错
/*报错的原因是,因为它是静态的,静态方法是随着类的加载而加载的,当我们的类加载的时候,
可能还没有创建对象,没有创建对象,W就没有值,就会报错。
*/
public static<W> void print(W w) { //静态方法必须声明自己的泛型
System.out.println(w);
}
我们测试一下
public static void main(String[] args) {
Tool<String> t = new Tool<>();
t.show("1111"); //输出1111
}
五、泛型接口的概述和使用
- A:泛型接口概述
- 把泛型定义在接口上
- B:定义格式
- public interface 接口名<泛型类型>
1、第一种方式,指定泛型,推荐使用这种:
直接看代码
/**
测试
*/
public class StringBuffer_01 {
public static void main(String[] args) {
Demo d = new Demo();
d.show("asdasdasd"); //输出asdasdasd
}
}
/**
* 定义一个泛型接口
* @param <T>
*/
interface Inter<T> {
public void show(T t);
}
/**
* 实现泛型接口
*/
class Demo implements Inter<String> {
public void show(String t) {
System.out.println(t);
}
}
2、第二种方式,不指定泛型:
直接看代码
/**
测试
*/
public class StringBuffer_01 {
public static void main(String[] args) {
Demo d = new Demo();
d.show("asdasdasd"); //输出asdasdasd
}
}
/**
* 定义一个泛型接口
* @param <T>
*/
interface Inter<T> { //推荐用这种
public void show(T t);
}
/**
* 实现泛型接口
*/
class Demo<T> implements Inter<T> { //没有必要在实现接口的时候给自己类加泛型
public void show(T t) {
System.out.println(t);
}
}
六、泛型高级之通配符
- A:泛型通配符<?>
- 任意类型,如果没有明确,那么就是Object以及任意的Java类了
- B:? extends E
- 向下限定,E及其子类
- C:? super E
- 向上限定,E及其父类
A,B例子:
public static void main(String[] args) {
//A:泛型通配符<?>
//List<?> list = new ArrayList<Integer>(); //当右边的泛型是不确定时,左边可以指定为?
//B:? extends E
ArrayList<Person> list1 = new ArrayList<>();
list1.add(new Person("张三", 23));
list1.add(new Person("李四", 24));
list1.add(new Person("王五", 25));
ArrayList<Student> list2 = new ArrayList<>();
list2.add(new Student("赵六", 26));
list2.add(new Student("周七", 27));
list1.addAll(list2);
System.out.println(list1);
}