Implementing equals(), hashCode(), toString() in the hierarchy like the Optional from Guava I have simple hierarchy which looks [a little bit] like the Optional&lt;?&gt; from Guava:

public abstract class Result&lt;T&gt; {

    public static &lt;ResultType&gt; Result&lt;ResultType&gt; get(ResultType result) {
        return new PresentResult(result);
    }

    public static Result&lt;?&gt; absent(Throwable exception) {
        return new AbsentResult(exception);
    }

    Result() {
        // clients of the package can't extend this class
    }

    public abstract boolean isPresent();
    public abstract T get();
    public abstract Throwable getException();
}


class PresentResult&lt;T&gt; extends Result&lt;T&gt; {

    private final T result;

    public PresentResult(T result) {
        this.result = result;
    }

    @Override
    public boolean isPresent() {
        return true;
    }

    @Override
    public T get() {
        return result;
    }

    @Override
    public Throwable getException() {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof PresentResult)) {
            return false;
        }
        PresentResult&lt;?&gt; other = (PresentResult&lt;?&gt;) obj;
        return Objects.equal(get(), other.get());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(get());
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("result", get())
                .toString();
    }
}


class AbsentResult extends Result {

    private final Throwable exception;

    public AbsentResult(Throwable exception) {
        this.exception = exception;
    }

    @Override
    public boolean isPresent() {
        return false;
    }

    @Override
    public Object get() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Throwable getException() {
        return exception;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof AbsentResult)) {
            return false;
        }
        AbsentResult other = (AbsentResult) obj;
        return Objects.equal(getException(), other.getException());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getException());
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("exception", getException())
                .toString();
    }
}


But I'm not sure whether I implemented the methods equals(), hashCode(), toString() correctly.

What do you think about them?
Some remarks:


Why does getException() return a Throwable instead of an Exception? Or even better, a RuntimeException? More generally, what is the purpose of this method? If I were you I'd "drop" it and make .get() throw the wanted exception instead. Since the exception would be a RuntimeException, there would be no need to declare it.
Is it on purpose that PresentResult and AbsentResult are not final? What do you expect further subclasses to extend if anything?
Is it legal to initialize a PresentResult with a null value, an AbsentResult with a null exception?