我正在尝试实现一个隔离对象的一部分的类,并用其他东西替换该部分。对象的一部分可能与对象本身的类型不同。
一个简单的例子是一个接受字符串“--12--”的类,隔离ascii数字,并用下一个自然数替换它。因此,整个序列将是"--12--" -> "12" -> 12 -> 13 -> "13" -> "--13--"
。
考虑到这一点,我实施了以下内容:
public abstract class Replacer<Outer, Inner>
{
protected abstract Inner decompose(Outer something);
protected abstract Outer compose(Inner something);
protected abstract Inner inner_replace(Inner something);
public Outer replace(Outer something)
{
Inner s = decompose(something);
s = inner_replace(s);
return compose(s);
}
}
现在,我希望能够编写一系列替换器 - 将它们堆叠起来,以便每个人使用“较低”的替换器计算其inner_replace
:
public abstract class ComposableReplacer<Outer, Inner> extends Replacer<Outer, Inner>
{
protected Replacer<Inner, ?> child;
@Override
public Outer replace(Outer something)
{
Inner s = decompose(something);
s = inner_replace(s);
if (child!=null)
s= child.replace(s);
return compose(s);
}
}
所以,到目前为止,这是正常的,但现在我正在尝试编写一个方便的方法 几个ComposableReplacers并自动堆叠它们:
public static <I, O> ComposableReplacer<I, O> compose(ComposableReplacer<?, ?>... rs)
{
for (int i=0; i<rs.length-1; i++)
rs[i].child= rs[i+1];
return rs[0];
}
这会失败,因为每个ComposableReplacer的内部类型必须是其子类型的外部类型,并且编译器无法从ComposableReplacer<?, ?>
数组中推断出它。
是否可以在java中执行此操作(并且仍具有类型安全性)?
修改
要清楚,问题是声明一个方法,它采用ComposableReplacer
数组并堆栈/链接它们,类型安全。
答案 0 :(得分:3)
即使支持通用数组,您的代码也会因逻辑错误而失败。数组由相同类型的元素组成,但您要执行的操作不适用于相同类型的项。如果您尝试使用两个参数而不是varargs来实现您的方法,这一点就变得清晰了:
// won’t work
public static <I, O> ComposableReplacer<I, O> compose(
ComposableReplacer<I, O> rs1, ComposableReplacer<I, O> rs2) {
rs1.child=rs2;
return rs1;
}
此代码仍然无法编译,因为rs1.child
需要ComposableReplacer<O,?>
而不是ComposableReplacer<I,O>
如果你解决这个问题,你的方法就会变成
public static <I, O> ComposableReplacer<I, O> compose(
ComposableReplacer<I, O> rs1, ComposableReplacer<O,?> rs2) {
rs1.child=rs2;
return rs1;
}
现在它可以工作,但这两个参数有不同的类型。如果Java具有类型安全的数组,则必须同时阻止包含ComposableReplacer<I, O>
和ComposableReplacer<O,?>
。 (除非您强制O
和I
相同。)
为了进一步说明,这里有三个参数的方法:
public static <I, O, X> ComposableReplacer<I, O> compose(
ComposableReplacer<I, O> rs1, ComposableReplacer<O,X> rs2,
ComposableReplacer<X, ?> rs3) {
rs1.child=rs2;
rs2.child=rs3;
return rs1;
}
在这里您可以看到每个参数都有不同的类型,并且您需要一个额外的类型参数,因此使用“类型安全数组”(读取java.util.List
)无法提供。最简单的解决方案是保持两个参数方法,让调用者多次调用它。或者n-arg如果你知道经常需要n args的用例。
答案 1 :(得分:0)
我会做那样的事情来实现目标
可以完成组合:
如果Inner和Outer相等:
abstract class Replacer<Outer, Inner> {
private Replacer<Inner, ?> child;
protected abstract Inner decompose(Outer something);
protected abstract Outer compose(Inner something);
protected abstract Inner inner_replace(Inner something);
public Replacer(Replacer<Inner, ?> child) {
this.child = child;
}
public Outer replace(Outer something) {
Inner s = decompose(something);
s = inner_replace(s);
if (child != null)
s = child.replace(s);
return compose(s);
}
public void setChild(Replacer<Inner, ?> child) {
this.child = child;
}
@SafeVarargs
public static <T> Replacer<T, T> compose(Replacer<T, T>... replacers) {
if (replacers.length == 0)
return new DummyReplacer<>();
else {
Replacer<T, T> current = replacers[0];
for (int i = 1; i < replacers.length; ++i) {
current.setChild(replacers[i]);
current = replacers[i];
}
return replacers[0];
}
}
}
class DummyReplacer<Outer> extends Replacer<Outer, Outer> {
public DummyReplacer(Replacer<Outer, ?> child) {
super(child);
}
public DummyReplacer() {
super(null);
}
@Override
protected Outer decompose(Outer something) {
return something;
}
@Override
protected Outer compose(Outer something) {
return something;
}
@Override
protected Outer inner_replace(Outer something) {
return something;
}
}
class Multiply extends Replacer<Integer, Integer> {
private int factor;
public Multiply(int factor, Replacer<Integer, ?> child) {
super(child);
this.factor = factor;
}
public Multiply(int factor) {
super(null);
this.factor = factor;
}
@Override
protected Integer decompose(Integer something) {
return something;
}
@Override
protected Integer compose(Integer something) {
return something;
}
@Override
protected Integer inner_replace(Integer something) {
return something * factor;
}
}
class Negate extends Replacer<String, Integer> {
public Negate(Replacer<Integer, ?> child) {
super(child);
}
public Negate() {
super(null);
}
@Override
protected Integer inner_replace(Integer something) {
return -something;
}
@Override
protected Integer decompose(String something) {
return Integer.parseInt(something);
}
@Override
protected String compose(Integer something) {
return something.toString();
}
}
class SharpToTildeExtract extends Replacer<String, String> {
public SharpToTildeExtract(Replacer<String, ?> child) {
super(child);
}
public SharpToTildeExtract() {
super(null);
}
@Override
protected String decompose(String something) {
return something.substring(1, something.length() - 1);
}
@Override
protected String compose(String something) {
return "~" + something + "~";
}
@Override
protected String inner_replace(String something) {
return something;
}
}
class UpperCaseReplacer extends Replacer<String, String> {
public UpperCaseReplacer(Replacer<String, ?> child) {
super(child);
}
public UpperCaseReplacer() {
super(null);
}
@Override
protected String decompose(String something) {
return something;
}
@Override
protected String compose(String something) {
return something;
}
@Override
protected String inner_replace(String something) {
return something.toUpperCase();
}
}
public class Main {
public static void main(String[] args) {
System.out.println(new SharpToTildeExtract().replace("#abc#"));
System.out.println(new SharpToTildeExtract(new UpperCaseReplacer()).replace("#abc#"));
System.out.println(Replacer.compose(new SharpToTildeExtract(), new UpperCaseReplacer()).replace("#abc#"));
System.out.println(new SharpToTildeExtract(new Negate(new Multiply(2))).replace("#5#"));
}
}
答案 2 :(得分:0)
ComposableReplacer
就是问题所在。
试试这个:
public abstract class Replacer< Outer, Inner > {
private static class DelegatingReplacer< Outer, Inner > {
private final Replacer< Outer, Inner > rplDelegate;
public DelegatingReplacer( Replacer< Outer, Inner > rplDelegate ) { this.rplDelegate = rplDelegate; }
@Override protected Inner decompose( Outer something ) { return rplDelegate.decompose( something ); }
@Override protected Outer compose( Inner something ) { return rplDelegate.compose( something ); }
@Override protected Inner inner_replace( Inner something ) { return rplDelegate.inner_replace( something ); }
}
protected abstract Inner decompose( Outer something );
protected abstract Outer compose( Inner something );
protected abstract Inner inner_replace( Inner something );
public final Outer replace( Outer something ) {
return compose( inner_replace( decompose( something ) ) );
}
public < Innerer > Replacer< Outer, Inner > chain( final Replacer< Inner, Innerer > rplChained ) {
return new DelegatingReplacer< Outer, Inner >( this ) {
@Override protected inner_replace( Inner something ) {
return rplChained.replace( super.inner_replace( something ) );
}
}
}
}
现在你可以做到
r1.chain( r2.chain( r3 ) ).replace( foo ); // for r1< O, I >, r2< I, J >, r3< J, K >
r1.chain( r2 ).chain( r3 ).replace( foo ); // for r1< O, I >, r2< I, J >, r3< I, K >
您不能指望Replacer
的异构数组以静态类型安全的方式组合。但是,如果所述阵列的构造被认为是静态类型安全的,那么这意味着您可以静态地确定元素的相互类型兼容性,并且可以如上所示构建您的链。
想要基于数组的方法的唯一原因是在运行时确定替换器(以及扩展名的类型)。所以你的问题(如何保证在运行时确定类型的数组的编译时类型安全性)似乎毫无意义。