java 泛型(Generic)

java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

泛型的基本概念看上面文章就行,说几点看开源库中看到的泛型用法:

  boolean hasLoadPath(Class<?> dataClass) {
    return getLoadPath(dataClass) != null;
  }

  <Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
    return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
  }

  private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    return runLoadPath(data, dataSource, path);
  }

hasLoadPath是一个普通方法,需要一个Class类型的对象,泛型是?,注意啦,?是一个类型实参,和Number、Integer等类是一样的,表示能接受任何Class对象,比如Number.class、ByteBuffer.class。

getLoadPath是一个泛型方法,自己定义的泛型是<Data>,Transcode是泛型类中定义的,看到没?可以一块用,不影响。Class<Data> dataClass表示在调用的时候传一个Class对象,Data就确定了。比如上面的代码,Data是?

我们看看hasLoadPath的调用:hasLoadPath(ByteBuffer.class),进入hasLoaPath方法中,dataClass还是Class<?>,除非(Class<ByteBuffer>)dataClass强转一下,就好像父类转子类一样。

我们在定义方法的时候,可以定义参数,比如methd(int a, int b),a和b叫做形参,调用是传入的叫实参,a和b是变量,变量天生是参数化的。为了便于理解泛型,我们也应该有个叫法,要不然不好理解和记忆,比如上面的decodeFromFetcher泛型方法,Data我们叫泛型形参,调用的时候,实际传入的叫泛形实参,Data本身是表达类型的,所以我们才说泛型就是把类型参数化。

我们再分析一下,下面的泛型方法:

  public <Data, TResource> Registry append(
      @NonNull String bucket,
      @NonNull Class<Data> dataClass,
      @NonNull Class<TResource> resourceClass,
      @NonNull ResourceDecoder<Data, TResource> decoder) {
    decoderRegistry.append(bucket, decoder, dataClass, resourceClass);
    return this;
  }

这个一看就是一个泛型方法,定义了Data和TResource两个泛型参数,在调用的时候才知道这两个泛型参数的具体类型,我们看看调用

        .append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)

通过调用,我们知道Data是ByteBuffer,TResource是Bitmap,这个没有问题,看看ResourceDecode<ByteBuffer, Bitmap>,decoder传入的是byteBufferBitmapDecoder

public class ByteBufferBitmapDecoder implements ResourceDecoder<ByteBuffer, Bitmap> {
}

说明:泛型类可以继承其它泛型类,而且是满足多态的。

不论是泛型类还是泛型方法,泛型是需要先定义的,比如:泛型类是在类名后面定义的,泛型方法是在返回值前面定义的


  public <Model, Data> Registry append(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass,
      @NonNull ModelLoaderFactory<Model, Data> factory) {
    modelLoaderRegistry.append(modelClass, dataClass, factory);
    return this;
  }
class EngineJob<R> implements DecodeJob.Callback<R>,
    Poolable {

      ...
      private DecodeJob<R> decodeJob;
      ...
}

只有在定义的时候才可以指定上下界,或者用通配符?的时候也可以指定上下界。

Java的泛型实现是在编译器这个层次来实现的,在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉,这个过程叫类型擦除。正是因为类型擦除的原因,编译器会禁止泛型类型参数的隐含转换,比如List<String>要传给List<Object>就是泛型类型参数隐含转换,这样会导致运行期出错。

在看Glide源码的时候总是能看到如下操作:

SingleRequest<?> request = new SingleRequest<Object>;

(SingleRequest<R>)request;

我们用类型擦除考虑一下就明白了。

Java 深度历险(五)——Java 泛型

Java泛型—类型转换

泛型还有更深的知识,尤其是Type,没看明白

Java泛型详解

Java中的Type关于Gson的TypeToken

发布了189 篇原创文章 · 获赞 25 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/lizhongyisailang/article/details/104248511