Arrays.asList(@NotNull T... a) 用法总结

1、Arrays.asList()方法简介

  • Arrays.asList主要用来将泛型可变长参数转换为List。
  • T… a是泛型可变长参数,可以简单理解为是数组。 一个方法只能有一个可变长参数,并且这个可变长参数必须是该方法的最后一个参数。

2、Arrays.asList()源码


    /**
     * Returns a fixed-size list backed by the specified array.  (Changes to
     * the returned list "write through" to the array.)  This method acts
     * as bridge between array-based and collection-based APIs, in
     * combination with {@link Collection#toArray}.  The returned list is
     * serializable and implements {@link RandomAccess}.
     *
     * <p>This method also provides a convenient way to create a fixed-size
     * list initialized to contain several elements:
     * <pre>
     *     List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
     * </pre>
     *
     * @param <T> the class of the objects in the array
     * @param a the array by which the list will be backed
     * @return a list view of the specified array
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

注意,上面源码中,new ArrayList<>(a); 并非是new 的java.util包下的ArrayList,而是new的Arrays中的内部类,如下:

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }
      ......
  }
  

3、Arrays.asList几种场景及易出现问题

3.1、Arrays.asList(String[]) 字符串数组转List

    public static void main(String[] args) {
        List<String> list = Arrays.asList("jack", "bob", "alice", "mark");
        System.out.println(JSON.toJSONString(list));
		// 结果返回:["jack","bob","alice","mark"]
    }   

3.2、Arrays.asList(int[]) int数组转List

    public static void main(String[] args) {
        int[] intarr = {1, 3, 4, 5, 6};
        List intList = Arrays.asList(intarr);
        System.out.println(JSON.toJSONString(intList));
    }
    // 返回结果:[[1,3,4,5,6]]
    // 注意:这里有个问题点需要注意,看下面:
  • 仅从结果打印上看,很多粗心的人回认为int数组和String数组转List都可以正确打印,并且数值也都按照int数组和String数组中的值打印出来了,但需要注意的是,打印的JSON串是有区别的:

    ["jack","bob","alice","mark"]	// 这是String数组打印值
    [[1,3,4,5,6]]					// 这是int数组打印值
    
  • 从上面打印的结果值可以看出,int数组外层是多了一个中括号的; 这种情况是因为转换的入参是泛型T… a,而泛型不能是基本数据类型,但为什么我们这里传的int数组没报错,也可以打印出来呢?因为Arrays.asList方法将入参的int数组当做是一个整体,该整体作为泛型传入参数,所以打印结果值的外面是多一层中括号的。 为方便理解,可以将int size = intList.size();打印,其结果是1,而不是5。

3.3、Arrays.asList(Person[]) Person对象数组转List

    public static void main(String[] args) {
        List<Person> peopleList = Arrays.asList(new Person(22, "张三"), new Person(33, "李四"), new Person(44, "王五"));
        System.out.println(JSON.toJSONString(peopleList));
        // 打印结果为:[{"age":22,"name":"张三"},{"age":33,"name":"李四"},{"age":44,"name":"王五"}]
    }
  • 可以看到代码中,直接传的是Person对象。若有一种场景,我需要在List中再添加上“赵六的信息”,这时我如果使用peopleList.add(new Person(55, “赵六”));就会报错。 是因为Arrays.asList得到的List是一个长度不可变的list,若想改为长度,可以使用:
List<Person> peopleList = Arrays.asList(new Person(22, "张三"), new Person(33, "李四"), new Person(44, "王五"));
System.out.println(JSON.toJSONString(peopleList));

// 将Arrays.asList生产的List转换成可变长的List
ArrayList<Person> peoples = new ArrayList<>(peopleList);
peoples.add(new Person(55, "赵六"));
  • 报错信息:
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:148)
	at java.util.AbstractList.add(AbstractList.java:108)
@Test public void testGetDeviceSimpleListInternal_MultipleDevices() { // 准备测试数据 OmadacId omadacId = new OmadacId("test-omadac"); SiteId siteId = new SiteId("test-site"); DeviceOutlineSimpleDTO dbDevice1 = new DeviceOutlineSimpleDTO(); dbDevice1.setMac("00:11:22:33:44:55"); DeviceOutlineSimpleDTO dbDevice2 = new DeviceOutlineSimpleDTO(); dbDevice2.setMac("AA:BB:CC:DD:EE:FF"); // 模拟行为 when(deviceRepository.findByOmadacIdAndSiteForOutLineSimple(omadacId, siteId)) .thenReturn(Arrays.asList(dbDevice1, dbDevice2)); when(deviceImageRepository.listByOmadacIdAndSiteIdAndMacs(omadacId, siteId, new HashSet<>(Arrays.asList("00:11:22:33:44:55", "AA:BB:CC:DD:EE:FF")))) .thenReturn(Collections.emptyList()); when(queryDeviceService.fillDeviceImageByOtherNode(anyList(), eq(omadacId), eq(siteId))) .thenReturn(Collections.emptyList()); when(queryDeviceService.resolveDeviceOutlinesSimple(anyList(), anyList(), isNull(), isNull())) .thenReturn(Arrays.asList(dbDevice1, dbDevice2)); // 调用方法 List<DeviceOutlineSimpleDTO> result = queryDeviceService.getDeviceSimpleListInternal( omadacId, siteId, null, null, false); // 验证结果 assertNotNull(result); assertEquals(2, result.size()); }也报错:org.mockito.exceptions.misusing.NotAMockException: Argument passed to when() is not a mock! Example of correct stubbing: doThrow(new RuntimeException()).when(mock).someMethod(); at com.tplink.smb.omada.manager.device.domain.model.device.QueryDeviceServiceTest.testResolveDeviceOutlinesSimple_WithMatchingDevice(QueryDeviceServiceTest.java:808) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
11-22
<think>我们已经在代码中注册了BouncyCastle提供者(通过`Security.addProvider(new BouncyCastleProvider())`),并且通过`Arrays.asList(Security.getProviders()).forEach(...)`确认了BC提供者已存在,但仍然出现`Unknown named curve`错误。 可能的原因及解决方案: 1. **Bouncy Castle版本问题**:旧版本可能不支持特定的国密曲线OID。请确保使用最新版本的Bouncy Castle(如1.77或更高版本)。在Maven中,可以检查依赖: ```xml <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> <version>1.77</version> </dependency> ``` 2. **提供者注册顺序问题**:在解析证书之前,必须确保Bouncy Castle提供者已被正确注册。如果注册发生在证书解析之后,则无效。同时,注意提供者的优先级:当多个提供者支持相同算法时,Java默认使用优先级最高的(位置靠前的)。我们可以尝试将BC提供者设置为首位: ```java Security.insertProviderAt(new BouncyCastleProvider(), 1); ``` 3. **证书解析的代码位置**:确保在调用`CertificateFactory.getInstance("X.509")`之前已经注册了BC提供者。因为`CertificateFactory`在初始化时会根据当前已注册的提供者来创建实例。 4. **曲线OID的映射问题**:虽然BC支持国密曲线,但可能没有将OID`1.2.156.10197.1.301`映射到具体的曲线实现。我们可以尝试手动添加OID映射(如果BC支持该曲线,一般不需要手动添加,但以防万一)。 5. **使用BC的`JceProvider`还是`FipsProvider`**:注意,Bouncy Castle有两个版本:普通版和FIPS版。国密算法通常在普通版中支持,确保没有错误地使用了FIPS提供者。 6. **完整的证书链问题**:如果证书链中包含了其他使用国密曲线的中间CA证书,也需要确保这些证书的曲线OID被识别。可能整个证书链都需要BC支持。 7. **尝试使用BC的`PEMParser`**:如果证书是PEM格式,可以尝试使用BC的`PEMParser`来读取证书,这样可能会更好地利用BC的扩展支持。 8. **调试BC的曲线注册表**:可以通过BC的API查看已注册的曲线,确认该OID是否被正确注册。 9. **使用BC的CertificateFactory**:显式指定使用BC提供的CertificateFactory实例。 具体步骤: **步骤1:升级BC版本并优先注册提供者** 修改注册代码,将BC提供者放在首位,并确保在解析证书之前调用: ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; // ... // 在静态块或程序初始化时注册 static { Security.removeProvider("BC"); // 先移除已有BC提供者(如果有) Security.insertProviderAt(new BouncyCastleProvider(), 1); } ``` **步骤2:检查BC提供者是否支持该曲线** 可以通过以下代码打印BC支持的所有椭圆曲线: ```java import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ECParameters; import java.util.Enumeration; // 打印所有已命名的曲线 Enumeration names = ECNamedCurveTable.getNames(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); X9ECParameters params = ECNamedCurveTable.getByName(name); System.out.println("Curve name: " + name + ", OID: " + params.getCurve().toString()); } ``` 如果输出中没有`1.2.156.10197.1.301`,则说明BC版本不支持,需要升级。 **步骤3:显式使用BC的CertificateFactory** 在获取CertificateFactory时,可以指定提供者: ```java CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); ``` **步骤4:使用BC的PEMParser(如果是PEM格式证书)** 如果证书是PEM格式,可以尝试: ```java import org.bouncycastle.openssl.PEMParser; import java.io.StringReader; // 假设digitalCertificate是PEM格式的字符串 try (PEMParser parser = new PEMParser(new StringReader(new String(digitalCertificate, StandardCharsets.UTF_8)))) { Object obj = parser.readObject(); if (obj instanceof X509Certificate) { X509Certificate cert = (X509Certificate) obj; // 使用证书 } } ``` **步骤5:手动注册国密曲线(可选)** 如果BC库中包含了该曲线,但没有通过OID自动注册,可以尝试手动映射: ```java import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; // 在注册BC提供者之后,手动添加国密曲线 ECNamedCurveParameterSpec sm2Spec = GMNamedCurves.getByName("sm2p256v1"); // 或者使用OID字符串 ``` 如果上述步骤仍不能解决问题,请检查证书本身是否有效,以及是否使用了正确的国密曲线参数。 最后,请确保在解析证书的代码中,BC提供者已经注册且位于提供者列表的首位,并且使用指定了提供者"BC"的`CertificateFactory`实例。 示例代码整合: ```java import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.Security; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import org.bouncycastle.jce.provider.BouncyCastleProvider; public class SM2CertificateParser { static { // 移除已有的BC提供者(避免重复) Security.removeProvider("BC"); // 添加BC提供者到首位 Security.insertProviderAt(new BouncyCastleProvider(), 1); } public static void main(String[] args) throws Exception { byte[] digitalCertificate = ... // 证书数据 parseCertificate(digitalCertificate); } public static void parseCertificate(byte[] digitalCertificate) { try { // 显式指定使用BC提供者 CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); try (InputStream is = new ByteArrayInputStream(digitalCertificate)) { X509Certificate x509Certificate = (X509Certificate) cf.generateCertificate(is); System.out.println("证书解析成功!"); System.out.println("证书算法:" + x509Certificate.getPublicKey().getAlgorithm()); } } catch (Exception e) { e.printStackTrace(); } } } ``` 如果问题仍然存在,请提供BC的版本号以及完整的错误堆栈。 §§相关问题§§ 1. 如何验证国密SM2证书的签名有效性? 2. 如何在Java中使用国密算法进行加密和签名? 3. 如何生成国密SM2证书? 4. 国密算法在HTTPS中如何配置? </think>### 解决 "Unknown named curve" 错误(已注册 Bouncy Castle 但仍报错) 虽然已确认 BC 提供者已注册,但仍出现曲线识别错误,以下是系统级解决方案: #### 根本原因分析 1. **BC 未正确注册到 SSL/TLS 上下文** 即使 BC 在全局提供者列表中可见,但证书解析时可能未使用 BC 的曲线解析器[^5] 2. **提供者优先级问题** Java 默认使用优先级最高的提供者,需确保 BC 在列表首位: $$Priority = 1 - \frac{Position}{ProviderCount + 1}$$ 位置越靠前优先级越高 3. **曲线别名未注册** 国密曲线 OID `1.2.156.10197.1.301` 需映射到具体实现类 --- ### 解决方案 #### 第一步:强制指定 BC 提供者 ```java // 静态代码块优先执行 static { Security.insertProviderAt(new BouncyCastleProvider(), 1); // 确保BC在首位 } // 解析证书时显式指定提供者 CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); // 关键点 InputStream is = new ByteArrayInputStream(digitalCertificate); X509Certificate cert = (X509Certificate) cf.generateCertificate(is); ``` #### 第二步:手动注册曲线别名 ```java import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; // 在解析前添加曲线映射 ECNamedCurveParameterSpec sm2Spec = GMNamedCurves.getByName("sm2p256v1"); Security.addProvider(new BouncyCastleProvider(){ { put("Alg.Alias.KeyFactory.1.2.156.10197.1.301", "SM2"); put("Alg.Alias.KeyPairGenerator.1.2.156.10197.1.301", "SM2"); } }); ``` #### 第三步:验证 BC 激活状态 ```java Provider bcProvider = Security.getProvider("BC"); if (bcProvider != null) { // 打印曲线支持列表 System.out.println("Supported curves: " + bcProvider.getProperty("AlgorithmParameters.EC SupportedCurves")); } else { throw new IllegalStateException("BouncyCastle provider not registered"); } ``` #### 配置检查清单 | 检查项 | 正确配置 | 错误配置 | |--------|----------|----------| | 提供者位置 | `Security.getProviders()[0]=BC` | `BC` 不在首位 | | 证书工厂 | `getInstance("X.509", "BC")` | 未指定提供者 | | 曲线别名 | 已注册 SM2 别名 | 未注册别名 | | BC 版本 | bcprov-jdk18on-1.77+ | 旧版本 | --- ### 高级解决方案 若上述步骤无效,需初始化国密算法上下文: ```java // 强制加载国密算法实现 Class.forName("org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$SM2"); Class.forName("org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util"); // 使用BC的KeyStore解析 KeyStore ks = KeyStore.getInstance("PKCS12", "BC"); ks.load(new ByteArrayInputStream(digitalCertificate), null); ``` > **重要提示**:国密证书需完整链验证,单独解析终端证书可能仍报错,需安装对应的国密根证书到信任库。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小野猪

若恰好解决你的问题,望打赏哦。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值