How do you optimize memory usage when manipulating large strings in Java, and explain the difference between String, StringBuilder, and StringBuffer?