泛型方法的泛型的类型有谁确定?

济南大飞哥 2018-07-25 05:45:42
最近搞泛型搞的有点晕。

/**
* 将Map中的value对象转为jsonstring
*/
public static <T> Map<T, String> serializeMapValue(Map<T, ?> map)
{
if (map == null)
{
return null;
}

Map<T, String> jedisMap = new HashMap<T, String>();

for (Map.Entry<T, ?> entry : map.entrySet())
{
jedisMap.put(entry.getKey(), toJSONStringWithClassName(entry.getValue()));
}

return jedisMap;
}

上面是我写的一个方法,把map的value转String的。因为key一般是String,之前的一版代码key就是String,后来我想,既然key没有动,为何不再抽象一下?于是改成了上面这个样子,把key定义成了泛型T。上述方法是能正确执行,已经测试过。有了上一版,改成这版很容易,写代码的过程感觉很简单,但是细想起来感觉有点晕。

我写了个错误的调用方法,如下:

Map<String,User> map = null;

Map<Boolean,String> newmap = JSONUtil.serializeMapValue(map);

肯定会报错时预料到的,错误报的是Type mismatch: cannot convert from Map<String,String> to Map<Boolean,String>。我之前一直以为类型是由声明的返回类型决定,所以以为会报方法不接收某某类型,或者说参数必须是Map<Boolean,User>类型, 从现象看,是由入参决定了。所以我疑问上面的T是怎么确定的?还是说由第一次用到时确定的,想来想去,感觉挺复杂。

还有这种


public <T> T get(String key)
{
if (StringUtils.isBlank(key))
{
return null;
}

ShardedJedis jedis = RedisCacheFactory.getInstance().getResource(cluster);

try
{
return (T)JSONUtil.parseObject(jedis.get(key));
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
jedis.close();
}

return null;
}


他的泛型又是在哪里确定的?还是压根没有确定下来,根本是个语法糖,避免让客户端强制转型?
...全文
657 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
ninuxGithub 2018-07-31
  • 打赏
  • 举报
回复
jdk 加入泛型的本质: 为了在编译的时候检查程序的准确性, 不让代码在编译之前有一些明显的错误; 在真正编译的时候jvm会擦除泛型;
sha_4yu 2018-07-30
  • 打赏
  • 举报
回复
引用 8 楼 flyfeifei66 的回复:
又见一个诡异问题。
[quote=引用 4 楼 C_FengSu 的回复:]
[quote=引用 3 楼 C_FengSu 的回复:]
我觉得是在泛型方法return;的时候确定的,

补图(刚开始用按到Ctrl+Enter就发出来了)
[/quote]

我一个类中写了两个方法

public Long zrem(String key, Object member);

public Long zrem(String key, List<?> members);

分别表示处理一个任何类型和多个任意类型。上述写法能正常调用到。
而如果写成

public Long zrem(String key, Object member);

public Long zrem(String key, List<Object > members);

那么我即便传递一个list参数,实际只会永远调用第一个,但是编辑器并不报方法定义重复。[/quote]

我特意试了一下,并不会只调用第一个。
引用
如果 Java 编译器在同一个阶段中找到了多个适配的方法,那么它会在其中选择一个最为贴切的,而决定贴切程度的一个关键就是形式参数类型的继承关系。

以上引用于郑雨迪的深入拆解Java虚拟机
  • 打赏
  • 举报
回复
由于java所有类都继承Object,用T只是替代(可以简单的理解为T其实就是Object,可以代替任何class类),可以人工指定T的类型,比如在方法定义上加上T extends Map,那么T的传入参数只能是Map以及子类,实现类。若不指定,传入的时候编译器会校验是否为Object(类似)处理。运行的时候,编译器会去根据你的代码强转,才会存在castclass异常,如果你代码里面不去强转的话,同样不会任何错,这跟你后面补图里面,返回了原本的类名一样;
所以个人觉得泛型,并不是编译器决定的是由用户的代码敲定的,若不指定则为Object的效果,若指定则为指定的类,但是T始终只是代表一种class类类型,并不代表实体对象的实际class类型;若实体对象的class类型跟指定的class类型不一致,就会报错
C_FengSu 2018-07-27
  • 打赏
  • 举报
回复
引用 9 楼 flyfeifei66 的回复:
[quote=引用 7 楼 u010970951 的回复:]


public <T> Long zrem(String key, T member);
public Long zrem(String key, List<Object> members);

或者调过来,第一个带T,第二个用具体类型,也能区分。[/quote]


首先,这个List和T不是一个东西吧,我为了理解改了一下代码
class TestClass{

public Long zrem(String key, Object member) {
return 1L;
}

public Long zrem(String key, List<Object > members) {
return 2L;
}

public Long zrem(String key, String members) {
return 3L;
}

public <T> Long zrem(String key, T members) {
return 4L;
}

}


上面的代码中,1L和4L是冲突的。1L和4L和其他两个都不会冲突(就是123,234一起不会冲突),
你可以试试调用一下,看看打印的结果是什么
济南大飞哥 2018-07-27
  • 打赏
  • 举报
回复
引用 7 楼 u010970951 的回复:


public <T> Long zrem(String key, T member);
public Long zrem(String key, List<Object> members);

或者调过来,第一个带T,第二个用具体类型,也能区分。
济南大飞哥 2018-07-27
  • 打赏
  • 举报
回复
又见一个诡异问题。
引用 4 楼 C_FengSu 的回复:
[quote=引用 3 楼 C_FengSu 的回复:]
我觉得是在泛型方法return;的时候确定的,

补图(刚开始用按到Ctrl+Enter就发出来了)
[/quote]

我一个类中写了两个方法

public Long zrem(String key, Object member);

public Long zrem(String key, List<?> members);

分别表示处理一个任何类型和多个任意类型。上述写法能正常调用到。
而如果写成

public Long zrem(String key, Object member);

public Long zrem(String key, List<Object > members);

那么我即便传递一个list参数,实际只会永远调用第一个,但是编辑器并不报方法定义重复。
stacksoverflow 2018-07-26
  • 打赏
  • 举报
回复
引用 5 楼 stacksoverflow 的回复:
我理解泛型就是个模板替换在编译期间的替换。让代码更清晰并且避免了强制转换导致的运行期间才发现类型不匹配问题。
至于由入参还是返回值来决定,不重要,反正编译过不去的话,说明代码肯定有问题,这就是泛型要达到的目的,避免了把问题推移到运行期间。

就像代码写错了,编译器会提示错误一样,至于编译器怎么parse的程序,我不想也无力关心。
stacksoverflow 2018-07-26
  • 打赏
  • 举报
回复
我理解泛型就是个模板替换在编译期间的替换。让代码更清晰并且避免了强制转换导致的运行期间才发现类型不匹配问题。
至于由入参还是返回值来决定,不重要,反正编译过不去的话,说明代码肯定有问题,这就是泛型要达到的目的,避免了把问题推移到运行期间。
C_FengSu 2018-07-26
  • 打赏
  • 举报
回复
引用 3 楼 C_FengSu 的回复:
我觉得是在泛型方法return;的时候确定的,

补图(刚开始用按到Ctrl+Enter就发出来了)
C_FengSu 2018-07-26
  • 打赏
  • 举报
回复
我觉得是在泛型方法return;的时候确定的,
济南大飞哥 2018-07-26
  • 打赏
  • 举报
回复
人工人工人工人工人工

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧