1、什么是泛型?
泛型(Generics)是把类型参数化,运用于类、接口、方法中,在调用时传入具体的类型。
泛型就是参数化类型
- 适用于多种数据类型执行相同的代码
- 泛型的类型在使用时指定
- 泛型归根到底就是“模板”
优点:使用泛型时,在实际使用之前类型就已经确定了,不需要强制类型转换。
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
2、泛型的使用场景
2.1 用于集合
/*** 运用于集合中*/
public class Demo01 {//不使用泛型,直接存取数据public static void test01() {List list = new ArrayList();list.add("001");list.add(100);Object o1 = list.get(1);if(o1 instanceof Integer) {//如果不判断类型,直接强转Integer,则运行时可能直接抛出异常o1 = (Integer)o1;}System.out.println(o1);}public static void test02() {List<Integer> list = new ArrayList<Integer>();//list.add("001"); 放数据时进行安全检查,"001"不是Integer类型,编译不通过list.add(100);System.out.println(list.get(0));}public static void main(String[] args) {test01();test02();}
}
2.2 自定义泛型
泛型字母
- 形式类型参数(formal type parameters)即泛型字母
- 命名泛型字母可以随意指定,尽量使用大写字母(多个参数时,在字母后加数字,例T1,T2)
- 常见字母:T(Type),K V (Key Value),E(Element)
泛型类
- 只能用在成员变量上,只能使用引用类型
泛型接口
- 只能用在抽象方法上
泛型方法
- 返回值前加<T>
自定义泛型类
/*** 自定义泛型类* @param <T>*/
class Student<T> {private T prop;public T getProp() {return prop;}public void setProp(T prop) {this.prop = prop;}@Overridepublic String toString() {return "Student [prop=" + prop + "]";}
}public class Demo02 {public static void main(String[] args) {//Student<int> s = new Student<int>(); 不能为基本类型,会编译报错Student<Integer> student = new Student<Integer>();student.setProp(18);//输出:Student [prop=18]System.out.println(student);}
}
自定义泛型接口
/*** 自定义泛型接口* 接口中泛型字母只能使用在方法中,不能使用在全局常量中* @param <T>*/
public interface Comparator<T1, T2> {//public static T1 param; 静态类型不能引用非静态的参数,会编译报错void compare(T1 t1);T2 compare();public abstract T1 compare2(T2 t2);
}
非泛型类里定义泛型方法
/*** 非泛型类里定义泛型方法*/
public class Demo03 {public static<T> void test01(T t) {System.out.println(t);}public static<T extends List> void test02(T t) {t.add("sdfs");System.out.println(t);}public static <T extends Object> void test03(T ...l) {for(T t:l) {System.out.println(t);}}public static void main(String[] args) {//泛型参数test01("01");//泛型的继承test02(new ArrayList<Integer>());//可变参数test03(new ArrayList<Integer>(), new ArrayList<String>());}}
泛型类的继承
abstract class Father<T1, T2> {T1 age;public abstract void makeFriend(T2 t);
}/*** 父类泛型完全保留*/
class Child1<T1, T2> extends Father<T1, T2> {@Overridepublic void makeFriend(T2 t) {System.out.println("My attr: "+age+" &T2="+t);System.out.println("I am "+getClass().getName()+", let`s be friend.");}
}/*** 父类泛型部分保留*/
class Child2<T1> extends Father<T1, Integer> {@Overridepublic void makeFriend(Integer t) {System.out.println("My attr: "+age+" &T2="+t);System.out.println("I am "+getClass().getName()+", let`s be friend.");}
}/*** 父类泛型不保留,子类按需实现*/
class Child3 extends Father<Integer, String> {@Overridepublic void makeFriend(String t) {System.out.println("My attr: "+age+" &T2="+t);System.out.println("I am "+getClass().getName()+", let`s be friend.");}
}/*** 没有具体类型* 泛型擦除,继承父类的子类,没有指定类型,默认为Object*/
@SuppressWarnings("rawtypes")
class Child4 extends Father {@Overridepublic void makeFriend(Object t) {System.out.println("My attr: "+age+" &T2="+t);System.out.println("I am "+getClass().getName()+", let`s be friend.");}
}public class Demo03 {public static void main(String[] args) {new Child1().makeFriend("1");new Child2().makeFriend(1);new Child3().makeFriend("1");new Child4().makeFriend("1");}
}
/*** 类型擦除*/
public class Demo03 {public static void test01(Student<Integer> student) {student.setProp(18);System.out.println(student);}public static void main(String[] args) {Student student = new Student();//输出:Student [prop=18]test01(student);Student<String> s2 = new Student<String>();//编译报错,参数不匹配//test01(s2);}
}
通配符
通配符(Wildcards)
- T、K、V、E 等泛型字母为有类型,类型参数赋予具体的值
- ?未知类型 类型参数赋予不确定值,任意类型
- 只能用在声明类型、方法参数上,不能用在定义泛型类上
/*** 泛型的通配符,类型不确定,用于变量声明或者形参上面* 不能用在类上或者对象创建上*/
public class Demo03 {public static<T> void test01(Student<T> student) {//编译报错:不能转换 Student<Integer> 为 Student<T>//student = new Student<Integer>();//student = new Student<String>();//student = new Student<BigDecimal>();System.out.println(student);}public static void test02(Student<?> student) {//?号代表类型参数不确定,下面代码可以执行student = new Student<Integer>();student = new Student<String>();student = new Student<BigDecimal>();System.out.println(student);}public static void main(String[] args) {Student student = new Student();//输出:Student [prop=null]test02(student);}
}
extends/super
上限(extends)
指定的类必须是继承某个类,或者实现了某个接口(不是implements),即<=
- ? extends List
下限(super)
即父类或本身
- ? super List
/*** extends:泛型的上限 <= 一般用于限制操作 不能使用在添加数据上,一般都是用于数据的读取* supper:泛型的上限 >= 即父类或自身。一般用于下限操作*/
public class Demo03<T extends Fruit> {public static void test01() {Demo03<Fruit> t1 = new Demo03<Fruit>();Demo03<Apple> t2 = new Demo03<Apple>();//编译报错:类型转换失败//Demo03<Fruit> t3 = new Demo03<Apple>();}public static void test02(List<? extends Fruit> list) {//编译报错//list.add(new Fruit());//list.add(new Object());}public static void test03(List<? super Apple> list) {//可以编译通过list.add(new Apple());list.add(new RedApple());//编译报错//list.add(new Fruit());}}
泛型嵌套
/*** 泛型嵌套**/
public class Demo05 {public static void main(String[] args) {Student2<String> student = new Student2<String>();student.setScore("优秀");System.out.println(student.getScore());//泛型嵌套School<Student2<String>> school = new School<Student2<String>>();school.setStu(student);String s = school.getStu().getScore(); //从外向里取System.out.println(s);// hashmap 使用了泛型的嵌套Map<String, String> map = new HashMap<String,String>();map.put("a", "张三");map.put("b", "李四");Set<Entry<String, String>> set = map.entrySet();for (Entry<String, String> entry : set) {System.out.println(entry.getKey()+":"+entry.getValue());}}
}public class School<T> {private T stu;public T getStu() {return stu;}public void setStu(T stu) {this.stu = stu;}}public class Student2<T> {T score;public T getScore() {return score;}public void setScore(T score) {this.score = score;}
}
其他(数组)
import java.util.ArrayList;
import java.util.List;/*** 泛型没有多态* 泛型没有数组* JDK1.7对泛型的简化* @author Administrator**/
public class Demo06 {public static void main(String[] args) {Fruit fruit = new Apple(); // 多态,父类的引用指向子类的对象//List<Fruit> list = new ArrayList<Apple>(); //泛型没有多态 List<? extends Fruit> list = new ArrayList<Apple>();//泛型没有数组//Fruit<String>[] fruits = new Fruit<String>[10];//ArrayList底层是一个Object[],它放数据的时候直接放,取数据的时候强制类型转化为泛型类型/*public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;}*//*E elementData(int index) {return (E) elementData[index];}*///JDK1.7泛型的简化,1.6编译通不过List<Fruit> list2 = new ArrayList<>();}
}
参考:
https://segmentfault.com/a/1190000014824002?utm_source=tag-newest
http://www.importnew.com/tag/%E6%B3%9B%E5%9E%8B