JavaSE实现Pair<A, B>的record基础类与深拷贝(原型模式)

 在Programming时,经常遇到需要操纵一对参数的场景。像C++就有的std::pair

import org.jetbrains.annotations.Contract; //可选,因为是辅助人编码用的注解
import org.jetbrains.annotations.NotNull; //可选,因为是辅助人编码用的注解
import org.jetbrains.annotations.Nullable; //可选,因为是辅助人编码用的注解

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serial;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;

/**
 * Generic pair.<br>
 * Although the instances of this class are immutable, it is impossible
 * to ensure that the references passed to the constructor will not be
 * modified by the caller.
 * @param Yin
 * @param Yang
 * @param <A> It is best to have implemented the {@code Serializable} interface, and even if it's not, the {@code Cloneable} interface must have been implemented.
 * @param <B> It is best to have implemented the {@code Serializable} interface, and even if it's not, the {@code Cloneable} interface must have been implemented.
 * @author DIA
 */
public record Pair<A, B>(@NotNull A Yin, @NotNull B Yang) implements Serializable, Cloneable {
	@Serial private static final long serialVersionUID = -8245392630373082964L;

	/**
	 * @return {@code Pair<A, B>}: {@code (Yin, Yang)}
	 */
	@Override
	@NotNull
	public String toString() {
		return "Pair<" + Yin.getClass() + ", " + Yang.getClass() + ">: (" + Yin + ", " + Yang + ")";
	}

	/**
	 * @param otherObject the reference object with which to compare.
	 * @return {@code true} if the given object is also a map entry and
	 * the two entries represent the same mapping.
	 */
	@Override
	@Contract(value = "null -> false", pure = true)
	public boolean equals(@Nullable final Object otherObject) {
		return (this == otherObject) ||
			   ((otherObject instanceof Pair<?,?> pair) &&
				Objects.equals(Yin, pair.Yin) && Objects.equals(Yang, pair.Yang));
	}

	/**
	 * @param otherYin Type A parameter of other record {@code Pair<A, B>}
	 * @param otherYang Type B parameter of other record {@code Pair<A, B>}
	 * @return {@code true} if {@code otherYin} equals to {@code Yin} and {@code otherYang} equals to {@code Yang}
	 */
	public boolean equals(@Nullable final A otherYin, @Nullable final B otherYang) {
		return Yin.equals(otherYin) && Yang.equals(otherYang);
	}

	/**
	 * @return a {@code Pair<A, B>} instance obtained by <strong>deep cloning</strong>
	 * if A and B both have implemented {@code Serializable} or {@code Cloneable} interface.
	 * Otherwise, the instance {@code Pair<A, B>} obtained by the <strong>shallow copy</strong> will be returned.
	 * @throws CloneNotSupportedException {@code throw new CloneNotSupportedException} if Both not be implemented {@code Serializable}.
	 */
	@SuppressWarnings("unchecked")
	@Override
	@Contract(" -> new")
	@NotNull
	public Pair<A, B> clone() throws CloneNotSupportedException {
		if ( Yin instanceof Serializable && Yang instanceof Serializable ) {
			try(final var BYTES_OUT = new ByteArrayOutputStream();
				final var OOS = new ObjectOutputStream(BYTES_OUT)
			) {
				OOS.writeUnshared(Yin);
				OOS.writeUnshared(Yang);
				try(final var OIS = new ObjectInputStream(new ByteArrayInputStream(BYTES_OUT.toByteArray())
				) {
					return new Pair<>((A) OIS.readUnshared(), (B) OIS.readUnshared()); //必定返回深克隆的对象
				}
			} catch (final IOException | ClassNotFoundException e) {
				e.printStackTrace();
			}
		}else if ( Yin instanceof Cloneable && Yang instanceof Cloneable ) {
			try {
				return new Pair<>((A) Yin.getClass().getDeclaredMethod("clone").invoke(Yin), (B) Yang.getClass().getDeclaredMethod("clone").invoke(Yang));
			} catch (final IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
				e.printStackTrace();
			}
		}
		return (Pair<A, B>) super.clone(); //有可能会返回浅克隆的对象
	}
}

主要涉及到的知识点为record基础类型的coding,Java的反射,以及Deep Cloning深拷贝的具体实现,并且我让.clone()方法无论如何都要返回一个cloned实例对象(有可能是浅拷贝的),而且尽可能地是深拷贝的实例对象。

Java record基础类型 多种方式实现深拷贝,主要用过序列化与反序列化实现绝对的深拷贝。同时也采用了反射来进行深拷贝,因为Object的.clone()方法是protected级别的。即使深拷贝失败,也至少会返回浅拷贝的实例对象。

下面是简单的测试用例:

    @Test
	void test03() throws CloneNotSupportedException {
		final var array = new ArrayList<Integer>();
		final var p0 = new Pair<>(array, "3225");
		final var p1 = new Pair<>(new ArrayList<>(List.of(56455, 425, 85638, 9)), "3225");
		array.add(56455);
		array.add(425);
		array.add(85638);
		final var p2 = p0.clone();
		p1.Yin().remove(p1.Yin().size() - 1);
		Assertions.assertEquals(p0, p1);
		Assertions.assertEquals(p0, p2);
		System.out.println(p0.hashCode());
		array.clear();
		System.out.println(p0);
		System.out.println(p1);
		System.out.println(p2);
		System.out.println(p1.hashCode() + "------" + p2.hashCode());
		Assertions.assertNotEquals(p0, p2);
		Assertions.assertEquals(p1, p2);
	}

该测试成功通过✅,运作效果完全在计划之中,尚未发现任何偏差。

唯一的遗憾便是SonarLint老是对我的.clone()方法发出警告,说啥必须要使用构造方法、工厂方法构造的方式,来代替.clone()方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

被遗忘的DIA

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值