EL通过Integer键访问映射值

我有一个由Integer键入的Map。 使用EL,我怎样才能通过它的键访问一个值?

Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1, "One"); map.put(2, "Two"); map.put(3, "Three"); 

我认为这将工作,但它不(在地图已经在请求的属性):

 <c:out value="${map[1]}"/> 

跟进:我跟踪了这​​个问题。 显然${name[1]}会将数字作为Long进行地图查找。 当我将HashMap更改为TreeMap并收到错误时,我想到了这一点:

 java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long 

如果我改变我的地图是:

 Map<Long, String> map = new HashMap<Long, String>(); map.put(1L, "One"); 

那么${name[1]}返回“One”。 那是什么? 为什么<c:out>把一个数字视为一个长整数。 这似乎违反我的想法(因为int比long更常用)。

所以我的新问题是,是否有一个通过Integer值访问映射的EL符号?

初步答复(EL 2.1,2009年5月)

正如在这个java论坛主题中提到的:

基本上自动装箱将一个Integer对象放到Map中。 即:

 map.put(new Integer(0), "myValue") 

EL(expression式语言)将0评估为长,因此在地图中寻找Long作为键。 即它评估:

 map.get(new Long(0)) 

由于Long不等于Integer对象,因此它在地图中找不到该条目。
这就是简而言之。


自2009年5月以来的最新情况(EL 2.2)

2009年12月,引入了EL 2.2和JSP 2.2 / Java EE 6 ,与EL 2.1相比有一些不同 。
看来(“ ELexpression式parsing整数一样长 ”):

您可以在EL 2.2中的Long对象self上调用intValue方法

 <c:out value="${map[(1).intValue()]}"/> 

这可能是一个很好的解决方法(下面Tobias Liefke的答案中也提到)


原始答案:

EL使用以下包装器:

 Terms Description Type null null value. - 123 int value. java.lang.Long 123.00 real value. java.lang.Double "string" ou 'string' string. java.lang.String true or false boolean. java.lang.Boolean 

展示这个的JSP页面:

  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ page import="java.util.*" %> <h2> Server Info</h2> Server info = <%= application.getServerInfo() %> <br> Servlet engine version = <%= application.getMajorVersion() %>.<%= application.getMinorVersion() %><br> Java version = <%= System.getProperty("java.vm.version") %><br> <% Map map = new LinkedHashMap(); map.put("2", "String(2)"); map.put(new Integer(2), "Integer(2)"); map.put(new Long(2), "Long(2)"); map.put(42, "AutoBoxedNumber"); pageContext.setAttribute("myMap", map); Integer lifeInteger = new Integer(42); Long lifeLong = new Long(42); %> <h3>Looking up map in JSTL - integer vs long </h3> This page demonstrates how JSTL maps interact with different types used for keys in a map. Specifically the issue relates to autoboxing by java using map.put(1, "MyValue") and attempting to display it as ${myMap[1]} The map "myMap" consists of four entries with different keys: A String, an Integer, a Long and an entry put there by AutoBoxing Java 5 feature. <table border="1"> <tr><th>Key</th><th>value</th><th>Key Class</th></tr> <c:forEach var="entry" items="${myMap}" varStatus="status"> <tr> <td>${entry.key}</td> <td>${entry.value}</td> <td>${entry.key.class}</td> </tr> </c:forEach> </table> <h4> Accessing the map</h4> Evaluating: ${"${myMap['2']}"} = <c:out value="${myMap['2']}"/><br> Evaluating: ${"${myMap[2]}"} = <c:out value="${myMap[2]}"/><br> Evaluating: ${"${myMap[42]}"} = <c:out value="${myMap[42]}"/><br> <p> As you can see, the EL Expression for the literal number retrieves the value against the java.lang.Long entry in the map. Attempting to access the entry created by autoboxing fails because a Long is never equal to an Integer <p> lifeInteger = <%= lifeInteger %><br/> lifeLong = <%= lifeLong %><br/> lifeInteger.equals(lifeLong) : <%= lifeInteger.equals(lifeLong) %> <br> 

除了上面的注释之外,另外一个有用的提示是当你在一些variables中包含一个string值时,比如请求参数。 在这种情况下,将这个传入也将导致JSTL将“1”的值作为一个sting,并在Map哈希映射中找不到匹配。

解决这个问题的一个方法是做这样的事情。

 <c:set var="longKey" value="${param.selectedIndex + 0}"/> 

这将被视为一个Long对象,然后有一个机会来匹配一个对象,当它包含在地图Map或其他内容中。

然后像往常一样继续

 ${map[longKey]} 

如果您将数字放入“(”“)”“,则可以使用Long中的所有function。 这样你就可以把long赋给int:

 <c:out value="${map[(1).intValue()]}"/> 

基于上面的post,我试了这个,这工作得很好,我想使用地图B的值作为地图A的键:

 <c:if test="${not empty activityCodeMap and not empty activityDescMap}"> <c:forEach var="valueMap" items="${auditMap}"> <tr> <td class="activity_white"><c:out value="${activityCodeMap[valueMap.value.activityCode]}"/></td> <td class="activity_white"><c:out value="${activityDescMap[valueMap.value.activityDescCode]}"/></td> <td class="activity_white">${valueMap.value.dateTime}</td> </tr> </c:forEach> </c:if> 

如果你碰巧有一个带有Integer键的Map ,你不能改变,你可以编写一个自定义的EL函数来把Long转换为Integer 。 这将允许你做这样的事情:

 <c:out value="${map[myLib:longToInteger(1)]}"/>