一、优点
编译时检查添加元素类型,安全
减少类型转换,效率
没有警告
// 泛型
public class Generic1 {
public static void main(String[] args) {
// <Dog> 表示arrayList只能放Dog类型
ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("aa",14));
arrayList.add(new Dog("dd",2));
// 遍历时可以直接用Dog 不用Object转Dog
for (Dog dog:arrayList) {
System.out.println(dog.getName()+" "+dog.getAge());
}
}
}
class Dog {
private String name;
private int age;
public Dog(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 Generic2 {
public static void main(String[] args) {
Person<String> person = new Person<String>("xcv"); // 相当于下面所有E都是String
person.f();
}
}
class Person<E> {
E s; // 属性的数据类型在创建Person的时候指定,在编译期间就确定E是什么类型
public Person(E s) { // E作为参数类型
this.s = s;
}
public E f(){
System.out.println(s.getClass()); // class java.lang.String
return s; // E作为返回类型
}
}
三、语法
3. 1 泛型的声明
interface 接口
T,K,V 不代表值,是表示类型
可以使用任意字母,常用T
3.2 泛型的实例化
要在类名后面指定类型参数的值(类型)
List
Iterator
public class Generic3 {
// 用泛型的方式给HashSet放入3个对象
public static void main(String[] args) {
HashSet<Student> students = new HashSet<Student>();
students.add(new Student("A",14));
students.add(new Student("B",15));
students.add(new Student("C",16));
// 遍历
for (Student s:students) {
System.out.println(s);
}
// 用泛型给HashMap添加3个对象
HashMap<String,Student> hashMap = new HashMap<String,Student>();
hashMap.put("A",new Student("AA", 28));
hashMap.put("V",new Student("VV", 29));
hashMap.put("C",new Student("CC", 27));
// 迭代器 EntrySet
Set<Map.Entry<String,Student>> set = hashMap.entrySet();
Iterator<Map.Entry<String,Student>> iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Student> next = iterator.next();
System.out.println(next.getKey()+" "+next.getValue());
}
}
}
class Student {
private String name;
private int age;
public Student(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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.3 注意事项
- interface List
{},public class HashSet {}..
T,E只能是引用类型
- 在给泛型指定具体类型后,可以传入该类型或其子类类型
- 泛型使用形式
List
List
不给泛型指定类型,默认是Object ```java public class Generic { public static void main(String[] args) {
// 1. 给泛型指向数据类型是引用类型,不能是基本数据类型
List<Integer> integers = new ArrayList<Integer>();
// List<int> ints = new ArrayList<int>(); 不能是int这类基本数据类型
// 2. 泛型指定类型可以是该类型,也可以是该类型的子类型
Pig<A> aPig = new Pig<A>(new A()); // E指定了A类型
Pig<A> bPig = new Pig<A>(new B());
// 3. 使用形式
ArrayList<Integer> integers1 = new ArrayList<Integer>();
List<Integer> integers2 = new ArrayList<Integer>();
// 简写 编译器推断类型
ArrayList<Integer> list = new ArrayList<>();
List<Integer> list1 = new ArrayList<>();
List list2 = new ArrayList(); // 4. 这样写泛型默认是Object
}
}
class A{}
class B extends A{}
class Pig
public Pig(E e) {
this.e = e;
}
}
<a name="hEPMZ"></a>
## 四、自定义
<a name="zYvMt"></a>
### 4.1 自定义泛型类
class 类名<T,R,...>{<br />成员<br />}
1. 普通成员可以使用泛型(属性、方法)
1. 使用泛型的数组不能初始化
1. 静态方法中不能使用类的泛型
1. 泛型类的类型,实在创建对象时确定的
1. 在创建类型时没有指定类型默认为Object
```java
public class CustomGeneric_ {
public static void main(String[] args) {
}
}
// Tiger后面有泛型,Tiger称为自定义泛型类
// 泛型标识符可以有福哦个
// 普通成员可以使用泛型(属性和方法)
// 使用泛型数组不能初始化
// 静态属性和方法不能使用泛型,因为在类加载,没创建对象时就使用,不能确定类型
class Tiger<T,R,M>{
String name;
T t;
M m;
R r;
// T[] ts = new T[10]; 不能确定T的类型,不知道需要多大的空间
T[] ts;
public Tiger(String name, T t, M m, R r) {
this.name = name;
this.t = t;
this.m = m;
this.r = r;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public M getM() {
return m;
}
public void setM(M m) {
this.m = m;
}
public R getR() {
return r;
}
public void setR(R r) {
this.r = r;
}
}
4.2 自定义泛型接口
interface 接口名
- 接口中,静态成员不能使用泛型
- 泛型接口的类型在继承接口或者实现接口时确定
没有指定类型,默认为Object ```java public class CustomInterfaceGeneric { public static void main(String[] args) {
} } interface IUsb{ R get(U u); void hi(R r); void run(R r1,R r2,U u1,U u2); default R method(U u){
return null;
} } // 继承接口时,指定泛型接口类型 interface IA extends IUsb
{
} // 实现IA接口时,IA继承IUsb接口,指定了U为String ,R为Double,String替换了U,Double替换了R class AA implements IA { @Override public Double get(String s) { return null; }
@Override
public void hi(Double aDouble) {
}
@Override
public void run(Double r1, Double r2, String u1, String u2) {
}
@Override
public Double method(String s) {
return IA.super.method(s);
}
}
// 实现接口时,指定泛型的接口类型
class BB implements IUsb
@Override
public void hi(Float aFloat) {
}
@Override
public void run(Float r1, Float r2, Integer u1, Integer u2) {
}
@Override
public Float method(Integer integer) {
return IUsb.super.method(integer);
}
}
<a name="WJTWk"></a>
### 4.3 自定义泛型方法
修饰符 <T,R...> 返回类型 方法名(参数列表){}
1. 泛型方法,可以定义在普通类中,也可以定义在泛型类中
1. 当泛型方法被调用时,类型会确定
```java
public class CustomMethodGeneric {
public static void main(String[] args) {
Car car = new Car();
car.fly("a",111); // 调用方法时,传入参数 编译器就会确定类型
}
}
// 泛型方法可以定义在普通类中,也可以定义在泛型类中
class Car{ // 普通类
// <T,R>是泛型,提供给fly使用
public <T,R> void fly(T t,R r){ // 泛型方法
}
}
class Fish<T,R>{ // 泛型类
public void run(){
}
public <U,M> void eat(){
}
//hi()方法不是泛型方法,只是使用了泛型
public void hi(T t){
}
// 泛型方法可以使用类声明的泛型,也可以使用自己声明的泛型
public <K> void hello(R r,K k){ // K是泛型方法自己声明的泛型
}
}
五、继承和通配符
- 泛型不具备继承性
- <?> 支持任意泛型类型
- <? extends A> 支持A类以及A类的子类,确定上限
<? super A> 支持A类以及A类的父类,不限于直接父类,确定下限 ```java public class GenericExtends { public static void main(String[] args) {
Object o = new String("xx");
// List<Object> list = new ArrayList<String>();错的,泛型不具备继承性
List<Object> list = new ArrayList<>();
List<String> list1 = new ArrayList<>();
List<AAA> list2 = new ArrayList<>();
List<BBB> list3 = new ArrayList<>();
List<CCC> list4 = new ArrayList<>();
print1(list);
print1(list1);
print1(list2);
print1(list3);
print1(list4);
// List<? extends AAA> c 可以接受AAA或AAA的子类
// print2(list); x
// print2(list1); x
print2(list2);
print2(list3);
print2(list4);
// List<? extends AAA> c 可以接受AAA或AAA的子类
print3(list);
// print3(list1); x
print3(list2);
// print3(list3); x
// print3(list4); x
}
@Test public static void print1(List<?> c){
for(Object object : c){ // 通配符 取出时就是Object
System.out.println(object);
}
}
// ? extends AAA 表示上限 可以接受AAA或AAA的子类 public static void print2(List<? extends AAA> c){
for(Object object : c) {
System.out.println(object);
}
}
// ? super AAA 表示下限 可以接受AAA或AAA的父类,不限于直接父类 public static void print3(List<? super AAA> c){
for(Object object : c) {
System.out.println(object);
}
} } class AAA{
} class BBB extends AAA{
} class CCC extends BBB{
} ```