我正在一个项目中,我需要用新的ExpFoo替换旧的ExpFoo。
一个例子是给定一个ExpFoo((x * y)+(x * z)),我们有新的IntFoo 2,它将替换Varfoo x。我们有一个PlusFoo(a + b),它将替换Varfoo y。
所以结果将是:((2 *(a + b)+(2 * z))
这是它在Main类上的外观:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
ExpFoo e1 = new IntFoo(1);
ExpFoo e2 = new IntFoo(2);
ExpFoo e5 = new IntFoo(5);
ExpFoo x = new VarFoo("x");
ExpFoo plus = new PlusFoo(e1, e2);
ExpFoo times = new TimesFoo(e5, x);
ExpFoo bigTimes = new TimesFoo(plus, times);
ExpFoo[] exps = { e1, e2, e5, x, plus, times, bigTimes };
System.out.println(Arrays.toString(exps));
Replacement r = new Replacement();
r.put(new VarFoo("x"), new PlusFoo(e1, e5));
System.out.println(r);
for (ExpFoo exp : exps) {
System.out.println(exp + " has " + exp.numberOfNodes() + " nodes and after applying " + r + " the value " + exp.computeValue(r));
}
ExpFoo ex1 = new PlusFoo(new TimesFoo(new VarFoo("x"), new VarFoo("y")),new TimesFoo(new VarFoo("x"), new VarFoo("z")));
Replacement repl = new Replacement();
repl.put(new VarFoo("x"), new IntFoo(2));
repl.put(new VarFoo("y"), new PlusFoo(new VarFoo("a"), new VarFoo("b")));
ExpFoo ex2 = ex1.applyReplacement(repl);
System.out.println("ex1: " + ex1);
System.out.println("ex2: " + ex2);
}
}
我有两个问题:
对于第一个问题,我无法获得ExpFoo times = new TimesFoo(e5, x);
和
ExpFoo bigTimes = new TimesFoo(plus, times);
使用exp.computeValue(r)
,因为我无法确定如何计算1 + 5到6。
我所得到的只是一个异常,内容为: UnsupportedOperationException:如果没有替换就无法计算varfoo的值!
对于时间,它应返回为(5 * x)具有3个节点,并应用[x:=(1 + 5)]值30
对于bigTimes,它应返回为((1 + 2)*(5 * x))有7个节点,并且在应用[x:=(1 + 5)]值90
对于第二个问题,我遇到了一个问题
ExpFoo ex2 = ex1.applyReplacement(repl);
它返回一个异常 TimesExpFoo无法转换为com.company.VarFoo类,我无法使其正常工作。 它应返回为(((2 *(a + b)+(2 * z))
除“替换”之外,我不允许为所有类创建实例变量。
我也不能在所有类中使用泛型。
下面是它的工作方式说明,Replacement类在所有类中都是单独的。
对于课程,这是我到目前为止所做的。
Varfoo类:
import java.util.Set;
/**
* A VarFoo is a symbolic ExpFoo that stands for a value that has not yet
* been fixed. A VarFoo has a name of the format
* letter (letter | digit)^*
* (where '(letter | digit)^*' stands for 'a string of length 0 or more that
* contains only letters and digits').
* Here the class methods Character.isLetter(char) and
* Character.isLetterOrDigit(char) determine whether a character is
* a letter/a letter or a digit, respectively.
* Instances of this class are immutable.
*/
public class VarFoo implements ExpFoo {
/**
* Name of this VarFoo. Non-null, of the format
* <p>
* letter (letter | digit)*
*/
private String name;
/**
* Constructs a new VarFoo with the specified name.
*
* @param name must not be null; must be a String of the format letter
* (letter | digit)^*
*/
public VarFoo(String name) {
this.name = name;
}
@Override
public int numberOfNodes() {
return 1;
}
@Override
public int computeValue() {
throw new UnsupportedOperationException("Cannot compute the value of a varfoo without a replacement!");
}
@Override
public int computeValue(Replacement repl) {
//TODO;
}
@Override
public ExpFoo applyReplacement(Replacement s) {
//TODO
}
@Override
public boolean isVarFooFree() {
// TODO
return true;
}
@Override
public Set<VarFoo> getVarfoo() {
return null;
}
@Override
public void collectVarfoo(Set<VarFoo> vars) {
for (char c : name.toCharArray()) {
if (Character.isAlphabetic(c)){
vars.add(new VarFoo(name));
}
}
}
@Override
public String toString() {
return name;
}
/**
* The method returns true if o is an instance of class VarFoo
* whose name is equal to the name of this VarFoo; otherwise it
* returns false.
*
* @return whether this VarFoo and Object o are equal
*/
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof VarFoo))
return false;
if (o == this)
return true;
return name.equals(((VarFoo) o).name);
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
}
替换类:
import java.util.HashMap;
import java.util.Map;
/**
* A Replacement represents a mapping of finitely many VarFoo to
* ExpFoo. One can construct an empty Replacement, update a Replacement
* by adding/replacing/forgetting mappings of VarFoo to ExpFoo, and
* query Replacements for the value to which they map a varfoo, whether they
* have a mapping for a specific varfoo, and for a String representation.
*/
public class Replacement {
private Map<VarFoo, ExpFoo> replacementMap;
/**
* Constructs an empty Replacement (i.e., a Replacement that does not
* hold mappings for any varfoo(s).
*/
public Replacement() {
replacementMap = new HashMap<>();
}
/* Mutators */
/**
* Associates the specified ExpFoo with the specified Varfoo in this
* Replacement. If the Replacement previously contained a mapping for the
* Varfoo, the old ExpFoo is replaced.
*
* @param var the Varfoo with which exp is to be associated
* @param exp the ExpFoo to which var is to be mapped
* @return the ExpFoo to which var was mapped so far, or null if var did
* not yet have a mapping in this Replacement
* @throws NullPointerException if var or exp is null
*/
public ExpFoo put(VarFoo var, ExpFoo exp) {
return replacementMap.put(var, exp);
}
/**
* Forgets the mapping for the specified Varfoo. Does not modify this
* Replacement if it does not have a mapping for the specified Varfoo.
*
* @param var the Varfoo for which we want to forget the mapping
* @return whether a mapping for var was forgotten due to the method call
* @throws NullPointerException may be thrown if var is null
*/
public boolean forget(VarFoo var) {
if (var == null) {
return true;
}
else {
replacementMap.clear();
return true;
}
}
/* Accessors */
/**
* Returns the value to which the specified Varfoo is mapped, or null if
* this Replacement contains no mapping for the specified Varfoo.
*
* @param var the Varfoo for which we want the corresponding ExpFoo to
* which it is mapped
* @return the ExpFoo to which this Replacement maps var, or var if
* this Replacement does not have a mapping for var
* @throws NullPointerException may be thrown if var is null
*/
public ExpFoo get(VarFoo var) {
return replacementMap.get(var);
}
/**
* Returns whether this Replacement has an explicit mapping of var to an
* ExpFoo.
*
* @param var the Varfoo for which we want to know if this Replacement
* has a mapping
* @return whether this Replacement has an explicit mapping of var to an
* ExpFoo
* @throws NullPointerException may be thrown if the parameter is null
*/
public boolean hasMappingFor(VarFoo var) {
return replacementMap.containsValue(var);
}
@Override
public String toString() {
String s = "";
for (Map.Entry<VarFoo, ExpFoo> ReplacementKey : replacementMap.entrySet()) {
s = "[" + ReplacementKey.getKey() + ":=" + ReplacementKey.getValue() + "]";
}
return s;
}
}
ExpFoo类:
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Basic interface for arithmetic ExpFoo. Implementations are expected to
* be immutable, i.e., after object creation, the object's state cannot change,
* and there are no mutator methods in any class that implements this interface.
*/
public interface ExpFoo {
/**
* Computes the number of sub-ExpFoo of this ExpFoo (its "size").
*
* @return the number of nodes of this ExpFoo.
*/
int numberOfNodes();
/**
* Computes the int value represented by this ExpFoo object. This
* ExpFoo object must not contain Varfoos.
*
* @return the int value represented by this ExpFoo
*/
int computeValue();
/**
* Computes the int value represented by this ExpFoo.
*
* @param repl
* to be used to assign values to this ExpFoo; must not be
* null
* @return the int value represented by this ExpFoo
* @throws UnsupportedOperationException
* if the ExpFoo with repl applied to it still has
* Varfoo
* @throws NullPointerException
* if s is null
*/
default int computeValue(Replacement repl) {
ExpFoo specialised = applyReplacement(repl);
return specialised.computeValue();
}
/**
* Returns whether this ExpFoo is VarFoo-free, i.e., none of its
* direct or indirect sub-ExpFoo is a VarFoo object.
*
* @return whether this ExpFoo is VarFoo-free, i.e., none of its
* direct or indirect sub-ExpFoo is a VarFoo object.
*/
boolean isVarFooFree();
/**
* Returns the Set of Varfoo of this ExpFoo. The returned Set may be
* modified.
*
* @return the Set of Varfoo of this ExpFoo
*/
default Set<VarFoo> getVarfoo() {
Set<VarFoo> result = new LinkedHashSet<>();
collectVarfoo(result);
return result;
}
/**
* Adds all Varfoo in this ExpFoo to vars
*
* @param vars
* Varfoo will be added here; parameter must not be null
* @throws NullPointerException
* if vars is null
*/
void collectVarfoo(Set<VarFoo> vars);
/**
* Applies a Replacement to this ExpFoo and returns the result.
*
* @param r
* a Replacement to be applied to this ExpFoo; must not be
* null
* @return a version of this ExpFoo where all Varfoo have been
* replaced by the values stored in s for the Varfoo
* @throws NullPointerException
* if s is null
*/
ExpFoo applyReplacement(Replacement r);
}
BinaryFoo类:
import java.util.Set;
/**
* Abstract class for ExpFoos with two direct subExpFoos. Provides an
* implementation for numberOfNodes() method. Instances of this class are immutable.
*/
public abstract class BinaryFoo implements ExpFoo {
/** the left subExpFoo; non-null */
private ExpFoo left;
/** the right subExpFoo; non-null */
private ExpFoo right;
/** String representation of the operator symbol; non-null */
private String operatorSymbol;
/**
* Constructs a BinaryFoo with left and right as direct
* subExpFoo and with operatorSymbol as the String representation of
* the operator.
*
* @param left
* the left subExpFoo; non-null
* @param right
* the right subExpFoo; non-null
* @param operatorSymbol
* String representation of the operator symbol; non-null
*/
public BinaryFoo(ExpFoo left, ExpFoo right,
String operatorSymbol) {
if (left == null) {
throw new NullPointerException("Illegal null value for left!");
}
if (right == null) {
throw new NullPointerException("Illegal null value for right!");
}
if (operatorSymbol == null) {
throw new NullPointerException(
"Illegal null value for operatorSymbol!");
}
this.left = left;
this.right = right;
this.operatorSymbol = operatorSymbol;
}
/**
* Getter for the left subExpFoo.
*
* @return the left subExpFoo
*/
public ExpFoo getLeft() {
return left;
}
/**
* Getter for the right subExpFoo.
*
* @return the right subExpFoo
*/
public ExpFoo getRight() {
return right;
}
/**
* Getter for the operator symbol.
*
* @return the operator symbol
*/
public String getOperatorSymbol() {
return operatorSymbol;
}
@Override
public int numberOfNodes() {
return 1 + left.numberOfNodes() + right.numberOfNodes();
}
@Override
public void collectVariables(Set<VarFoo> vars) {
vars.add((VarFoo)left);
vars.add((VarFoo)right);
}
@Override
public boolean isVarFooFree() {
// TODO
return false;
}
@Override
public String toString() {
return "(" + left + " " + operatorSymbol + " " + right + ")";
}
@Override
public boolean equals(Object o) {
if (!(o instanceof BinaryFoo)) {
return false;
}
BinaryFoo other = (BinaryFoo) o;
// relies on instance variables being non-null
return operatorSymbol.equals(other.operatorSymbol)
&& left.equals(other.left) && right.equals(other.right);
}
@Override
public int hashCode() {
int result = (left == null) ? 0 : left.hashCode();
result += (right == null) ? 0 : right.hashCode();
return result;
}
}
TimesFoo类:
/**
* Represents an ExpFoo of the form e1 * e2.
* Instances of this class are immutable.
*/
public class TimesFoo extends BinaryFoo {
/**
* Constructs a TimesFoo with left and right as direct
* subExpFoo.
*/
public TimesFoo(ExpFoo left, ExpFoo right) {
super(left, right, "*");
}
@Override
public int computeValue() {
return getLeft().computeValue() * getRight().computeValue();
}
@Override
public int computeValue(Replacement subst) {
return computeValue();
}
@Override
public ExpFoo applyReplacement(Replacement r) {
ExpFoo e = s.get((VarFoo)getVarFoo());
return e;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof TimesFoo)) {
return false;
}
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
}
PlusFoo类:
/**
* Represents an ExpFoo of the form e1 + e2.
* Instances of this class are immutable.
*/
public class PlusFoo extends BinaryFoo {
/**
* Constructs a PlusFoo with left and right as direct subExpFoos.
*
* @param left the left subExpFoo; non-null
* @param right the right subExpFoo; non-null
*/
public PlusFoo(ExpFoo left, ExpFoo right) {
super(left, right, "+");
}
@Override
public int computeValue() {
return getLeft().computeValue() + getRight().computeValue();
}
@Override
public ExpFoo applyReplacement(Replacement r) {
ExpFoo e = s.get((VarFoo)getVarFoo());
return e;
}
@Override
public int computeValue(Replacement repl) {
return computeValue();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof PlusFoo)) {
return false;
}
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
}
IntFoo类:
import java.util.Objects;
import java.util.Set;
/**
* ExpFoo that represents an int value.
*/
public class IntFoo implements ExpFoo {
/**
* Stores the encapsulated value.
*/
private int value;
/**
* Constructs a new IntFoo encapsulating value.
*
* @param value to be encapsulated in this IntFoo
*/
public IntFoo(int value) {
this.value = value;
}
/**
* @return the int value this IntFoo stands for
*/
public int getValue() {
return value;
}
@Override
public int numberOfNodes() {
return 1;
}
@Override
public int computeValue(Replacement repl) {
return computeValue();
}
@Override
public int computeValue() {
return value;
}
@Override
public ExpFoo applyReplacement(Replacement r) {
VarFoo var = new Variable(name); //error
ExpFoo e = s.get(var);
return e;
}
@Override
public boolean isVarFooFree() {
// TODO
return false;
}
@Override
public Set<VarFoo> getVarfoo() {
return null;
}
@Override
public void collectVarfoo(Set<VarFoo> vars) {
}
@Override
public String toString() {
return "" + value;
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof IntFoo))
return false;
if (o == this)
return true;
return value == (((IntFoo) o).value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
答案 0 :(得分:0)
第一个问题
我无法获取时间和bigTimes的值。
根本原因在TimesFoo#computeValue
@Override
public int computeValue(Replacement subst) {
return computeValue();
}
您将完全忽略该方法subst
中的替换参数,而仅调用computeValue()
,因此您的变量将永远无法解析,因此错误为UnsupportedOperationException: Cannot compute the value of a varfoo without a replacement!
第二个
我无法使用applyReplacement(repl)。
根本原因在PlusFoo#applyReplacement
@Override
public ExpFoo applyReplacement(Replacement r) {
return null;
}
您刚刚返回null
,这就是您得到的。您需要将替换递归地应用于子表达式
答案 1 :(得分:0)
此示例仅是一个玩具,在某些区域还不完整。但是它说明了动态加载以前尚未编译到应用程序中的类的强大功能。
try {
Class<?> clas = getClass().getClassLoader()
.loadClass(
"junk.keep.streamsandLambdas.MyMethods");
Object myMethods = clas.getConstructor()
.newInstance();
Method[] methods = myMethods.getClass()
.getDeclaredMethods();
System.out.println("Available methods:");
for (Method m : methods) {
System.out.println(" " + m.getName());
}
Method m = myMethods.getClass().getMethod("expFoo", int.class,
int.class, int.class);
System.out.println("\nInvoking " + m.getName());
int v = (int) m.invoke(myMethods, 10,20,30);
System.out.println(v);
} catch (Exception cnf) {
cnf.printStackTrace();
}
现在将以下已编译的类放在与其他类相同的包和位置中。
package your.package.name;
public class MyMethods {
public int expFoo(int x, int y, int z) {
return (x*y) + (x * z);
}
public int plusFoo(int a, int b) {
return a + b;
}
}
您可以更改MyMethods
的内容并重新编译而无需更改主应用程序。使用类加载器和反射还有很多其他功能。您可以在自己的位置创建特殊的类,并定义自己的类加载器以加载它们。我不知道这是否可以帮助您满足当前的要求,但是仍然值得了解。