V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Macolor21
V2EX  ›  Java

请教大佬一个泛型的问题

  •  
  •   Macolor21 · 2021-12-24 11:35:24 +08:00 · 2377 次点击
    这是一个创建于 826 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我有一个抽象类 Animal, 如下

    public abstract class Animal<T> {
    
        public List<T> getList(){
            return new ArrayList<>();
        }
    
    }
    

    我想要扩展这个抽象类的功能,于是我继承了该抽象类实现了 Tiger 。在这里我会限制 Tiger 的泛型必须是 String 的子类。

    我的核心需求是扩展 getList 方法,让其返回值不再是空 List, 而是包含一个元素 "I'm Tiger" 的字符串集合。

    以下面的写法,IDEA 会编译出错,请问有什么其他方式实现这个需求吗?

    public abstract class Tiger<T extends String> extends Animal<T> {
    
        @Override
        public List<T> getList() {
            ArrayList<String> strings = new ArrayList<>();
            strings.add("I'm Tiger");
            return strings;
        }
    }
    
    第 1 条附言  ·  2021-12-24 18:05:17 +08:00

    最后通过强转能够解决

    public abstract class Tiger<T extends String> extends Animal<T> {
    
        @Override
        public List<T> getList() {
            ArrayList<String> strings = new ArrayList<>();
            strings.add("I'm Tiger");
            return (List<T>) strings;
        }
    }
    
    8 条回复    2021-12-24 22:14:35 +08:00
    gadfly3173
        1
    gadfly3173  
       2021-12-24 11:48:44 +08:00   ❤️ 1
    首先 string 没法被继承。。。这是 final class 。
    保留 extends String 的话可以改成
    ArrayList<T> strings = new ArrayList<>();
    strings.add((T) "I'm Tiger");
    Leviathann
        2
    Leviathann  
       2021-12-24 11:52:48 +08:00
    翻译成 ts ,报错更友好
    ‘string' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'String'.
    只能返回 T 的子类型而不是 string
    因为 string 不能直接赋值给子类型
    wolfie
        3
    wolfie  
       2021-12-24 11:53:06 +08:00
    编译期的东西不指定泛型就行。

    或者

    public abstract class Tiger extends Animal<String> {
    @Override
    public List<String> getList() {}
    }
    debuggerx
        4
    debuggerx  
       2021-12-24 11:54:21 +08:00
    Tiger.java:

    public abstract class Tiger extends Animal<String> {
    --@Override
    ----public List<String> getList() {
    ------ArrayList<String> strings = new ArrayList<>();
    ------strings.add("I'm Tiger");
    ------return strings;
    ----}
    }
    aguesuka
        5
    aguesuka  
       2021-12-24 11:55:32 +08:00
    String 是 final 的.
    如果 String 不是 final 的, 假如它有一个子类 A. 那么我可以定义 Tiger<A> tiger, 但是 tiger.getList().get(0) 会报 ClassCastException, 因为期待的类型是 A, 实际上是 String. 就像一楼那样
    实际上应该是

    ArrayList<T> strings = new ArrayList<>();
    strings.add(aObjectWhichClassIsT);
    return strings;
    shily
        6
    shily  
       2021-12-24 12:05:11 +08:00
    所以楼主不看错误提示吗?问问题也不发错误提示吗?

    楼上也就 2 楼靠谱。


    根本原因是父类的 List 无法直接赋值给子类 List; 比如 List<Object> 是无法赋值 给 List<String> 的,因为你无法判断 List 里是否有不合法的数据。

    例如:
    ArrayList<Object> objs = new ArrayList<>();
    objs.add("I am string");
    Integer iAmInteger = 10;
    objs.add(iAmInteger);


    // 一下的场景中 String 就是 T extends Object
    List<String> strings = objs; // 此处编译错误,提示需要 List<String> 但是提供了 List<Object>
    unco020511
        7
    unco020511  
       2021-12-24 17:38:38 +08:00
    你需要一篮子苹果,我说我给你一篮子水果(水果里啥都有,除了苹果还有别的),你会同意吗?
    CodeGou
        8
    CodeGou  
       2021-12-24 22:14:35 +08:00 via Android
    kotlin 里有 in out 的概念。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2680 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:14 · PVG 23:14 · LAX 08:14 · JFK 11:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.