泛型
泛型是一种未知的,不确定的数据类型。
举例:
ArrayList<E>中的E就是一个泛型,是一个未知的数据类型。
泛型虽然是未知的数据类型,但是并不是一直未知,一直不确定,在我们使用一个类的时候,这个泛型表示的数据类型会被确定下来。
举例:
ArrayList<Student> 此时这个泛型类型E表示的就是Student类型。
泛型也可以省略,如果省略泛型相当于泛型是Object
泛型好处:
1. 省略了向下转型的代码。
2. 将运行时期的问题提前到了编译时期。
public static void main(String[] args) {
//创建集合,省略泛型 泛型也可以省略,如果省略泛型相当于泛型是Object
ArrayList list = new ArrayList();
//添加元素
//list.add(100); 运行时期报错
list.add("hello");
list.add("world");
list.add("java");
//遍历集合,输出集合中每一个字符串的长度
for (Object obj : list) {
//向下转型
String s = (String) obj;
// 因为length是字符串里的方法, obj是object类型,所以没法调用, 多态只能调用父类里的方法。
System.out.println(s.length());
}
System.out.println("===================");
//创建集合,使用泛型
ArrayList<String> list2 = new ArrayList<>();
//添加元素
//list2.add(100); 编译时期报错
list2.add("hello");
list2.add("world");
list2.add("java");
//遍历集合,输出集合中每一个字符串的长度
for (String str : list2) {
// 省略了向下转型的代码。
System.out.println(str.length());
}
}
- 泛型擦除
/*
泛型擦除
Java中的泛型都是伪泛型,泛型只在源代码阶段有效,一旦编译,泛型就会消失。
*/
public static void main(String[] args) {
//创建集合
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
//遍历集合(集合.for)
for (String s : list) {
System.out.println(s);
}
}
- 泛型类
泛型是一种未知的,一种不确定的数据类型。
如果在定义类的时候,类名后面写上<T>,就表示在类的范围内定义了一个泛型类型T(不确定的数据类型T)
这种未知的类型T等到我们使用这个类的时候就会被确定出来。
这个T可以使用其他字母代替。
例如:
public class myClass<T> {
}
- 泛型方法
泛型方法的定义格式:
修饰符 <泛型> 返回值类型 方法名(参数列表) {
方法体;
return 返回值;
}
在方法上定义的泛型,需要等到调用方法的时候才能确定。
//平板类
public class Pad {
public void study() {
System.out.println("平板学习");
}
}
//手机类
public class Phone {
public void call() {
System.out.println("打电话");
}
}
/*
泛型就是一种未知的,不确定的数据类型。
如果在定义类的时候类名后面写上<T>,那么就表示定义了一个泛型类型T。
这个T可以在整个类中使用。
T表示一种未知的,不确定的数据类型。 当我们使用这个类(创建对象),那么这个T表示的数据类型才会明确出来。
尖括号中的T可以使用任何字母代替
在类上面定义的泛型等到使用这个类创建对象时就指定了,如果想要延后泛型类型指定的时间,让泛型在调用
方法的时候指定,那么可以使用泛型方法。
如果在某个方法上定义了泛型,那么该方法就是泛型方法了
泛型方法的格式:
修饰符 <泛型> 返回值类型 方法名(参数类型 参数名) {
方法体;
return 返回值;
}
在方法上定义的泛型,在整个方法中都可以使用,方法上定义的泛型需要等到调用方法时才能确定该泛型的类型。
小结:
如果在类上面(中)定义泛型,该类就是一个泛型类。在类中定义泛型需要使用这个类时才会指定该泛型的类型。
如果在方法上(中)定义泛型,该方法就是一个泛型方法。在方法中定义的泛型需要调用该方法时才会指定该泛型的类型。
*/
public class Factory<T> {//表示在类的范围内【定义】了一个未知的,不确定的数据类型T。
//定义方法,方法接收什么类型的参数,就得到什么类型的结果
//第一个<E>:是在定义泛型,表示在方法中定义了一个未知的,不确定的类型E
//后面两个E:使用了泛型E作为参数类型和返回值类型。
public <E> E getSame(E e) {
return e;
}
//定义方法,可以修理任何东西
//【使用】泛型类型T当做方法的参数类型和返回值类型.
public T method(T t) {
//修理...
return t;
}
//定义方法,可以修理任何东西
/*
public Object method(Object obj) {
//修理...
//返回
return obj;
}
*/
//定义方法,用来修理手机
/*
public Phone method(Phone p) {
//假装修理...
//返回手机
return p;
}
*/
//定义方法,修理pad
/*
public Pad method(Pad p) {
//假装修理...
//返回pad
return p;
}
*/
}
public static void main(String[] args) {
//创建Factory对象
//尖括号中的Phone表示在【明确(指定)】泛型的类型
Factory<Phone> f = new Factory<>();
//调用方法,修理手机
Phone p = f.method(new Phone());
//打电话
p.call();
}
public static void main(String[] args) {
//创建Factory对象
Factory<Phone> f = new Factory<>();
//调用getSame方法,接受什么类型的参数,就产出什么结果
Phone phone = f.getSame(new Phone());
Pad pad = f.getSame(new Pad());
String str = f.getSame("aaa");
}
-
泛型接口
如果在定义接口的时候在接口名后面写上<T>,那么这个接口就是一个泛型接口了。 泛型T表示一种未知的不确定的数据类型。 泛型接口的使用: 1. 实现类实现接口的时候,可以直接明确接口中的泛型类型。 2. 实现类实现接口的时候,可以不指定接口中的泛型,等到使用实现类的时候再指定
泛型接口
/*
如果在定义接口的时候在接口名后面写上<T>,那么该接口就是一个泛型接口了。
泛型接口的使用:
1. 实现类在实现接口时可以直接明确泛型的类型。
2. 实现类在实现接口时不指定泛型,等到使用该实现类的时候再指定泛型。
*/
public interface MyInterface<T> {//表示在接口中定义了一个未知的不确定的数据类型T
//定义方法使用泛型类型当做方法参数和返回值类型
T method(T t);
}
/*
实现类在实现接口时,可以在接口名后面的尖括号中直接指定接口中的泛型
*/
public class MyClassA implements MyInterface<Phone>{
@Override
public Phone method(Phone phone) {
return null;
}
}
/*
实现类在实现接口时不指定泛型,等到使用实现类时再指定
在定义类或接口的时候,只有在当前类或接口名字后面写的尖括号才是在定义泛型。
*/
public class MyClassB<T> implements MyInterface<T>{
@Override
public T method(T t) {
return null;
}
}
public static void main(String[] args) {
//创建MyClassA对象
MyClassA ma = new MyClassA();
//调用方法
Phone p = ma.method(new Phone());
//创建MyClassB对象
MyClassB<Pad> mb = new MyClassB<>();
Pad pad = mb.method(new Pad());
}
-
泛型通配符
?表示泛型通配符,可以匹配任何类型的泛型。 注意:泛型通配符一定要放在参数位置被动匹配,不要主动使用(创建对象时使用)
/*
泛型之间是没有继承关系的。
比如ArrayList<Object>并不是ArrayList<String>的父类。
如果想要让泛型可以匹配任何类型,那么可以使用泛型通配符。
?表示泛型通配符,可以匹配任何类型的泛型
注意:
泛型通配符一定要被动匹配(在方法参数位置使用),不要主动使用(比如创建集合对象的时候泛型为?通配符)。
*/
public class Demo01GenericTest {
public static void main(String[] args) {
//创建集合用来保存字符串
ArrayList<String> strList = new ArrayList<>();
//添加
strList.add("hello");
strList.add("world");
strList.add("java");
//调用printArrayList方法,遍历
printArrayList(strList);
//创建集合保存整数
ArrayList<Integer> intList = new ArrayList<>();
//调用printArrayList遍历
printArrayList(intList);
//创建集合(不要主动使用泛型通配符)
//ArrayList<?> list = new ArrayList<>();
//list.add();
}
/*
定义方法,可以遍历保存任何元素的ArrayList集合。
*/
public static void printArrayList(ArrayList<?> list) {//?表示泛型通配符,可以匹配任何类型.
//遍历集合,输出里面的每一个元素
for (Object obj : list) {
System.out.println(obj);
}
}
}
- 泛型限定
泛型限定:可以限制泛型通配符的范围。
<? extends A>:表示泛型类型要么是A类,要么是A类的子类。上限
<? super A>:表示泛型类型要么是A类,要么是A类的父类。 下限
泛型的使用场景:主要用于代码的重构或代码的设计。
public class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public Person(String name, int age) {
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;
}
}
public class Student extends Person{
//提供带参的构造方法,用来在创建对象时直接给属性赋值
public Student(String name, int age) {
//将收到的姓名和年龄交给父类的构造方法完成赋值。
super(name, age);
}
public Student() {
}
}
public class Teacher extends Person{
public Teacher() {
}
public Teacher(String name, int age) {
super(name, age);
}
}
/*
如果要对?泛型通配符的取值范围进行限制,那么可以使用泛型限定。
<? extends A>:接收的泛型要么是A类,要么是A类的子类。上限
<? super A>:接收的泛型要么是A类,要么是A类的父类。下限
泛型可以用于代码优化,代码重构。
*/
public class Demo02GenericTest {
public static void main(String[] args) {
//创建集合保存Student对象
ArrayList<Student> stuList = new ArrayList<>();
//添加元素
stuList.add(new Student("jack", 13));
stuList.add(new Student("rose", 12));
stuList.add(new Student("tom", 15));
//调用printArrayList方法遍历
printArrayList(stuList);
//创建集合保存Person对象
ArrayList<Person> personList = new ArrayList<>();
printArrayList(personList);
//创建集合保存Object
ArrayList<Object> objList = new ArrayList<>();
//printArrayList(objList); //参数集合的泛型要么是Person要么是Person的子类,不能是Person的父类
//调用method方法,演示下限
//method(stuList);//要求参数集合的泛型要么是Person,要么是Person的父类。不能是Person的子类
method(personList);
method(objList);
}
/*
定义方法,演示泛型下限
*/
public static void method(ArrayList<? super Person> list) {//要求参数集合的泛型要么是Person,要么是Person的父类。
}
/*
定义方法,遍历保存Person或者Person子类的集合。
*/
public static void printArrayList(ArrayList<? extends Person> list) {//参数集合的泛型要么是Person要么是Person的子类
//对参数集合进行遍历
for (Person p : list) {
System.out.println(p);
}
}
}