不懂就问, Java 泛型,泛型方法,泛型接口 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
RiceMarch
V2EX    Java

不懂就问, Java 泛型,泛型方法,泛型接口

  •  
  •   RiceMarch 2021-12-30 22:45:21 +08:00 4240 次点击
    这是一个创建于 1404 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这是原有的泛型接口和具体的某一个实现类

    //泛型接口 public interface SaveService<T> { void save(List<T> saveList); } //具体实现类 public class UserSaveSrviceImpl implements SaveService<User>{ @Override public void save(List<User> saveList) { //... } } 

    处于一些原因,必须把泛型接口改成非泛型接口...(很奇葩的问题,但是必须改掉接口的泛型)

    public interface SaveService { <T> void save(List<T> saveList); } 

    于是想把泛型方法续上...强行续...

    public class UserSaveServiceImpl implements SaveService{ @Override public <T> void save(List<T> saveList) { } //期望还能续上指定的类型 User } 

    结果也很明显,具体实现类上的类型算是完蛋啦,请问如何能满足这样的奇葩需要么(能满足么...

    25 条回复    2022-01-07 11:34:58 +08:00
    donggexiongdi
        1
    donggexiongdi  
       2021-12-30 23:18:15 +08:00
    看下 hashmap
    RiceMarch
        2
    RiceMarch  
    OP
       2021-12-30 23:48:58 +08:00
    @donggexiongdi Map 也是泛型接口来着...public class HashMap<K,V> extends AbstractMap<K,V>,我就是不想加类的泛型
    Jooooooooo
        3
    Jooooooooo  
       2021-12-31 00:47:21 +08:00   1
    没看懂...

    而且你可以再想想是否提了 A/B 问题
    Macolor21
        4
    Macolor21  
       2021-12-31 01:48:11 +08:00 via iPhone   1
    续上类型是什么意思?
    你写的代码里写了一个泛型方法,那这个方法就是泛型的,它的约束范围只在方法级别。

    你的问题描述不清楚,但有两种走向:
    1. 你想实现类级别泛型,所有方法的返回类型等都是 User (只能泛型类 /接口)
    2. 你想实现 save 的泛型。(你已经写出了泛型方法,但你没指定泛型类型,在实现类还是 T ,需要将 T 改成 User ,就可以了)

    所以我还是不懂你的问题,你写的第二个实现中没有指定泛型类型,你的方法还是泛型方法。

    在你的第一个实现中你指定了泛型 User 。该类继承 T 的方法都是泛型。

    如果你是想用户使用 UserImpl 时,只能用 User 类型,那你把 T 改成 User 不就可以了?

    方法调用层只能看到 List<User>的入参
    wellsc
        5
    wellsc  
       2021-12-31 02:44:31 +08:00 via iPhone
    RedrumSherlock
        6
    RedrumSherlock  
       2021-12-31 06:11:28 +08:00 via Android
    什么叫续上指定的类型?调用方法的时候不就把类型传进去了么?
    hingbong
        7
    hingbong  
       2021-12-31 07:36:15 +08:00 via Android
    你是想接口方法是带泛型的,实现类不是?不行的,你想想你的需求在
    hingbong
        8
    hingbong  
       2021-12-31 07:37:56 +08:00 via Android
    你是想接口方法是带泛型的,实现类不是?不行的,结合多态来看,你想想你的需求在使用接口调用的时候怎么确定类型,除非在实现类判断类型,传参不对就报错
    zhilincom
        9
    zhilincom  
       2021-12-31 07:47:01 +08:00
    不让用泛型是公司不让用吗?要么遵守要么跳槽。如果不是干嘛给自己找不自在?
    Ariver
        10
    Ariver  
       2021-12-31 08:11:00 +08:00   1
    之前的实现,user 是被范型接口确定的,你的类,实现了这个,那么类型也就确定了。所以,方法上的,类型,也是确定的。
    你想的实现,接口不是范型的,那么实现类上也就没有那个 T 的类型了。
    那么,范型方法上的类型,就是在方法调用的时候根据传入的类型来决定的。

    ps.一般来说,这种范型方法我们通常做法是<? extends T>. 这样在你的 save 方法内,才可以使用 T 这个父类上的方法,不然没啥用。
    yidinghe
        11
    yidinghe  
       2021-12-31 08:20:09 +08:00 via Android
    接口改成这样,那就写一个唯一的实现类算了
    kujio
        12
    kujio  
       2021-12-31 09:13:28 +08:00
    可以试试不用泛型,用一个被继承的实体抽象类来代替泛型 T
    RiceMarch
        13
    RiceMarch  
    OP
       2021-12-31 09:19:43 +08:00 via iPhone
    @zhilincom 不是 是我另外的同事要在一个 list 塞这个接口的不同实现类 导致一个 list 有多种实现类,静态扫描被拒绝 所以他要求我把接口的泛型抹掉 哎 无奈
    cppc
        14
    cppc  
       2021-12-31 09:43:11 +08:00
    @RiceMarch 这难道不是你同事的问题,List<SaveService<?>> 不行?如果不用泛型,那么是不是会有 SaveUserService,SaveXxxService ,这样 List 就能装下你得接口了?
    timethinker
        15
    timethinker  
       2021-12-31 09:50:36 +08:00
    根据里氏替换原则,子类实例指向父类指针,也就是说假如有一个 SubUser extends User ,此时 List<User>是可以 add 这个 SubUser 实例的吧。如果想要返回 List<SubUser>,可以把方法签名改为 List<? extends User>。
    timethinker
        16
    timethinker  
       2021-12-31 09:56:36 +08:00
    @qwe520liao 这里说反了,应该是父类指针既可以指向父类实例,也可以指向子类实例。虽然 Java 没有指针的概念,但是这里相当于引用。
    wolfie
        17
    wolfie  
       2021-12-31 10:02:23 +08:00
    X Y +1
    aguesuka
        18
    aguesuka  
       2021-12-31 10:13:19 +08:00
    @RiceMarch XY 问题, 你只需将
    //泛型接口
    public interface SaveService<T> {
    void save(List<T> saveList);
    }
    改成
    //泛型接口
    public interface SaveService<T> {
    void save(List<? extends T> saveList);
    }
    aguesuka
        19
    aguesuka  
       2021-12-31 10:19:50 +08:00
    甚至是新的 method
    public interface SaveService<T> {
    void save(List<? extends T> saveList);
    void <T> saveAllWithoutTyping(List<T> saveList);
    }
    goalidea
        20
    goalidea  
       2021-12-31 11:47:48 +08:00
    如果你确定该实现类型是 User 强转过来就行了
    Joker123456789
        21
    Joker123456789  
       2021-12-31 13:00:23 +08:00   1
    按照你现在的写法,你传进来什么类型,T 就是什么类型,但是无法 在创建对象的时候 约束 这个方法只能接收什么类型。

    既然如此,不如 把 T 去掉咯,只要是 List 就收。

    如果 你想 实现在创建对象的时候 约束 这个方法只能接收什么类型,那么 接口上的 <T> 是必须保留的,也就是必须用你一开始的那种方式。

    如果你现在遇到的需求,用泛型是 最佳的方案,那你可以去跟 不让你用泛型的那个人 商量一下 怎么解决。
    如果不用泛型问题也不大,那么干脆去掉泛型把,因为你现在的这个做法 体现不出泛型的意义。
    aliveyang
        22
    aliveyang  
       2021-12-31 15:51:35 +08:00
    看不懂问题
    RiceMarch
        23
    RiceMarch  
    OP
       2021-12-31 18:44:18 +08:00 via iPhone
    @aguesuka 其实本质上是同事的奇葩想法 想把 interface SaveService<T>的这个 T 去掉我今天已经拒绝了他这个要求 hhhh
    RiceMarch
        24
    RiceMarch  
    OP
       2021-12-31 18:46:50 +08:00 via iPhone
    @Joker123456789 确实是的 今天已经和她商量过了 List 的类型肯定还是要的 不然静态检查直接被拦截了 hhhhh 还是按照第一种继续做了
    okou19900722
        25
    okou19900722  
       2022-01-07 11:34:58 +08:00
    很简单,因为 java 里的泛型是擦除的。
    目前我了解的可以通过反射获取到泛型的,似乎只有子类实现父类时,传给父类的泛型可以获取,比如

    List<String> list = new ArrayList<String>();
    这样写,拿不到,因为泛型是 ArrayList 上的,但

    List<String> list = new ArrayList<String>(){};
    这样写就可以拿到泛型,这是因为这实际上是生成了一个 ArrayList 子类的匿名类的对象。

    具体的原因,我说不清楚,写过 gson 的,应该对 TypeToken 很熟悉,基本都是 new TypeToken<xxxx>(){}的写法
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3068 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 62ms UTC 00:33 PVG 08:33 LAX 16:33 JFK 19:33
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86