"Hello, Amigo! Today you're going to learn how to do something new: replace the System.out object."
System.out is a static PrintStream variable called out in the System class. This variable has the final modifier, so you simply assign it a new value. However, the System class has a special method to do this: setOut(PrintStream stream). And that's what we'll use.

"Interesting. And what will we replace it with?"

"We need some object that can collect the output data. ByteArrayOutputStream is best suited for this job. This is a special class that is a dynamic (resizable) array and implements the OutputStream interface."

"An adapter between an array and OutputStream?"

"Something like that. Here's what our code looks like."

Code
public static void main(String[] args) throws Exception
{
 //Save the current PrintStream in a special variable
 PrintStream consoleStream = System.out;

 //Create a dynamic array
 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 //Create an adapter for the PrintStream class
 PrintStream stream = new PrintStream(outputStream);
 //Set it as the current System.out
 System.setOut(stream);

 //Call a function that knows nothing about our changes
 printSomething();

 //Convert the data written to our ByteArray into a string
 String result = outputStream.toString();

 //Put everything back to the way it was
 System.setOut(consoleStream);
}

public static void printSomething()
{
 System.out.println("Hi");
 System.out.println("My name is Amigo");
 System.out.println("Bye-bye!");
}

"And what will we do with this line?"

"Well, whatever we want. For example, we would reverse it. Then the code would look like this:"

Code
public static void main(String[] args) throws Exception
{
 //Save the current PrintStream in a special variable
 PrintStream consoleStream = System.out;

 //Create a dynamic array
 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 //Create an adapter for the PrintStream class
 PrintStream stream = new PrintStream(outputStream);
 //Set it as the current System.out
 System.setOut(stream);

 //Call a function that knows nothing about our changes
 printSomething();

 //Convert the data written to our ByteArray into a string
 String result = outputStream.toString();

 //Put everything back to the way it was
 System.setOut(consoleStream);

 //Reverse the string
 StringBuilder stringBuilder = new StringBuilder(result);
 stringBuilder.reverse();
 String reverseString = stringBuilder.toString();

 //Output it to the console
 System.out.println(reverseString);
}

public static void printSomething()
{
 System.out.println("Hi");
 System.out.println("My name is Amigo");
 System.out.println("Bye-bye!");
}

"How interesting! Now I'm beginning to understand a little bit of the great capabilities these small classes provide."
"Thank you for the interesting lesson, Bilaabo."