The best way to do this for Java is to use the WebDriver interface (or even RemoteWebDriver class) to define the web driver object as a generic type.
WebDriver driver = new XYZDriver();
Where XYZ is the name of the specific browser you need to use. The image below shows the type hierarchy of the WebDriver interface for each supported browser.

I am not sure what the OP meant by "switch" browsers, but I assume what the OP meant was to have the ability to choose different browsers at the beginning of a session. Although each web driver concretion has different requirements to initialize a web driver instance, the general concept on how to do this is something like this:
public WebDriver initializeBrowser(string browserName) throws Exception {
WebDriver driver = null;
switch (browser.toLowerCase()) {
case "chrome":
driver = createChromeDriver();
break;
case "firefox":
driver = createFirefoxDriver();
break;
...
default:
throw new Exception("Unsupported browser: " + browserName);
}
return driver;
}
Each createXXXDriver should encapsulate the process of creating a driver instance, like setting the system properties for the driver location, setting any driver options needed (i.e. set headless mode, start maximized or minimized, etc.), and finally calling the related constructor.
I used this approach on a previous project and worked like a charm. In my particular case, I passed the browser name using a VM parameter (-Dbrowser=xxx). Doing so, allowed me to, not only to run my tests with different browsers on my local box, but also to configure my CI/CD environment (Jenkins) to run the exact job with different parameters; one of which was the browser I wanted to use for a particular test run.
import org.openqa.selenium.WebDriver;- Nathan Merrill