我有两种方法,如下所示
private List<Long> getIds(String name, List<Cat> cats) {
List<Long> catIds = new ArrayList<>();
for (Cat cat : cats) {
if (cat.getName().equals(name)) catIds.add(cat.getId());
}
return catIds;
}
private List<Long> getIds(String name, List<Dog> dogs) {
List<Long> dogIds = new ArrayList<>();
for (Dog dog : dogs) {
if (dog.getName().equals(name)) dogIds.add(dog.getId());
}
return dogIds;
}
我的猫狗课程如下
public class Cat {
String name;
Long id;
// additional variables
// getters and setters
}
public class Dog {
String name;
Long id;
// additional variables
// getters and setters
}
为了避免冗余,我想将上述两种方法转换为单一的泛型方法。
我尝试了以下
private List<Long> getIds(String name, List<T> objects) {
List<Long> ids = new ArrayList<>();
for (T object : objects) {
if (object.getName().equals(name)) ids.add(object.getId());
}
return ids;
}
但它没有成功,因为它抱怨通用T没有getName
或getId
此处Cat
和Dog
是内置的java类。因此,我不能执行继承并为Animal
和name
作为数据变量的超级id
提供。
有没有办法在不实现继承的情况下完成合并上述两种方法?
答案 0 :(得分:4)
另一种可能性:如果您使用的是Java 8,则可以将名称和ID的getter方法作为附加参数传入方法。这是类型安全的,既不需要反思也不需要修改原始类。
private <T> List<Long> getIds(String name, List<T> objects, Function<T, String> getName, Function<T, Long> getId) {
List<Long> ids = new ArrayList<>();
for (T object : objects) {
if (getName.apply(object).equals(name)) {
ids.add(getId.apply(object));
}
}
return ids;
}
或更短,使用流:
private <T> List<Long> getIds(String name, List<T> objects, Function<T, String> getName, Function<T, Long> getId) {
return objects.stream().filter(o -> getName.apply(o).equals(name))
.map(getId).collect(Collectors.toList());
}
用法:
List<Long> ids = getIds("some name", listOfCats, Cat::getName, Cat::getId);
当然,虽然这种方法的 body 对于所有情况都是相同的,但您必须以不同的方式调用,具体取决于输入。为此,您可以提供一个入口方法,以适当的方式调用另一个方法,或者在类型错误的情况下引发异常。
private List<Long> getIds(String name, List<?> objects) {
if (objects.size() == 0) {
return Collections.emptyList();
}
if (objects.get(0) instanceof Cat) {
return getIds(name, (List<Cat>) objects, Cat::getName, Cat::getId);
}
if (objects.get(0) instanceof Dog) {
...
}
throw new IllegalArgumentException("List containing unsupported type!");
}
答案 1 :(得分:1)
您需要为PHP/Apache
和Cat
定义一个公共接口,例如Dog
。
您可以传递Animal
作为参数。
答案 2 :(得分:1)
你能为Dog和Cat制作一个界面吗?
interface animal {
...
Long getId();
}
public class Cat implements Animal
public class Dog implements Animal
那么你的方法就会变成
private List<Long> getIds(String name, List<Animal> animals) {
List<Long> ids = new ArrayList<>();
for (Animal animal : animals) {
ids.add(animal.getId());
}
return ids;
}
关于你提到的内置类,你可以将它们包装在另一个类中,并实现描述所需行为的接口(或超类)。
我曾经为log4j
和logback
事件对象提供相同的界面,它们两个肯定是完全不同的。
这里包装器去..
public abstract class EventWrapper {
public abstract String getFormattedMessage();
}
实际拥有内置类的子类
public class Log4jEvent extends EventWrapper {
LoggingEvent event;
public Log4jEvent(LoggingEvent event) {
this.event = event;
}
@Override
public String getFormattedMessage() {
if (event.getMessage() != null) {
return event.getMessage().toString();
} else {
return null;
}
}
}
LogbackEvent类与Log4jEvent类非常相似,而在代码的其他部分,有许多方法接收EventWrapper的参数类型。也许这种情况可以帮助您开发解决方案。
答案 3 :(得分:1)
好的,我知道你不能使用任何类型的继承。这是一个使用Reflection API的简短解决方案:
private static List<Long> getIds(String name, List<?> objects) {
List<Long> ids = new ArrayList<>();
for (Object object : objects) {
try {
Method getName = null;
Method getId = null;
for (Method method : object.getClass().getMethods()) {
if (method.getName().equals("getName") && method.getReturnType().equals(String.class) && method.getParameterTypes().length == 0) {
getName = method;
}
if (method.getName().equals("getId") && method.getReturnType().equals(Long.class) && method.getParameterTypes().length == 0) {
getId = method;
}
if (getName != null && getId != null && getName.invoke(object).equals(name)) {
ids.add((Long) getId.invoke(object));
break;
}
}
} catch (Exception e) {
System.out.println(e);
}
}
return ids;
}
答案 4 :(得分:0)
如果您无法更改Cat和Dog类,则应使用Reflection API。 否则使用接口Animal(或类型转换)
答案 5 :(得分:0)
我能想到的最简单的解决方案(保留继承)是检查对象是否为Dog或Cat类型。以下是该方法的代码: -
private List getIds(String name, List objects) {
List<Long> ids = new ArrayList<>();
for (Object obj : objects) {
if (obj instanceof Dog) {
Dog d = (Dog) obj;
if (d.getName().equals(name)) {
ids.add(d.getId());
}
} else if (obj instanceof Cat) {
Cat c = (Cat) obj;
if (c.getName().equals(name)) {
ids.add(c.getId());
}
}
}
return ids;
}
但它并没有使用泛型。
答案 6 :(得分:0)
如果在方法中有更多行是没问题的。那怎么样?
private List<Long> getIds(String name, List<?> objects) {
List<Long> ids = new ArrayList<Long>();
for (Object object : objects) {
if(object instanceof Dog){
Dog dog = (Dog) object;
if (dog.getName().equals(name))
ids.add(dog.getId());
} else if (object instanceof Cat){
Cat cat = (Cat) object;
if (cat.getName().equals(name))
ids.add(cat.getId());
}
}
return ids;
}
更通用的方法是:
private <T> List<Long> getIds(String name, List<T> objects, IdGetter<T> idGetter) {
List<Long> ids = new ArrayList<Long>();
for (T object : objects) {
Long id= idGetter.getId(object);
if(id != null){
ids.add(id);
}
}
return ids;
}
public interface IdGetter<T> {
Long getId(T object);
}