【问题标题】:How to cast a Session object to Map?如何将 Session 对象转换为 Map?
【发布时间】:2014-02-11 21:37:56
【问题描述】:

我正在转换旧的 java 代码以支持泛型,并遇到了这行代码,它试图将从会话中检索到的对象转换为 TreeMap

TreeMap allTransactions = (TreeMap) pageContext.getSession()
                                               .getAttribute("allTransactions");

当我尝试将其转换为特定类型时:

TreeMap<String, MyDataBean> allTransactions = (TreeMap<String, MyDataBean>) 
                       pageContext.getSession().getAttribute("allTransactions");

它给了我一个warning

Type safety: Unchecked cast from Object to TreeMap<String,MyDataBean>

为了彻底消除警告,我编写了一个方法将其转换为Map

public static <K,V> Map<K,V> castToMap(Class<? extends K> clazz1, 
                                       Class<? extends V> clazz2, Map<?,?> c) {
    Map<K,V> map = new TreeMap<K,V>();
    for (Map.Entry<?,?> entry : c.entrySet()) {
        Object key = entry.getKey();
        Object value = entry.getValue();
        map.put(clazz1.cast(key), clazz2.cast(value));
    }
    return map;
}

好消息:这次我修改初始代码调用这个方法时没有报错:

Map<String, MyDataBean> allTransactions = MyUtilityClass.castToMap(String.class, 
                                                               MyDataBean.class, 
            (Map<?,?>)pageContext.getSession().getAttribute("allTransactions"));

但我仍然必须在 ^^^here 转换它来调用我的函数。

问题 1: 为什么现在我仍在使用演员表(Map&lt;?,?&gt;) 而不是我之前尝试过的(TreeMap&lt;String,MyDataBean&gt;) 时没有显示任何错误?

问题 2: 由于其他开发人员尚未提交代码,我的应用程序目前已损坏,因此我无法运行该应用程序并验证其正确性。任何人都可以通过查看它来判断此铸造的行为是否与以前相同?

【问题讨论】:

  • 我认为添加该方法没有意义。它没有实现任何具体的目标。地图就是地图,通用符号只是装点门面——也许在编写新代码时可用作调试辅助工具,但当您知道代码按原样工作时,它只会妨碍您。
  • 请注意,TreeMap 有一个接受地图的构造函数。所以你的演员可以简单地是return new TreeMap&lt;K,V&gt;(c);docs.oracle.com/javase/7/docs/api/java/util/…
  • @HotLicks 我必须摆脱警告。你能推荐一个替代方案吗?
  • @corsiKa 当我这样写return new TreeMap&lt;K,V&gt;((Comparator&lt;? super K&gt;) c);时,它仍然会发出未经检查的警告
  • 原代码有什么问题?还是TreeMap&lt;?,?&gt;

标签: java session generics map casting


【解决方案1】:

如果它是 Map,那么它隐含地是 Map&lt;?,?&gt; - 就像任何东西的映射一样。它认为这是一个安全的转换,因为它是一张地图,它不会失败。在这一点上,这与将其强制转换为任何其他对象没有什么不同,他们认为这是安全的。

如果它是一个糟糕的演员表(比如说它是一个列表,而不是一个地图),那么它会在其他任何事情出错之前在那里爆炸。但是因为这些类型在编译时丢失了,如果问题出在泛型类型上,它会很高兴地继续下去。所以Map&lt;?,?&gt; 被认为是安全的,因为如果这是问题,它会因为不是地图而爆炸。

就您的第二个问题而言,它看起来不错,但如果没有更多上下文,很难说。话虽如此,您应该能够使用源代码管理中的历史记录来获取早期版本进行比较。如果您无法获得早期版本的代码,那么您的源代码管理就不是很有用了,是吗?

【讨论】:

  • 如果 it 是一个 Map 那么它隐含是一个 Map,?> - 你的意思是会话对象?
  • 不,我的意思是 pageContext.getSession().getAttribute("allTransactions") - 毕竟这就是你要投射的,对吧?
  • 是的,这就是我正在铸造的。但是TreeMap&lt;String,MyDataBean&gt; 有什么问题呢?我在这里的类型更清楚。
  • 因为会话对象不存储 TreeMap&lt;String,MyDataBean&gt; 引用 - 它存储 Object 引用。如果您想将 Object 转换为 Map&lt;?,?&gt;,没有警告也没关系。但是,一旦您尝试将这些泛型类型放入其中,它就会说“等等,您需要对此进行一些验证。”
【解决方案2】:

广告 1.:强制转换本身是安全的,因为您没有指定编译器无法与方法签名匹配的任何类型。 Java 4 List 可以安全地分配给 Java 5 List&lt;?&gt;,但是当你指定一个类型时,你会假设一些东西,编译不能安全地检查(因此警告)。

广告 2.:您已经用“软”方法调用转换替换了“硬”语言转换,如果类不能相互转换,这将同样失败 - 我更喜欢语言转换的不太冗长的版本,因为应该依赖自己的 API。

【讨论】:

  • 我不明白你所说的hard 语言转换是什么意思。能否请您简单解释一下您的Ad2 解释?
  • 我相信他的意思是硬转换定义了泛型类型,而软转换只是改变了引用类型(当然不是基础类类型)。
  • TreeMap&lt;String, MyDataBean&gt; allTransactions = (TreeMap&lt;String, MyDataBean&gt;) pageContext.getSession().getAttribute("allTransactions"); 是一种语言转换,因为您使用 Java 语言构造转换 getAttribute() 的结果,而 clazz1.cast(key) 使用封装在方法调用中的转换。
  • 一个小问题,前泛型被称为 Java 1.4,而不是 Java 4。他们去掉了“1”。从 Java 5 开始。
  • 你能举一个在这种情况下不那么冗长的语言转换的例子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-02
  • 1970-01-01
  • 2016-08-07
  • 1970-01-01
  • 2011-12-23
  • 2020-03-16
相关资源
最近更新 更多