java学习加拓展(持续更新,找需要的内容请crl+f搜索)@@huzicpp

本文详细介绍了Java中的泛型,包括泛型类、泛型方法、泛型继承、类型通配符和泛型擦除。同时,讲解了Java注解的使用,包括自定义注解、元注解以及注解的反射处理。通过对泛型和注解的深入理解,可以提高代码的安全性和可维护性。

java泛型

原文链接

  1. 泛型的解释:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊类型。
  2. 参数化类型:<数据类型>的数据类型只能是引用类型,含义是将类型放在<>当做参数一样传递。
有关概念:
ArrayList<E>中的E称为类型参数变量, ArrayList<Integer>中的Integer称为实际类型参数。
整个ArrayList<E>称为泛型类型,整个ArrayList<Integer>称为参数化的类型。
泛型需要的原因:
Collection, Map集合对元素的类型没有任何限制,本来我们的Collection集合装载的是全部的Dog对象,但是外面把Cat储存到集合中,是没有任何问题的。
避免返回对象之后还要强制类型转换。

泛型类

解释:泛型类就是将泛型定义在类上,例如:

class Dog <T>

用户使用该类的时候,才把类型明确下来。
在类上定义的泛型,在类的方法中可以被使用。
使用方法
在用户创建的时候指定类型,该类就会自动转换成用户需要的类型。

Dog<String> myDog = new Dog<>();

泛型方法

仅仅在方法中需要使用泛型,定义泛型方法(先定义后使用)

public <T> void show(T t){
}

泛型类继承

泛型接口

public interface Inter<T>{
	public abstract void show(T t);
}
子类明确泛型类的类型参数变量
public interface InterImpl implements Inter<String>
{
	@override
	public abstract void show(T t){
		System.out.print(s);
	}

}
子类不明确泛型类的类型参数变量

也要注明该泛型

public class InterImpl<T> implements Inter<T>
{
	@override
	public abstract void show(T t){
		System.out.print(s);
	}
}

注: 实现类的要是重写父类的方法,返回值的类型要和父类一样
类上声明的泛型只对非静态成员有效

类型通配符(很厉害的东西)

实例:需要一个方法接收一个集合参数,遍历集合并把集合元素打印出来(用list)

public void test(List<?> list)
{
	for(int i = 0; i < list.size(); i++){
		sysout(list.get(i));
	}

}

注:?可以匹配任意的类型,任意的java类都可以匹配。
泛型中的<Object>没有继承关系
只能调用对象与类型无关的方法,不能调用与类型有关的方法。

设定通配符的上限
List<? extends Number>

表示只能是Number的子类或者自身。

设定通配符的下限
<? super Type>

只能是Type或者Type的父类

泛型擦除

泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,挡住向集合插入非法数据,但是生成的class文件不瘦影响,这个过程称为擦除。

java注解(servlet用到,暂时没接触到)

常见注解就不讲了, 用到了再说

自定义注解

  1. 标记Annotation
    没有任何成员变量的注解称为标记注解,类似@override
public @interface MyAnnotation
{
}
  1. 元数据Annotation
    定义带成员变量的注解叫元数据注解(Annotation)
public @interface MyAnnotation
{
	String username();
	int age();
}

注意在注解上定义的成员变量只能是String, 数组,class,枚举类,注解

注解使用

通过注解来让方法拥有变量

//注解有什么属性,修饰的时候就要给出对应值
@MyAnnotation(username = "zhong", age = 20)
public void add(String username, int age)
{
}

注解设置默认值

public @interface MyAnnotation
{
	String username() default "ehllo";
	int age() default 20;
}

注解属性为value

public @interface MyAnnotation
{
	String value() default "ehllo";
}

可以不指定value,直接赋值

@MyAnnotation("hello")
注解的基本信息注入方法上
反射技术:
反射出该类的方法
通过方法得到注解上具体的信息
将注解上的信息注入到方法上
public static void reflection() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
	Class aClass = Annotation.class;
	Method method = aClass.getMethod("add", String.class, int.class);

	//通过该方法得到注解上的具体信息
	MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
	String username = annotation.username();
	int age = annotation.age();
	//这两句不太懂
	Object o = aClass.newInstance();
	method.invoke(o, username, age);
}

注:要在注解定义前加

@Retention(RetentionPolicy.RUNTIME)

JDK的元Annotation

@Retention修饰另一个Annotation
作用是将制定被修饰的Annotation被保留多次时间,包含一个RetentionPolicy类型value变量,
SOURCE 编译
CLASS class文件
RUNTIME 运行
因为我们使用反射得到注解上的信息,而反射是运行的时候来获取信息的,所以要修改保留时间。默认是保留到class。
@Target修饰另一个Annotation

target是指定Annotation的用途的。如果是指定ElementType为ANNOTATION_TYPE,则被修饰的annotation只能修饰annotation。

@Documented

被该注解修饰的注解类将被javadoc工具提取为文档

@Inherited

使得被修饰的注解,拥有继承性。被被修饰的类继承,而不是本身的继承。

<think>我们已知用户需求:使用Java结合Bouncy Castle 1.78版本实现签发CRL(证书吊销列表),并且签名过程需要调用外部的sign接口(而不是使用bc库内置的私钥签名)。 关键点: 1. CRL的构建:使用Bouncy Castle提供的类来构建CRL条目和CRL对象。 2. 调用外部签名接口:通常,bc库的CRL签发需要提供一个包含私钥的ContentSigner对象。但这里我们需要自定义一个ContentSigner,它不直接使用私钥,而是调用外部的签名服务。 步骤: 1. 创建X509v2CRLBuilder对象,设置颁发者、生效时间、下次更新时间等。 2. 添吊销条目(每个条目包含被吊销证书的序列号、吊销日期、原因等)。 3. 构建CRL时,需要提供一个ContentSigner。我们需要自定义一个ContentSigner实现,在其getOutputStream()方法中返回一个输出流,用于收集待签名的数据(即CRL的tbsCertList部分),然后在getSignature()方法中调用外部的签名服务对收集到的数据进行签名,并返回签名值。 注意:CRL的签名算法标识需要与外部签名使用的算法一致。这里我们假设使用SM2算法,因此算法标识应为“SM3withSM2”(OID: 1.2.156.10197.1.501)。 自定义ContentSigner的实现思路: - 定义一个类,实现ContentSigner接口。 - 在构造函数中,可以传入算法标识(如AlgorithmIdentifier)以及其他可能需要的参数(如访问外部签名服务的客户端)。 - 维护一个ByteArrayOutputStream,用于收集待签名数据。 - 实现getOutputStream()方法,返回这个ByteArrayOutputStream。 - 实现getSignature()方法:当需要生成签名时,从ByteArrayOutputStream中获取待签名数据(即tbsCertList部分),然后调用外部签名服务进行签名,返回签名值。 - 实现getAlgorithmIdentifier()方法,返回算法标识。 注意:在构建CRL时,bc库会先写入tbsCertList数据到ContentSigner的输出流,然后调用getSignature()获取签名,最后将签名值写入CRL中。 示例代码结构如下: 1. 自定义ContentSigner: ```java import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.operator.ContentSigner; import java.io.ByteArrayOutputStream; import java.io.IOException; public class ExternalSigner implements ContentSigner { private final AlgorithmIdentifier algorithmIdentifier; private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); public ExternalSigner(AlgorithmIdentifier algorithmIdentifier) { this.algorithmIdentifier = algorithmIdentifier; } @Override public AlgorithmIdentifier getAlgorithmIdentifier() { return algorithmIdentifier; } @Override public java.io.OutputStream getOutputStream() { return outputStream; } @Override public byte[] getSignature() { // 获取待签名数据(tbsCertList部分的DER编码) byte[] data = outputStream.toByteArray(); // 调用外部签名服务对data进行签名,假设有一个外部签名服务类:ExternalSignatureService // 这里需要根据实际情况实现,例如: // byte[] signature = ExternalSignatureService.sign(data); byte[] signature = ...; // 调用外部签名接口 return signature; } } ``` 2. 构建CRL并调用外部签名: ```java import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.*; import org.bouncycastle.cert.X509v2CRLBuilder; import java.math.BigInteger; import java.util.Date; public class CRLGenerator { public static void main(String[] args) throws Exception { // 颁发者名称(应与CA证书的主题一致) X500Name issuerName = new X500Name("CN=Test CA, O=Test Organization, C=CN"); // 创建CRL构建器 X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerName, new Date()); // 设置下次更新时间 crlBuilder.setNextUpdate(new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000)); // 添吊销条目(示例:吊销两个证书) crlBuilder.addCRLEntry(new BigInteger("123456"), new Date(), CRLReason.privilegeWithdrawn); crlBuilder.addCRLEntry(new BigInteger("789012"), new Date(), CRLReason.cessationOfOperation); // 创建自定义的ContentSigner(使用SM2签名算法) AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(GMObjectIdentifiers.sm2sign_with_sm3); // 对应OID: 1.2.156.10197.1.501 ContentSigner externalSigner = new ExternalSigner(sigAlgId); // 构建CRL X509CRLHolder crlHolder = crlBuilder.build(externalSigner); // 将证书吊销列表写入文件或进行其他操作 byte[] crlBytes = crlHolder.getEncoded(); // ... 保存或发送CRL } } ``` 需要注意的事项: 1. ExternalSigner类中的getSignature()方法需要实现对外部签名服务的调用。外部签名服务应该能够根据传入的tbsCertList数据(即原始数据)和指定的算法(SM3withSM2)生成签名。注意,外部签名服务可能需要知道公钥对应的私钥在哪里(例如:硬件密机、远程签名服务器等)。 2. 签名算法标识:在Bouncy Castle中,SM2签名算法的OID为1.2.156.10197.1.501(即GMObjectIdentifiers.sm2sign_with_sm3)。需要引入bc的prov包,版本1.78。 3. 外部签名服务返回的签名值应该是DER编码的。因为SM2签名值通常由两个大整数(r, s)组成,需要按照ASN.1 DER编码格式进行编码。如果外部签名服务返回的是两个大整数的字节数组(未编码),则需要在getSignature()方法中进行DER编码。 关于DER编码:可以使用Bouncy Castle的DERSequence来构造: ```java ASN1EncodableVector v = new ASN1EncodableVector(); v.add(new ASN1Integer(new BigInteger(1, r))); // r和s是签名值的两个部分 v.add(new ASN1Integer(new BigInteger(1, s))); return new DERSequence(v).getEncoded(ASN1Encoding.DER); ``` 但是,如果外部签名服务已经返回了DER编码的签名,则直接返回即可。 另外,引用[1]中提到不同bc包版本可能有区别,但1.78版本与1.60以上版本在CRL签发方面应该没有重大变化。注意在项目中正确引入bcprov-jdk15on-178.jar(或对应版本的jar包)。 由于用户特别提到bc库1.78版本,我们使用该版本进行开发。 总结:通过自定义ContentSigner,我们可以将签名过程委托给外部服务,从而实现在不直接访问私钥的情况下完成CRL的签发。 §§相关问题§§ 1. 如何验证使用外部签名服务签发的CRL? 2. 在自定义ContentSigner中,如何处理签名失败的情况? 3. 除了CRL,这种方法是否也适用于签发X.509证书? </think>### Java使用Bouncy Castle 1.78实现CRL签发及外部签名调用 #### 核心实现步骤 1. **依赖配置** 添Bouncy Castle 1.78依赖(Maven): ```xml <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> <version>1.78</version> </dependency> ``` 2. **构建CRL主体** 创建CRL条目并设置吊销信息: ```java import org.bouncycastle.asn1.x509.*; import org.bouncycastle.cert.X509v2CRLBuilder; X500Name issuer = new X500Name("CN=CA, O=MyOrg, C=CN"); X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, new Date()); // 添吊销条目(证书序列号+吊销时间+原因) crlBuilder.addCRLEntry( new BigInteger("123456"), new Date(), CRLReason.privilegeWithdrawn ); ``` 3. **自定义签名接口** 实现`ContentSigner`抽象签名逻辑: ```java import org.bouncycastle.operator.ContentSigner; import java.io.OutputStream; public class ExternalSigner implements ContentSigner { private final ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); @Override public OutputStream getOutputStream() { return dataStream; // 收集待签名数据 } @Override public byte[] getSignature() { byte[] tbsData = dataStream.toByteArray(); return callExternalSignApi(tbsData); // 调用外部签名服务 } @Override public AlgorithmIdentifier getAlgorithmIdentifier() { return new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256); } } ``` 4. **调用外部签名服务** 模拟外部签名接口调用(需对接实际HSM/签名服务): ```java private byte[] callExternalSignApi(byte[] tbsData) { // 示例:通过HTTP调用外部签名服务 // 实际需替换为HSM/SDK调用 return HttpPost("https://sign-service/api/sign", tbsData); } ``` 5. **生成最终CRL** 组合构建并输出CRL: ```java X509CRLHolder crlHolder = crlBuilder.build(new ExternalSigner()); byte[] crlDer = crlHolder.getEncoded(); // DER格式CRL ``` #### 关键注意事项 1. **数据一致性** 外部签名服务需严格处理原始数据 `tbsData`(未签名的CRL主体),避免修改内容[^1]。 2. **算法标识匹配** `AlgorithmIdentifier` 必须与实际签名算法一致(如SM2需用 `GMObjectIdentifiers.sm2sign_with_sm3`)[^1]。 3. **BC包冲突解决** 若接入方存在不同BC版本: - 使用Maven Shade插件重定位包名 - 动态载BC Provider(需OpenJDK支持): ```java Security.insertProviderAt(new BouncyCastleProvider(), 1); ``` 4. **签名格式** 外部服务返回的签名值需符合DER编码规范(SM2签名应为 `r||s` 格式)。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值