泛型:jdk5.0出现的新特性;参数化的类型。可以将某个类型当做参数传递给类、接口或方法中
联想:
A a = new A();
class A{
T t;
}
method("john");
public void method(String s){
//访问s
}
区别:
方法的参数:传递的是值,必须传参,只能用在方法中
泛型:传递的是类型,可以不用传参,默认为Object,可以用在方法、类、接口中
1、编译时检查待添加的元素类型,提高了类型的安全性
2、减少了类型转换的次数,提高了效率
没有使用泛型:
String——>Object——>String
使用泛型:
String——>String——>String
3、减少了编译警告
语法:
类型<指定的泛型> 名 = new 类型<>();
表示形式如下:
Set set = new HashSet();
Set set2 = new HashSet<>();//jdk7.0 类型推断
Set set3 = new HashSet();//为了新老版本兼容性,不推荐使用
Set set4 = new HashSet();//为了新老版本兼容性,不推荐使用
注意:
①泛型的类型只支持引用类型
②编译类型和运行类型的泛型必须一致
一、自定义泛型类
定义语法:
class MyClass{
T name;
publci void setName(T t){}
}
注意:里面可以定义使用泛型的属性、方法也可以定义不使用泛型的普通属性和普通方法
但不能定义使用泛型的静态方法和使用泛型的数组初始化!
答:创建对象时
语法:
MyClass m = new MyClass<>();
二、自定义泛型接口
定义语法:
interface MyInter{
U method(T t);
}
答:被继承或实现时,可以确定,如果不确定,则默认是Object类型。如果想延续泛型,则需要将子接口或实现类设计成泛型形式!
一、泛型的好处 【面试题】
1、减少了编译警告
2、编译时检查类型,提高类型的安全性
3、大大减少了类型转换的次数,提高了效率
二、泛型的语法和使用 ★
Set set = new HashSet();
Set set = new HashSet<>(); //jdk7
Set set = new HashSet();为了兼容
Set set = new HashSet();为了兼容
Set set = new HashSet();
注意:泛型的类型 只允许引用类型!!
三、自定义泛型
1、自定义泛型类
定义语法:
class MyClass{
T t;
public void setT(T t){}
public T[] getT(){return null}
}
备注:不允许有使用泛型的静态方法和使用泛型的数组初始化
什么时候确定泛型类的泛型?
创建对象时!如果没有指定泛型也不报错,只是默认Object类型
2、自定义泛型接口
定义语法:
interface MyInterface{
T getT();
void setT(T t);
}
什么时候确定泛型接口的泛型?
实现该接口或继承该接口!如果没有指定泛型也不报错,只是默认Object类型
3、自定义泛型方法
定义语法:
修饰符 返回类型 方法名(E e){
}
什么时候确定泛型?
方法被调用时!
四、泛型的继承性和通配符
一)泛型不具备继承性!
List
二)通配符
?:支持任意类型。 不能添加,除了null
? extends 类A:支持类A以及A的子类。 不能添加,除了null
? super 类A:支持类A以及A的父类(不限于直接父类)。 不能添加,除了null和A的对象
示例:
List> list= new ArrayList();
list.add(null);
list.add(obj);//错误!
1.泛型的声明
interface List 和 class GenTest
其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。
2.泛型的实例化:
一定要在类名后面指定类型参数的值(类型)。如:
List strList = new ArrayList();
Iterator iterator = customers.iterator();
T只能是类,不能用基本数据类型填充。但可以使用包装类填充
把一个集合中的内容限制为一个特定的数据类型,这就是generics背后的核心思想
1.对象实例化时不指定泛型的话,默认为:Object。
2. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如
3. 泛型类的构造器如下:
public GenericClass(){}。
而如下是错误的:
public GenericClass(){}
4.从泛型类派生子类,泛型类型需具体化
5.如果泛型类是一个接口或抽象类,则不可创建泛型类的对象。
6.静态方法中不能使用类的泛型
7.异常类不能是泛型的
8.加入集合中的对象类型必须与指定的泛型类型一致。
9.泛型不同的引用不能相互赋值。
>尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中。
10.泛型的指定中不能使用基本数据类型,可以使用包装类替换。
11. 不能使用new E[]。但是可以:
E[] elements = (E[])new Object[capacity];
class Person{
//使用T类型定义变量
private T info;
//使用T类型定义一般方法
public T getInfo(){
return info;
}
public void setInfo(T info){
this.info = info;
}
使用T类型定义构造器
public Person(){}
public Person(T info){
this.info = info;
}
//static的方法中不能声明泛型
//public static void show(T t){
//}
//不能在try-catch中使用泛型定义
//try{}
//catch(MyException ex){}
}
方法也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法的格式:
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
例如
public class DAO {
public E get(int id, E e){
E result = null;
return result;
}}
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G并不是G的子类型!
比如:String是Object的子类,但是List并不是List的子类。
public void testGenericAndSubClass() {
Person[] persons = null;
Man[] mans = null;
// 而 Person[] 是 Man[] 的父类.
persons = mans;
Person p = mans[0];
// 在泛型的集合上
List personList = null;
List manList = null;
// personList = manList;(报错)
}
1.使用类型通配符:?
比如:List> ,Map,?>
List>是List、List等各种泛型List的父类。
2.读取List>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。
唯一的例外是null,它是所有类型的成员。
将任意元素加入到其中不是类型安全的:
Collection> c = new ArrayList();
c.add(new Object()); // 编译时错误
因为我们不知道c的元素类型,我们不能向其中添加对象。
add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。
唯一的例外的是null,它是所有类型的成员。
另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object
public static void main(String[] args) {
List> list = null;
list = new ArrayList();
list = new ArrayList();
//list.add(3);
list.add(null);
List l1 = new ArrayList();
List l2 = new ArrayList();
l1.add(“尚硅谷");
l2.add(15);
read(l1);
read(l2); }
static void read(List> list){
for(Object o : list){
System.out.println(o);
} }
允许所有泛型的引用调用
举例:
extends Number> (无穷小 , Number]
只允许泛型为Number及Number子类的引用调用
super Number> [Number , 无穷大)
只允许泛型为Number及Number父类的引用调用
extends Comparable>
只允许泛型为实现Comparable接口的实现类的引用调用
public static void printCollection3(Collection extends Person> coll){
//Iterator只能用Iterator>或Iterator extends Person>.why?
Iterator> iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
} }
public static void printCollection4(Collection super Person> coll){
Iterator> iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
} }
用户在设计类的时候往往会使用类的关联关系,例如,一个人中可以定义一个信息的属性,但是一个人可能有各种各样的信息(如联系方式、基本信息等),所以此信息属性的类型就可以通过泛型进行声明,然后只要设计相应的信息类即可。