android API 26 中对 findViewById()泛型的理解

android在api 26中的findViewById方法使用了泛型,使我们在开发中免了强转类型的苦恼,今天突然冒出了一个疑问(个人在之前对泛型还没有深入理解),故在此记录一下:
findViewById()怎么知道我要的是哪一种类型,也就是说它怎么能根据不同ID刚好强转成相对应的View。

1.一般来说方法泛型原型是这个样子的:

public <T extends View> T get(T t);
public <T extends View> void get(T t);
public <T,E> void get(T t,E e);

<>里面是对参数t的约束和对类型T的声明,例如<T extends View>声明了一种类型T,且T是View的子类,然后根据传入的参数做一些处理,这里T的意义是在于对参数T t的约束和声明,任何View的子类都可以作为参数传进来进行处理。

2.看一下findViewById()函数原型:调用了函数findViewTraversal()

    @Nullable
    public final <T extends View> T findViewById(@IdRes int id) {
        if (id == NO_ID) {
            return null;
        }      
        return findViewTraversal(id);
    }
    protected <T extends View> T findViewTraversal(@IdRes int id) {
        //判断ID是否和自己相同,相同则强转返回
        if (id == mID) {
            return (T) this;
        }
        return null;
    }

疑问产生了,findViewTraversal()方法参数是一个int值,T是一个声明的未知类型,怎么做到返回给我一个正确的类型的呢?(T) this是强转了,但是强转的是个什么东西?只知道T是继承View的,如下代码,是怎么转强转ImageView的,它怎么知道我需要的是一个ImageView类型。
例如:

ImageView img = findViewById(R.id.img);

解谜:findViewById()其实并不能根据一个ID返还给你一个对的类型,什么意思呢?下面这两行代码都能编译通过并且运行:

ImageView img = findViewById(R.id.img);
Button button= findViewById(R.id.img);

这两行代码在编译后会是这个样子的:

ImageView img = (ImageView)findViewById(R.id.img);
Button button= (Button)findViewById(R.id.img);

也就是说该方法不知道你要什么,只是使用了泛型(T) this进行了强制类型转换,告诉编译器在编译的时候该方法返回的是一个泛型类型,要进行类型转换,明显,强转为Button的时候程序在运行时会崩溃。

总结:其实在原理上findViewById()方法和之前版本是一样的,在编译之后,都需要进行了强转类型,只不过,api 26中使用了泛型,强转操作不用开发人员每次都手动进行,而是放在了编译过程中。

猜你喜欢

转载自blog.csdn.net/weixin_38062353/article/details/81585291