@Override
  public final V get(char[] searchArr, int startOffset) {
    // there are existing children. binary search them to see if there are any with
    // matching prefixes
    int lower = 0;
    int upper = children.length - 1;
    char keyPrefixFirst = searchArr[startOffset];
    while (lower <= upper) {
      // pick the midpoint
      int mid = lower + (upper - lower) / 2;
      AbstractNode<V> childNode = children[mid];

      // common case: key and the child prefix will have zero chars in common
      char childPrefixFirst = childNode.getPrefixFirst();

      if (keyPrefixFirst < childPrefixFirst) {
        // not the right key. keep binary searching the next child.
        upper = mid - 1;
        continue;
      } else if (keyPrefixFirst > childPrefixFirst) {
        // not the right key. keep binary searching the next child.
        lower = mid + 1;
        continue;
      }

      // if we get here the, the first chars match, which is exciting. if the
      // rest of the strings don't match exactly, we don't have to explore any
      // further.

      // a quick check we can do is to see if this current child prefix is
      // longer than what's left in the search key, as that would guarantee a
      // non-match.
      // TODO: evaluate if this is actually beneficial
      final char[] childPrefix = childNode.getPrefix();
      if (childPrefix.length > searchArr.length - startOffset) {
        return null;
      }

      // now let's check if the next bit of searchArr matches the prefix. we
      // already checked the first char, so we can start with 1. note that this
      // will short-circuit itself right away if the child prefix is only 1
      // char.
      for (int i = 1; i < childPrefix.length; i++) {
        if (childPrefix[i] != searchArr[startOffset + i]) {
          return null;
        }
      }

      // if we reach this point, then we've got a child match. 
      // if there is no more searchArr left, then return the value we found.
      if (searchArr.length == childPrefix.length + startOffset) {
        return childNode.value;
      }

      // if there's more then we need to recurse.
      return childNode.get(searchArr, startOffset + childPrefix.length);
    }

    // didn't find a sub-match
    return null;
  }