一.概念
1.为什么需要泛型?
不使用泛型时:
public class Test01 {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("m1", "sssss");
String str = (String)map.get("m1");
}
}
使用泛型后:
public class Test01 {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("m1", "sssss");
String str = map.get("m1");
}
}
jdk1.5出现的泛型,通过<数据类型>来接收一种引用数据类型,作用是编译程序时,使用检查集合中添加的对象是否是该类型的,从而把运行时期的问题转移到了编译时期,提高了程序的安全性。否则很容易出现“java.lang.ClassCastException”异常。使用泛型就可以解决此类问题。
这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。
泛型擦除:编译时存在泛型,编译完成后字节码文件中是没有泛型的.
2.泛型的优缺点
在泛型出现之前,当我们想增加程序的扩展性时,常用Object,但是泛型出现之后,我们更多的时候使用泛型。
使用Object
public class Tool {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
使用泛型
public class Tool1<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
一个实体类
public class Worker {
}
使用对比
public class Test01 {
public static void main(String[] args) {
// HashMap<String, String> map = new HashMap<>();
// map.put("m1", "sssss");
// String str = map.get("m1");
// 使用object
Tool tool = new Tool();
tool.setObj(new Worker());
Worker worker = (Worker) tool.getObj();
// 使用泛型
Tool1<Worker> tool1 = new Tool1<>();
tool1.setT(new Worker());
Worker worker1 = tool1.getT();
}
}
3.什么是泛型?
所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。泛型的出现避免了强转,并且把错误转移到了编译时期。
泛型格式:通过<>来定义要操作的引用数据类型
其实Java的泛型就是创建一个用类型作为参数的类。就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1、str2的值是可变的。而泛型也是一样的,这样写class Java_Generics<K,V>,这里边的K和V就象方法中的参数str1和str2,也是可变。
泛型参数的命名风格为:推荐你用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母,这使它和其他的普通的形式参数很容易被区分开来。使用T代表类型,无论何时都没有比这更具体的类型来区分它。这经常见于泛型方法。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。如果一个泛型函数在一个泛型类里面出现,最好避免在方法的类型参数和类的类型参数中使用同样的名字来避免混淆。对内部类也是同样。
编写泛型类要注意:
1) 在定义一个泛型类的时候,在 “<>”之间定义形式类型参数,例如:“class TestGen<K,V>”,其中“K” , “V”不代表值,而是表示类型。
2) 实例化泛型对象的时候,一定要在类名后面指定类型参数的值(类型),一共要有两次书写。例如:
TestGen<String,String> t=new TestGen<String,String>();
3) 泛型中<K extends Object>,extends并不代表继承,它是类型范围限制。
4.什么时候使用泛型?
1.当类中要操作的引用数据类型不确定的时候
2.早期定义object来完成扩展,现在定义泛型来完成扩展。一般的应用开发中泛型使用较少,多用在框架或者库的设计中,为增加扩展性。
二.泛型的使用
1.泛型类
直接看代码:
public class Demo1 {
public void show(String s) {
System.out.println("show:" + s);
}
public void show(Integer i) {
System.out.println("show:" + i);
}
public static void main(String[] args) {
Demo1 demo1 = new Demo1();
demo1.show(3);
demo1.show("111111");
}
}
public class Demo<T> {
public void show(T t) {
System.out.println("show:" + t);
}
public static void main(String[] args) {
Demo<String> demo = new Demo<>();
demo.show("hello");
Demo<Integer> demo1 = new Demo<>();
demo1.show(2);
}
}
以上对使用泛型和不使用泛型做了对比,我们之前需要写两个方法,现在一个就搞定了,泛型的优势不言自明。
说明:
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型之后,所有要操作的类型就固定了,即方法操作的类型就固定了。一个方法的参数的类型只有在该类上的泛型确定了才能确定。
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
2.泛型方法
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
泛型定义在方法上时,放在返回类型的前面,修饰符的后面。
public <E> void fun(E e) {
System.out.println("show:" + e);
}
Demo<Integer> demo1 = new Demo<>();
demo1.fun("fdfdfdf");
demo1.fun(122);
全部代码:
public class Demo<T> {
public void show(T t) {
System.out.println("show:" + t);
}
// 这个E与类的泛型类型是无关的
public <E> void fun(E e) {
System.out.println("show:" + e);
}
public static void main(String[] args) {
Demo<String> demo = new Demo<>();
demo.show("hello");
Demo<Integer> demo1 = new Demo<>();
demo1.show(2);
demo1.fun("fdfdfdf");
demo1.fun(122);
}
}
说明:
静态方法泛型有一个需要注意:
静态方法不可以访问类上定义的泛型,只能将泛型定义到方法上。原因是因为:类加载的时候,类还没有泛型类型呢,之后创建了类的对象,才知道类的泛型。
public static <W> void method (W w) {
System.out.println("show:" + w);
}
3.泛型接口
直接看代码
public interface Inter<T> {
void show (T t);
}
public class InterImpl implements Inter<String> {
@Override
public void show(String s) {
}
}
假设类在实现接口的时候,并不知道泛型的类型,怎么办呢?
public interface Inter<T> {
void show (T t);
}
public class InterImpl1<T> implements Inter<T> {
@Override
public void show(T t) {
}
}
4.通配符(?)
任意类型,这样可以提高他的通用性
public class Demo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("2222");
list.add("333");
dieDai(list);
}
private static void dieDai(ArrayList list) {
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
System.out.println(o);
}
}
private static void dieDai1(ArrayList<?> list) {
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
System.out.println(o);
}
}
private static <Q> void dieDai2(ArrayList<Q> q) {
for (int i = 0; i < q.size(); i++) {
Q q1 = q.get(i);
System.out.println(q1);
}
}
}
5.泛型限定(extends ,super )
受限泛型是指在泛型的操作过程中,可以指定一个泛型对象的范围上限和范围下限
格式:
上限:
声明对象: 类名称<? extends Person>对象名称
声明类:访问权限 类名称<泛型标识 extends 类>
这个尖括号里必须是person或者person的子类.就是你传过来的集合元素类型可以是person或者person的子类
下限:
声明对象: 类名称<? super Person>对象名称
这个尖括号里必须是person或者person的父类.就是你传过来的集合元素类型可以是person或者person的父类
class Info<T>{
private T var;
public T getVar() {
return var ;
}
public void setVar(T var) {
this .var = var;
}
}
public class TypeTest {
public static void main(String[] args) {
Info< Integer>i= new Info< Integer>();
i.setVar(20);
fun(i);
}
public static void fun(Info<? extends Number> temp){
System. out .println("内容" +temp.getVar());
}
}
6.泛型数组
public class TypeTest {
public static void main(String[] args) {
//Integer i[]={1,2,3,4,5};//静态初始化数组
Integer i[]= fun1(1,2,3,4,5);
fun2(i);
}
public static <T> T[] fun1(T...arg){ //可变参数和泛型数组
return arg;
}
public static <T> void fun2(T param[]){
for (T t: param){
System. out .print(t+"," );
}
}
}
三.参考资料
https://yq.aliyun.com/articles/3311
http://www.weixueyuan.net/view/6321.html
http://blog.csdn.net/u012152619/article/details/47253811