Automatic casting for instanceof
The Answer by Alex Rudenko is correct.
Java 16 simplifies that code, with the arrival of JEP 394: Pattern Matching for instanceof
. The downcast becomes automatic.
Since casting immediately after a call to instanceof
is so common:
if ( obj instanceof String ) {
String s = (String) obj; // grr...
...
}
… pattern matching technology now allows for implicit casting. Notice the introduction of a variable name within the if ( instanceof )
test.
if ( obj instanceof String s ) { // <-- Implicit downcast to a named variable.
// Let pattern matching do the work!
...
}
(By the way, your Questions
class should be named as singular rather than plural given your description: Question
.)
Using this feature, the code seen in that other Answer becomes:
for ( Question question : questions ) {
if ( question instanceof MultipleChoice q ) {
doSomething( q ) ;
} else if ( question instanceof FillInBlank q ) {
doSomething( q ) ;
} else {
System.out.println( "Unexpected class: " + question.getClass() ) ;
}
}
…
private void doSomething( MultipleChoice mc ) {
// do something
System.out.println( mc.getChoice() );
}
private void doSomething( FillInBlank fib ) {
// do something
System.out.println( fib.getFilledAnswer() );
}
Full example code
Here is a complete example to run, in a single file.
package com.work.demo.casting;
import java.util.List;
import java.util.UUID;
public class App2
{
public static void main ( String[] args )
{
App2 app = new App2();
app.demo();
}
private void demo ( )
{
List < Question > questions =
List.of(
new MultipleChoice() ,
new FillInBlank() ,
new FillInBlank()
);
//System.out.println( "questions = " + questions );
for ( Question question : questions )
{
if ( question instanceof MultipleChoice q )
{
doSomething( q );
} else if ( question instanceof FillInBlank q )
{
doSomething( q );
} else
{
System.out.println( "Unexpected class: " + question.getClass() );
}
}
}
private void doSomething ( MultipleChoice mc )
{
// … do something …
System.out.println( mc.getChoice() );
}
private void doSomething ( FillInBlank fib )
{
// … do something …
System.out.println( fib.getFilledAnswer() );
}
}
abstract class Question
{
public final UUID id = UUID.randomUUID();
@Override
public String toString ( ) { return "Question[id=" + id + "]"; }
}
final class MultipleChoice extends Question
{
public String getChoice ( ) { return "some choice response. ID: " + this.id; }
}
final class FillInBlank extends Question
{
public String getFilledAnswer ( ) { return "some filled answer response. ID: " + this.id; }
}
When run.
some choice response. ID: bf418995-2d33-47c8-8276-06442330337a
some filled answer response. ID: 3fef17a3-9f46-463f-8e80-5361df6089bc
some filled answer response. ID: 1f2cb1e0-6142-49f2-96b8-888ded1210db
Sealed classes
In the future, the upcoming sealed classes feature may help further simplify such code.