class BaseKey implements Key {

    @Override
    public String toString() {

        final String typeName =
                Stream.of(getClass())
                        .map(Class::getInterfaces)
                        .flatMap(Stream::of)
                        .map(Class::getName)
                        .findFirst()
                        .get();

        // we use Object.hashCode to protect against accidentally printing/logging a value derived from the raw bytes
        // a side effect of this is 2 instances with the same underlying bytes will have different toString values
        return typeName + "@" + Integer.toHexString(super.hashCode());
    }

    protected  BaseKey(byte[] keyBytes);

}