1. 泛型
- 泛型:是一种未知的数据类型,当不知道会使用什么数据类型(或同一个方法可能接受不同数据类型),用泛型
- 泛型也可以作为变量接受数据类型
- E:未知的数据类型,即泛型,(在JAVA源码统一使用E,但其实可以是任意字母或单词)
- 在创建对象时会确定泛型E的数据类型,并将数据类型作为参数传递,赋值给泛型E
- 泛型没有继承的概念,< Integer >并不是< Object >的继承泛型
- 泛型可以作为返回值,参数,数据类型,如:
public class ArrayList< E >; public bollean add(E e); public E get (int index);
2. 不使用泛型创建集合
利:默认类型Object,可以存储任意类型
弊:不安全,可能引发异常
```java
ArrayList list =new ArrayList();
list.add("asd");//可以添加任意类型
list.add(1);
for (Object obj:list)
{
System.out.println(obj);
//如果想使用String特有的方法,需要向下转型
String s=(String)obj;
System.out.println(s.length());
//ClassCastException异常:类型转换异常
//因为list中含有Integer类型数据,不能转换到String
```
3. 使用泛型创建集合
利:避免了类型转换,把运行期代码异常,提前到了编译器期
弊:只能存储单一类型数据
4. 自定义含泛型的类
加在类名之后
```java
package linxu.day17;
public class myEclass<E> {//在类名后加<E>,其内所有和此E相同的数据类型都有E替换
private E name;
public myEclass() {
}
public myEclass(E name) {
this.name = name;
}
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
package linxu.day17;
import java.util.ArrayList;
import java.util.Iterator;
public class demomain {
public static void main(String[] args) {
demo2();
}
public static void demo2(){
myEclass<String> str= new myEclass<>();//创建自定义泛型数据
str.setName("灵虚");
System.out.println(str.getName());
}
}
```
5. 自定义含泛型参数的方法
泛型定义在修饰符和返回值之间,在调用方法时确定泛型的数据类型
格式:`修饰符 < E > 返回值 方法名(参数列表(泛型))`
必须在修饰符和返回值之间加上泛型符号,参数列表才能使用泛型作为参数
```java
package linxu.day17;
public class demomain {
public static void main(String[] args) {
method(1);
method("sdc");
}
public static <M> void method(M m){
System.out.println(m);
}//这里是一个普通的方法;也可以在其他类中定义含泛型的成员方法,静态方法等等
}
```
6. 含泛型的接口
含有泛型的接口,有俩种使用方式
- 定义接口的实现类,同时指定泛型的数据类型
//接口 package linxu.day17; public interface myEinterface<I> {//在接口名后加泛型 public abstract void method(I i); } //实现类 package linxu.day17; public class myEimpl implements myEinterface<String>{//在实现类名后跟具体的泛型数据类型 @Override public void method(String s) { System.out.println(s); } } //使用 package linxu.day17; public class demo2 { public static void main(String[] args) { myEimpl m=new myEimpl(); m.method("灵虚"); } }
- 接口使用什么泛型,实现类也跟着接口(相当于定义含义泛型的类,创建对象时才确定数据类型)
//实现类 package linxu.day17; public class myEimpl2<E> implements myEinterface<E>{ @Override public void method(E e) { System.out.println(e); } } //使用 package linxu.day17; public class demo2 { public static void main(String[] args) { myEimpl2 m2=new myEimpl2();//不使用泛型,默认Object类型 m2.method("灵虚天"); m2.method(3.3); myEimpl2<Integer> m3=new myEimpl2();//创建对象时确定数据类型 m3.method(666); } }
7. 泛型通配符
当使用泛型类或接口,传递的数据仍然不能确定数据类型,使用泛型通配符<?>
但是,一旦使用了泛型通配符,那么只能使用Objects的共性方法集合中元素自身的方法无法使用
但是泛型没有继承的概念,< Object >并不能表示接受所有数据类型
- 使用方法:
不能创建对象使用,只能作为方法参数使用 - 示例:
package linxu.day17; import java.util.ArrayList; import java.util.Iterator; public class demo3 { public static void main(String[] args) { ArrayList<Integer> arrayList1=new ArrayList<>(); ArrayList<String> arrayList2=new ArrayList<>(); arrayList1.add(1); arrayList1.add(2); arrayList2.add("王五"); arrayList2.add("张三"); myprint3(arrayList1); myprint3(arrayList2); } //泛型通配符作为参数 public static void myprint3(ArrayList<?> list){ Iterator<?> it =list.iterator(); while(it.hasNext()) System.out.println(it.next()); } }
- 泛型通配符作为参数和泛型作为参数
public static void myprint3(ArrayList<?> list)//泛型通配符作为参数 public static <M> void method(M m)//泛型作为参数 //通过上面俩个例子,我们发现,泛型通配符作为参数一般是在使用集合,且集合在使用时传递数据类型不确定时使用,可以使用集合的方法 //而泛型作为参数,只能对泛型做基本操作,即只能调用Objects类的方法
- 受限泛型——通配符的高级使用
(1)泛型的上限
格式:数据类型 <? extends 类>对象名
意义:只能接受该类型及其子类
(2)泛型的下限
格式:数据类型 <? super 类>对象名
意义:只能接受该类型及其父类
public static void myprint3(ArrayList<? extends Object> list){//限制传入的参数只能是Object及其子类
Iterator<?> it =list.iterator();
while(it.hasNext())
System.out.println(it.next());
}