软件构造Lab2心得
泛型
泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型的具体例子例如我们列表的具体实现:
ArrayList<String> example = new ArrayList<>();
而我们更可以在多个层面利用泛型
泛型接口
定义格式:
修饰符 interface接口名<代表泛型的变量> { }
public interface Graph<L>{
public boolean add(L vertex){}
public boolean remove(L vertex){}
public int set(L source, L target, int weight){}
}
使用泛型接口也分为两种情况:
定义类时就确定泛型类型
public class myGraph implements Graph<String>{
/* 具体实现省略 */
@Override
public boolean add(String vertex){}
@Override
public boolean remove(String vertex){}
@Override
public int set(String source, String target, int weight){}
}
直到创建对象时确定泛型类型
public class myGraph<L> implements Graph<L>{
/* 具体实现省略 */
@Override
public boolean add(L vertex){}
@Override
public boolean remove(L vertex){}
@Override
public int set(L source, L target, L weight){}
}
/* 创建对象 */
public static void main(String[] args) {
myGraph<String> mg = new myGraph<>();
}
泛型类
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种集合框架容器类,如:List、Set、Map。
定义格式:
修饰符 class类名<代表泛型的变量> { }
使用实例:
public class myGraph<L>{
public boolean add(L vertex){}
}
当泛型用于定义类时,确定泛型类型只有在创建对象的时候,如
myGraph<Integer> mg = myGraph<>();
泛型方法
定义格式:
修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
泛型方法,是在调用方法的时候指明泛型的具体类型。
泛型方法:
public class myGraph<L>{
public <T> boolean add(T vertex){}
}
确定泛型类型:
public static void main(String[] args) {
myGraph<String> mg = myGraph<>();
mg.add("username"); // 确定泛型为字符串
mg.add(521); // 确定泛型为整数
}
可见泛型方法随着我们传入参数不同,它的操作也变得不同
还有一部分是这里关于类型通配符的知识,由于时间有限,不作解释(其实我也还没学···)
总结
从上面我们能够看出,泛型的应用非常广泛,带给我们的好处也很多,可以避免强制类型转换的麻烦,可以对于一个接口或者类又或者方法而言,可以面向很多的类型,减少工作量,它也一定程度上保证了安全性,在编译阶段就能实现为我们找到这类错误,而不是运行时才报错。
[========]
在软件构造复习过程中,又了解了一些有关于泛型的知识。在这里做出分享
泛型是多态的形式之一,也可称为参数化多态,是指一个类型可代表多种类型进行编程
泛型同样有它的作用域,根据不同实现视作不同情况
-
当泛型用作泛型接口时,实现该接口的所有类及类中所有方法都可以使用该泛型代表很多数据类型
-
当泛型用于泛型类时,该类及其子类中和类中所有方法都可以使用该泛型
-
当泛型用于泛型方法时,只有方法内部可以使用
-
当泛型使用时有名字上的冲突时,按方法、类、接口优先选择泛型,例如:
public interface vehicle<T>{
public void Start();
public T time();
}
public class car<T,E> implements vehicle<T>{
//car类有自己定义的泛型E,是泛型类
private T Brand;
public<T> T Start(){···} //此泛型定义名字和接口重复,该方法为泛型方法,该方法内部泛型T由自己定义
public T time(){···} //此方法使用接口定义的泛型,不是泛型方法
public E getfee(E path){···} //该方法使用类定义的泛型,同样不是泛型方法
}
泛型的实现机制
这里听老师上课说,泛型的实现与Java虚拟机有关,其过程被称为类型擦除
虚拟机中没有泛型类型对象,其中所有对象都是普通类
泛型的相关信息只存在于编译阶段,而在运行时,都会被擦除
在定义泛型类型时,会自动提供一个原始数据类型(非泛型类型),原始类型的名字就是去掉类型参数后的泛型类型名
擦除时类型变量会被擦除掉,替换为限定类型,无限定类型就用Object
可以看作泛型是只给编译器看的,泛型使用这样一种障眼法来欺骗编译器,我是万能类型,你不能挑我的错
而运行时虚拟机不吃这一套,要求必须来一个合理的正确的类型来充当你这个位置,我先暂时用一个内部人员(你有限定的话我就找一个满足限定的人)来占上你的位置,直到你在运行时找到一个符合要求的实实在在的类型来替代你,才可以过关
泛型与LSP原则
与子类型必须要求符合LSP原则对比,泛型是不符合协变和逆变的
下面两种类型没有任何关系,不涉及父子类关系!!!
List<String> listStr = ArrayList<>();
List<Object> listObj = ArrayList<>();
再看下面的例子,程序会执行条件语句中的代码吗?
答案是肯定的,即使二者ArrayList的实现是不同的,一个存放着String,一个存放Integer
但是在运行时,作比较时二者得到的类都是ArrayList类,与内部存放无关,与泛型实现无关
再看下面的例子
同样地,二者没有任何关系,类型不匹配
认真复习,考试成功!!!