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

2021-12-30 22:45:21 +08:00
 RiceMarch

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

//泛型接口
public interface SaveService<T> {
    void save(List<T> saveList);
}

//具体实现类
public class UserSaveServiceImpl 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
}

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

3449 次点击
所在节点    Java
25 条回复
donggexiongdi
2021-12-30 23:18:15 +08:00
看下 hashmap
RiceMarch
2021-12-30 23:48:58 +08:00
@donggexiongdi Map 也是泛型接口来着...public class HashMap<K,V> extends AbstractMap<K,V>,我就是不想加类的泛型
Jooooooooo
2021-12-31 00:47:21 +08:00
没看懂...

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

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

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

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

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

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

ps.一般来说,这种范型方法我们通常做法是<? extends T>. 这样在你的 save 方法内,才可以使用 T 这个父类上的方法,不然没啥用。
yidinghe
2021-12-31 08:20:09 +08:00
接口改成这样,那就写一个唯一的实现类算了
kujio
2021-12-31 09:13:28 +08:00
可以试试不用泛型,用一个被继承的实体抽象类来代替泛型 T
RiceMarch
2021-12-31 09:19:43 +08:00
@zhilincom 不是 是我另外的同事要在一个 list 塞这个接口的不同实现类 导致一个 list 有多种实现类,静态扫描被拒绝 所以他要求我把接口的泛型抹掉 哎 无奈
cppc
2021-12-31 09:43:11 +08:00
@RiceMarch 这难道不是你同事的问题,List<SaveService<?>> 不行?如果不用泛型,那么是不是会有 SaveUserService,SaveXxxService ,这样 List 就能装下你得接口了?
timethinker
2021-12-31 09:50:36 +08:00
根据里氏替换原则,子类实例指向父类指针,也就是说假如有一个 SubUser extends User ,此时 List<User>是可以 add 这个 SubUser 实例的吧。如果想要返回 List<SubUser>,可以把方法签名改为 List<? extends User>。
timethinker
2021-12-31 09:56:36 +08:00
@qwe520liao 这里说反了,应该是父类指针既可以指向父类实例,也可以指向子类实例。虽然 Java 没有指针的概念,但是这里相当于引用。
wolfie
2021-12-31 10:02:23 +08:00
X Y +1
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
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
2021-12-31 11:47:48 +08:00
如果你确定该实现类型是 User 强转过来就行了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/825385

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX