用简单通俗的话来记录自己对架构的理解
1.为什么
啥都不说,大家先来看下ugly代码:
public int sum(int a, int b) {
return a + b;
}
public float sum(float a, float b) {
return a + b;
}
大家看到上面的代码,可能会微微一笑,我是不会写这样的代码,因为,我会使用extend/implements的父类来实现,是的,这是一种实现方式,但是,同样的,会出现的获取的结果还要进行类型转换,这也不是最优方案,所以,在JDK1.5之后,就推出了泛型。
那么,为啥要引入泛型,就是为了解决刚才看到的问题
(1)减少方法的复写,减少方法的改动
(2)减少类型强转
(3) 大大提高类型的可拓展性
2.是什么
(1)泛型是抽象参数化类型
首先我们看下现有的数据类型
public class Student<T> implements Cloneable{
private String name ;//引用数据类型
private int age;//基本数据类型
private List<Lesson> lessonList;//引用数据类型
private T t;//泛型的参数类型,可以是任意类型
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
由上可见:泛型实际上就是抽象的参数类型。
如何理解这里的抽象和参数类型呢?
抽象就是这个类型是后来指定,在调用时进行指定,而不是预先指定。
参数类型就是它也是一种数据类型(这是我个人的理解),只是作为调用时参数传递进来确定而已
(2)泛型的分类与应用
根据在一个类中的应用,泛型分为:
泛型类
泛型接口
泛型方法
如下:
泛型类:
public class Student<T> implements Cloneable{
private String name ;//引用数据类型
private int age;//基本数据类型
private List<Lesson> lessonList;//引用数据类型
private T t;//泛型的参数类型,可以是任意类型
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
泛型接口:
泛型方法:
public <T> T getFristResult(T t){
return t;
}
public <K,V> V getSecondResult(K k){
V t = null;
return t;
}
(3)通配符?和上下限的限定
1.权限限定在声明中应用
在泛型类的声明中,只能使用?extends T,但是不能使用? super T。如下代码:
同理,泛型接口亦是如此。
在泛型方法中,不支持?extend T。只能是 T extends Number这样
private class Generic2<T extends A>{
}
//报异常
private class Generic3<? super A>{
}
class A{};
class B extends A{}
class C extends B{}
class D extends C{}
//异常,编译无法通过
public <? extends A> T getKey(Class<T> tClazz){
try {
return tClazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}finally {
return null;
}
}
2.权限的限定可以在具体的实现中应用,如下代码:
//通用的子类实现方式
List<A> list = new ArrayList<>();
list.add(new C());
list.add(new A());
//泛型的是实现,会导致添加异常
List<? extends A> listAA = new ArrayList<>();
listAA.add(new B());//不支持任何类型的添加
A a = list.get(0);
//添加和获取都支持
List<? super C> listCsuper = new ArrayList<>();
listCsuper.add(new D());
listCsuper.add(new C());
listCsuper.add(new A());//不支持子类的实现
Object obj = listCsuper.get(0);
3.通配符的& 操作:
(1)这个操作只能单实现多继承,和类的继承原理保持一致
(2)使用这个字符后,子类必须是要同时实现继承这些类及接口
数字狗来验证:
private class Generic1<T extends Number & Dog>{
private T t;
public void deal(){
t.intValue();
t.shout();
}
}
private interface Dog{
void shout();
}
/**
* 数字狗的校验 &
*/
private class NumberDog extends Number implements Dog{
@Override
public int intValue() {
return 0;
}
@Override
public long longValue() {
return 0;
}
@Override
public float floatValue() {
return 0;
}
@Override
public double doubleValue() {
return 0;
}
@Override
public void shout() {
Log.d("haha","狂吠");
}
}
3.怎么实现
(1)泛型我更倾向于是个语法糖,在我们除了有基本数据和引用数据外,引入了一个任意类型的方式,但是,它的存在是在编译器,运行期是会泛型擦除。
可以通过三种方式进行验证:
(a)不同泛型的Class字节码对象名是否是一致?
List<Integer> integerList = new ArrayList<>();
List<String> stringList = new ArrayList<>();
String integerListName = integerList.getClass().getName();
String stringListName = stringList.getClass().getName();
System.out.println("integerListName.equals stringListName:"+(integerListName.equals(stringListName)));
(b)jad 工具进行反编译查看:
https://download.csdn.net/download/fullstackdeveloper/11665390:
反编译处理的字节码
public class MyClass
{
public MyClass()
{
}
public static void main(String args[])
{
java.util.List integerList = new ArrayList();
java.util.List stringList = new ArrayList();
String integerListName = integerList.getClass().getName();
String stringListName = stringList.getClass().getName();
System.out.println((new StringBuilder()).append("integerListName.equals stringListName:").append(integerListName.equals(stringListName)).toString());
}
}
©javac的编译后,再使用javap 反编译查看
这个是同理,我就不反编译了。
4.巨人肩膀
(1)泛型
https://blog.csdn.net/jeffleo/article/details/52250948
(2)为何要引入泛型擦除
https://blog.csdn.net/qq_30878303/article/details/79639904