在没有实例变量和泛型的情况下如何实现方法

时间:2020-01-10 15:02:22

标签: java

我正在一个项目中,我需要用新的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);

}
}

我有两个问题:

  1. 我无法获取时间和bigTimes的值。
  2. 我无法使用applyReplacement(repl)。

对于第一个问题,我无法获得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类在所有类中都是单独的。

UML image here

对于课程,这是我到目前为止所做的。

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);
}
}

2 个答案:

答案 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的内容并重新编译而无需更改主应用程序。使用类加载器和反射还有很多其他功能。您可以在自己的位置创建特殊的类,并定义自己的类加载器以加载它们。我不知道这是否可以帮助您满足当前的要求,但是仍然值得了解。

相关问题