I have a list of implementations to SomeInterface
List<SomeInterface> listOfThingsThatImplementsSomeInterface
I want to extract a specific implementation from the list according to its class name
private SomeInterface getThisType(SomeInterfaceImpl myType) {
SomeInterfaceImpl impl = null
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (current instanceof myType) {
impl = current
break;
}
}
return impl;
}
Is that possible in Java? should I be using generics?
CodePudding user response:
First you need the Class
instance of the desired class (which you have, you mention "according to its class name"). You can get a Class
instance from the class name using
Class<?> cls = SomeInterfaceImpl.class;
or if you have the class name as a String:
Class<?> cls = Class.forName("package.ClassName")
or from an instance using
SomeInterfaceImpl myType = ...;
Class<?> cls = myType.getClass()
Then you can call this method, assuming your have a List<SomeInterface> listOfThingsThatImplementsSomeInterface
somewhere:
private SomeInterface getThisType(Class<?> myType) {
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (myType.isInstance(current)) {
return current;
}
}
return null; //nothing found
}
CodePudding user response:
The method should take the class as parameter. Let's say your interface is T
, you can receive a parameter of type Class<? extends T>
Then go through the list and check for an element with the same class
Here is an example that should work:
private static <T> Optional<T> getThisType(
List<T> listOfThingsThatImplementsInterfaceT,
Class<? extends T> klass) {
return listOfThingsThatImplementsInterfaceT.stream()
.filter(klass::isInstance)
.findFirst();
}
Test with a list of Serializable
List<Serializable> listOfThingsThatImplementsSerializable = Arrays.asList(
new Integer(1), new Float(2), new Double(3)
);
System.out.println(
getThisType(listOfThingsThatImplementsSerializable, Float.class)
);
Looking for the Float
returns Optional[2.0]
CodePudding user response:
Suppose we have the desired implementation Class
instance, (refer to @f1sh answer if the class is Class<?>
), it can be done using Stream,
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
The key to match the type is using Class#isInstance
.
Some points to note:
- Make method return type generic so no cast is needed.
Class#cast
can be used to convert the return type of the Stream.- Use
Optional
to handle case when no element matched.
Full example
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class FilterByClass {
List<SomeInterface> someInterfaceList = new ArrayList<>();
public static void main(String[] args) {
FilterByClass filterByClass = new FilterByClass();
filterByClass.someInterfaceList = List.of(new SomeInterfaceImplA(), new SomeInterfaceImplB(), new SomeInterfaceImplC());
System.out.println(filterByClass.getThisType(SomeInterfaceImplA.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplB.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplC.class).get().name());
}
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
public interface SomeInterface {
default String name() {
return this.getClass().getSimpleName();
}
}
public static class SomeInterfaceImplA implements SomeInterface { }
public static class SomeInterfaceImplB implements SomeInterface { }
public static class SomeInterfaceImplC implements SomeInterface { }
}