来源:http://www.bjsxt.com/
1、S02E116_01116_自定义泛型泛型类泛型接口_泛型方法
(1)发生多态时,强制类型转换和手动类型检查(避免转换错误java.lang.ClassCastException):
Object obj = 80;
int score = (int)obj;//jdk1.7以后Object–>>Integer–>>自动拆箱
//int score = (Integer)obj;//jdk1.6之前
Student stu = new Student(80,90);//形参都是Object类型,存入整数时,int–>>Integer–>>Object
(2)泛型:
——【1】泛型就是参数化类型,使用广泛的类型;
——【2】起因:数据类型不明确
————(a)装入数据的类型都被当作Object对待,从而“丢失”自己的实际类型;
————(b)获取数据时往往需要转型,效率低,容易产生错误;
——【3】作用:
————(a)安全:在编译时检查类型安全;
————(b)省心:所有的强制转换都是自动和隐式的,提高代码的重用率;
(3)泛型类:定义类时使用泛型
——【1】格式:<>
class 类名<字母列表>{
修饰符 字母 属性;
修饰符 构造器(字母){}
修饰符 返回类型 方法(字母){}
}
泛型常见字母:T(Type表示类型),K V(分别代表键值中的Key Value),E(代表Element),?表示不确定的类型。
泛型类声明时的字母不能使用在静态属性、静态方法上(static不能访问泛型类的类型参数)
——【2】使用:指定具体类型
————(a)编译时会进行类型检查
————(b)获取数据时不需要强制类型转换
泛型类使用时不能指定基本类型,只能是引用类型
(4)泛型接口:字母不能使用在静态属性上,更不能用在全局常量上,只能使用在方法中
(5)泛型方法:
——【1】修饰符 <字母> 返回类型 方法名(字母){}
<字母>在返回类型前面,修饰符可以有static
——【2】注意:泛型还可以定义在方法中,是否拥有泛型方法,与其所在的类是否泛型没有关系
——【3】只能访问相应的对象的信息(get、print…),不能修改信息(还不确定类型,不能set…)
2、S02E117_01自定义泛型子类属性类型重写方法类型泛型擦除
(1)子(实现)类
——【1】非泛型子类声明时指定泛型父类 | 接口的具体类型
——【2】泛型父类 | 接口的子类为泛型类
——【3】子类为泛型类,泛型父类 | 接口不指定类型(泛型的擦除),继承的属性类型用Object替换
——【4】子类与父类 | 接口同时泛型擦除
——【5】错误:子类擦除,父类 | 接口使用泛型
擦除统一使用Object对待
package com.test.generic;
/**
* 父类为泛型类
* <br>1.属性
* <br>2.方法
* <p>要么同时擦除,要么子类大于等于父类的类型,
* 不能子类擦除,父类泛型
* <br>1.属性类型
* <br>父类中,随父类而定
* <br>子类中,随子类而定
* <br>2.方法重写
* <br>随父类而定
*/
public abstract class Father<T,T1> {
T name;
public abstract void test(T t);
}
/**
* 非泛型子类声明时指定泛型父类的具体类型
* <br>属性类型为具体类型
* <br>方法同理
*/
class Child1 extends Father<String,Integer>{
int t2;
@Override
public void test(String t) {
name = "指定的具体类型String";
}
}
/**
* 泛型父类的子类为泛型类
* <br>类型数不少于泛型父类的,类型顺序可以不同
* <br>类型在使用时确定
*/
class Child2<T1,T,T2> extends Father<T,T1>{
int t2;
@Override
public void test(T t) {
}
}
/**
* 子类为泛型类,泛型父类不指定类型(泛型的擦除),继承的属性类型用Object替换
*/
class Child3<T1,T2> extends Father{
T1 t2;
@Override
public void test(Object t) {//T用Object替换
this.name = "name类型为Object";
}
}
/**
* 子类与父类同时泛型擦除
*/
class Child4 extends Father{
int t2;
@Override
public void test(Object t) {//T用Object替换
this.name = "name类型为Object";
}
}
/**
* 错误:子类擦除,父类使用泛型
*/
/*
class Child5 extends Father<T, T1>{
int t2;
@Override
public void test(T t) {
}
}
*/
(2)泛形擦除
——【1】擦除:
————(a)在使用时没有指定具体的类型
————(b)子类继承时没有指定类型
——【2】处理:
————(a)擦除后不类型检查
————(b)一旦擦除之后按Object接收
————(c)使用时没有指定具体的类型,存在编译警告,加上可以去除,但是会类型检查(声明时的泛型跟使用时的泛型不同会报错)
package com.test.generic;
public class Student<T>{
private T javaScore;
public void setJavaScore(T t){
this.javaScore = t;
}
public static void main(String[] args){
Student<Object> stu = new Student<Object>();//消除警告使用<Object>,但是...
stu.setJavaScore("ab");//以Object对待
//test(stu);//类型检查,报错。要的是Integer,传的是Object
test1(stu);//不报错,声明时类型不确定
Student stu1 = new Student();//使用时没有指定具体的类型,警告
test(stu1);//不报错,擦除后不类型检查,警告
test1(stu1);//不报错,声明时类型不确定
stu1.setJavaScore("参数为Object类型");//警告
System.out.println(stu1.javaScore);
}
public static void test(Student<Integer> a){
a.setJavaScore(123);
System.out.println(a.javaScore);
}
public static void test1(Student<?> a){//?类型不确定
}
}
3、S02E118_01自定义泛型无多态通配符_无泛型数组_jdk7泛型使用
(1)泛型没有多态
——【1】回顾:类与接口存在多态
package com.test.generic;
/**
* 多态的两种形式
*/
public class Fruit {
public static void main(String[] args) {
Fruit f = new Apple();
test(new Apple());
}
//形参使用多态
public static void test(Fruit f){
}
//返回类型使用多态
public static Fruit test2(){
return new Apple();
}
}
class Apple extends Fruit{
}
——【2】泛型没有多态
————(a)直接使用:A a = new A();错误
————(b)方法形参与返回类型也不存在泛型多态
——【3】不能使用instanceof判断是否为泛型实例(a instanceof A)
(2)通配符:? extends super
——【1】可以用在声明类型及声明方法参数上,不能用在声明类上
——【2】?可以接受泛型的任意类型,只能接收和输出,不能修改(方法声明时参数无法正确知道具体的类型,因此不能修改)
——【3】? extends 泛型上限 <=
——【4】? super 泛型下限 >=
package com.test.generic;
/**
* 通配符
* ?:类型不定,使用时确定类型
* <br>使用:声明类型|声明方法上,不能声明类|使用时
* <br>? extends:<= 上限 指定类型:子类|自身
* <br>? super: >= 下限 指定类型:父类|自身
*/
public class Consumer<T> {
T number;
public static void main(String[] args) {
Consumer<?> con = new Consumer<String>();//?使用在声明类型,使用时确定类型String
test(new Consumer<Integer>());
test2(new Consumer<Apple>());//指定类型为子类(Apple)或自身(Fruit)
//test3(new Consumer<Apple>());//泛型没有多态
//test4(new Consumer<Apple>());//指定类型为父类或自身(Fruit)
test4(new Consumer<Object>());
test4(new Consumer<Fruit>());
//test4(con);//使用时要确定类型,Consumer<?> con类型不定
con = new Consumer<Fruit>();
//test4(con);//编译时看左边,Consumer<?> con类型不定
}
public static void test(Consumer<?> con){}
public static void test2(Consumer<? extends Fruit> con){}//<=
public static void test3(Consumer<Fruit> con){}
public static void test4(Consumer<? super Fruit> con){}//>=
}
(3)泛型嵌套
——【1】声明:嵌套使用泛型
A
package com.test.generic;
public class Boss<T> {
T con;
public static void main(String[] args) {
//泛型的嵌套
Boss<Consumer<String>> boss = new Boss<Consumer<String>>();
//从外到内拆分
boss.con = new Consumer<String>();
Consumer<String> con = boss.con;
String num = con.number;
System.out.println(num);
}
}
(4)泛型与数组
——【1】没有泛型数组,不能创建泛型数组
——【2】可以只有声明,可以使用?
A[] a1 = null;//没有意义
A
package com.test.generic;
/**
* 没有泛型数组
* 声明可以使用,但是创建失败。
*/
public class Array {
public static void main(String[] args) {
Student<?>[] arr = new Student[10];//声明可以,但是没有意义
MyArrayList<String> strList = new MyArrayList<String>();
strList.add(0, "a");
System.out.println(strList.getElem(0));
}
}
/**
* 变相使用泛型
*/
class MyArrayList<E>{
//E[] cap = new E[10];//没有泛型数组,类型不定,开辟不了空间
Object[] cap = new Object[10];
public void add(int idx,E e){
cap[idx] = e;
}
@SuppressWarnings("unchecked")
public E[] getAll(){
return (E[]) cap;
}
@SuppressWarnings("unchecked")
public E getElem(int idx){
return (E)cap[idx];
}
}
(5)jdk7泛型的改进
JDK7改进:声明时指定泛型即可,创建对象不用再次编写类型
如:A a = new A<>();