java Generic problems.Why does this work?

113 views Asked by At
public interface IPage<T> extends Serializable {
    /** @deprecated */
    @Deprecated
    default String[] descs() {
        return null;
    }

    /** @deprecated */
    @Deprecated
    default String[] ascs() {
        return null;
    }

    List<OrderItem> orders();

    default Map<Object, Object> condition() {
        return null;
    }

    default boolean optimizeCountSql() {
        return true;
    }

    default boolean isSearchCount() {
        return true;
    }

    default long offset() {
        return this.getCurrent() > 0L ? (this.getCurrent() - 1L) * this.getSize() : 0L;
    }

    default long getPages() {
        if (this.getSize() == 0L) {
            return 0L;
        } else {
            long pages = this.getTotal() / this.getSize();
            if (this.getTotal() % this.getSize() != 0L) {
                ++pages;
            }

            return pages;
        }
    }

    default IPage<T> setPages(long pages) {
        return this;
    }

    default void hitCount(boolean hit) {
    }

    default boolean isHitCount() {
        return false;
    }

    List<T> getRecords();

    IPage<T> setRecords(List<T> records);

    long getTotal();

    IPage<T> setTotal(long total);

    long getSize();

    IPage<T> setSize(long size);

    long getCurrent();

    IPage<T> setCurrent(long current);

    default <R> IPage<R> convert(Function<? super T, ? extends R> mapper) {
        List<R> collect = (List)this.getRecords().stream().map(mapper).collect(Collectors.toList());
        return this.setRecords(collect);
    }

    default String cacheKey() {
        StringBuilder key = new StringBuilder();
        key.append(this.offset()).append(":").append(this.getSize());
        List<OrderItem> orders = this.orders();
        if (CollectionUtils.isNotEmpty(orders)) {
            Iterator var3 = orders.iterator();

            while(var3.hasNext()) {
                OrderItem item = (OrderItem)var3.next();
                key.append(":").append(item.getColumn()).append(":").append(item.isAsc());
            }
        }

        return key.toString();
    }
}

This is the source code of a framework, when I use convert() function

default <R> IPage<R> convert(Function<? super T, ? extends R> mapper) {
        List<R> collect = (List)this.getRecords().stream().map(mapper).collect(Collectors.toList());
        return this.setRecords(collect);
    }

what makes me wonder is that The return type is new type variable R and he just call the this.setRecords(collect); but setRecords() funcation just receive List <T>!

IPage<T> setRecords(List<T> records);

To verify this, I wrote an interface myself, but the compilation failed

public interface IPage<T> {
    
    IPage<T> setRecords(List<T> list);

    default <R> IPage<R> convert() {
        List<R> collect = new ArrayList<>();
        return this.setRecords(collect);  //error
    }
    
}

Can someone help me solve my doubts?Thank you very much!

1

There are 1 answers

1
obourgain On

The source code of my-batis plus contains an additional cast to IPage to change the type of this.

The method code is:

default <R> IPage<R> convert(Function<? super T, ? extends R> mapper) {
    List<R> collect = this.getRecords().stream().map(mapper).collect(toList());
    return ((IPage<R>) this).setRecords(collect);
}