接受一个类对象或另一个类对象的方法

时间:2016-03-16 09:34:46

标签: java

我有两种方法,如下所示

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没有getNamegetId

此处CatDog是内置的java类。因此,我不能执行继承并为Animalname作为数据变量的超级id提供。

有没有办法在不实现继承的情况下完成合并上述两种方法?

7 个答案:

答案 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/ApacheCat定义一个公共接口,例如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;
}

关于你提到的内置类,你可以将它们包装在另一个类中,并实现描述所需行为的接口(或超类)。

我曾经为log4jlogback事件对象提供相同的界面,它们两个肯定是完全不同的。

这里包装器去..

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);
}