如何在实现接口但不扩展另一个类的Java类中引用超级方法?
我有几个Java类,它们扩展了通用列表接口的各种实现。他们只需记录添加到列表中的任何内容 LogginArrayList如下所示。顾名思义,它扩展了ArrayList。LoggingLinkedList类除了扩展LinkedList之外是相同的 我的主要目标是避免为了使用不同的基类而复制所有的公共代码。我正在尽可能地坚持干燥原则(不要重复你自己) 首先,请不要建议更好的登录方式。那根本不是我真正的申请。这只是演示我遇到的问题的一种简单方法 我有两个密切相关的问题。第一个问题是标题中的问题。如何在实现接口但不扩展另一个类的Java类中引用“super”方法 如下所示的LoggingArrayList类工作正常,但当我将类声明从…extends ArrayList更改为…implements List时,对super.method()的三个引用将不再可调用,因此我提出了第一个问题 对我的第二个问题的好回答几乎会使第一个问题变得毫无意义。第二个问题是:有没有一种方法可以声明一个抽象基类或一个接口,该接口使用各种add()方法的默认实现来扩展List,这样我就可以简单地扩展该抽象基类或实现该接口,并且只指定哪种类型的List将作为具体类的基础 例如,我想这样做:如何在实现接口但不扩展另一个类的Java类中引用超级方法?,java,generics,inheritance,design-patterns,generic-collections,Java,Generics,Inheritance,Design Patterns,Generic Collections,我有几个Java类,它们扩展了通用列表接口的各种实现。他们只需记录添加到列表中的任何内容 LogginArrayList如下所示。顾名思义,它扩展了ArrayList。LoggingLinkedList类除了扩展LinkedList之外是相同的 我的主要目标是避免为了使用不同的基类而复制所有的公共代码。我正在尽可能地坚持干燥原则(不要重复你自己) 首先,请不要建议更好的登录方式。那根本不是我真正的申请。这只是演示我遇到的问题的一种简单方法 我有两个密切相关的问题。第一个问题是标题中的问题。如何在
interface LoggingList<T extends Object, L extends List<T>> extends L
{
// overloaded methods go here as shown below
// with overloaded methods declared as default for the interface
}
接口日志列表扩展了L
{
//重载方法如下所示
//将重载方法声明为接口的默认方法
}
…然后,我可以简单地为列表的每个具体实现实现一次LoggingList,而无需复制所有公共代码。具体的类可能看起来像这样,在它们的花括号中不需要额外的代码:
public class LoggingArrayList<T extends Object> implements LoggingList<T, ArrayList<T>> {}
public class LoggingLinkedList<T extends Object> implements LoggingList<T, LinkedList<T>> {}
公共类LoggingArrayList实现LoggingList{}
公共类LoggingLinkedList实现LoggingList{}
问题是,我提出的接口定义是无效的(不会编译),而且,下面代码中对super.method的引用也不可用,除非我将LoggingList设置为抽象子类而不是接口,然后我就回到了现在的位置
提前感谢你提出的关于如何实现我的目标的想法
这是我的整个LoggingArrayList课程
public abstract class LoggingArrayList<T extends Object>
extends ArrayList<T>
{
protected void log(T e)
{
System.out.println(e == null ? "null" : e.toString());
}
@Override
public boolean add(T e) {
log(e);
// How do I reference a super.method()
// in a class that implements an interface
// but does not extend another class?
return super.add(e);
}
@Override
public boolean addAll(Collection<? extends T> clctn) {
boolean anyChanges = false;
for(T e : clctn)
{
// ensure that we call our overridden version of add()
// so it gets logged.
anyChanges = anyChanges || add(e);
}
return anyChanges;
}
@Override
public boolean addAll(int i, Collection<? extends T> clctn) {
for(T e : clctn)
{
// ensure that we call our overridden version of add()
// so it gets logged.
add(i, e);
i++; // keep the inserted elements in their original order
}
return !clctn.isEmpty();
}
@Override
public T set(int i, T e) {
log(e);
// How do I reference a super.method()
// in a class that implements an interface
// but does not extend another class?
return super.set(i, e);
}
@Override
public void add(int i, T e) {
log(e);
// How do I reference a super.method()
// in a class that implements an interface
// but does not extend another class?
super.add(i, e);
}
}
公共抽象类LoggingArrayList
扩展ArrayList
{
受保护的无效日志(TE)
{
System.out.println(e==null?“null”:e.toString());
}
@凌驾
公共布尔加法(TE){
日志(e);
//如何引用super.method()
//在实现接口的类中
//但是不扩展另一个类吗?
返回super.add(e);
}
@凌驾
public boolean addAll(Collection完成此操作的一种方法是:委托
不必为不同类型的列表提供多个实现,您可以只使用一个
public class LoggingList<T extends Object> implements List<T>
protected List<T> superList;
public LoggingList(List<T> anotherList) {
superList= anotherList;
}
protected void log(T e) {
System.out.println(e == null ? "null" : e.toString());
}
@Override
public boolean add(T e) {
log(e);
return superList.add(e);
}
public类LoggingList实现列表
受保护列表超级列表;
公共日志列表(另一个列表){
超级列表=另一个列表;
}
受保护的无效日志(TE){
System.out.println(e==null?“null”:e.toString());
}
@凌驾
公共布尔加法(TE){
日志(e);
返回超级列表。添加(e);
}
然后,您可以调用超级列表,而不是调用超级列表。
您仍然需要将构造函数从new LoggingLinkedList()
调整为new LoggingList(new LinkedList());
-但这应该没什么大不了的…您可以使用它。只需谷歌“如何使用jdk代理类”
仅供将来参考,下面是我使用Sergey Morozov建议的代理方法编写的一个完整的工作解决方案。它的核心代码不到50行。最后包含的一半以上的代码只是对实际功能的单元测试
我还不确定我是否会最终将这种方法用于我的目的,但这是一个非常有用的练习。谢谢你的建议,谢尔盖
public class LoggingListProxyFactory
{
protected static void log(String methodName, Object element)
{
System.out.println(methodName
+ ": ["
+ (element == null ? "null" : element.toString())
+ "]"
);
}
public static <T extends Object> List<T> getProxy(final List<T> list) {
return (List<T>) Proxy.newProxyInstance(
list.getClass().getClassLoader(),
new Class[]{ List.class },
new LoggingInvocationHandler(list)
);
}
private static class LoggingInvocationHandler<T>
implements InvocationHandler
{
final List<T> underlyingList;
public LoggingInvocationHandler(List<T> list) {
this.underlyingList = list;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
// These are the List interface methods that we want to log.
// In every case, the new elements happen to be the last parameter.
//
// boolean add(Object e)
// void add(int index, Object element)
// boolean addAll(Collection c)
// boolean addAll(int index, Collection c)
// Object set(int index, Object element)
String methodName = method.getName();
if( ( "add".equals(methodName)
| "addAll".equals(methodName)
| "set".equals(methodName)
)
// a few additional probably unnecessary checks
&& args != null
&& args.length == method.getParameterCount()
&& method.getParameterCount() > 0
)
{
log(methodName, args[args.length-1]);
}
return method.invoke(underlyingList, args);
}
}
public void testGetProxy() {
List<String>[] testLists = new List[] {
new ArrayList<>(),
new LinkedList<>()
};
for(List<String> aList : testLists)
{
List<String> proxy = LoggingListProxyFactory.getProxy(aList);
// aList.add(42); // type is enforced at compile time
aList.add(aList.getClass().getSimpleName());
aList.add("unlogged");
aList.add(null);
// proxy.add(42); // type is enforced at compile time
proxy.add(proxy.getClass().getSimpleName());
// exercise each the methods that are being logged
proxy.add("foo");
proxy.add(0, "bar");
proxy.add(null);
proxy.addAll(aList);
proxy.addAll(7, aList);
proxy.set(5, "five");
System.out.println();
System.out.println(aList.getClass().getSimpleName()
+ ".size() = " + aList.size());
aList.stream().forEach(System.out::println);
System.out.println();
System.out.println("proxy.size() = " + proxy.size());
proxy.stream().forEach(System.out::println);
}
}
}
公共类LoggingListProxyFactory
{
受保护的静态无效日志(String methodName,Object元素)
{
System.out.println(methodName
+ ": ["
+(element==null?“null”:element.toString()
+ "]"
);
}
公共静态列表getProxy(最终列表){
返回(列表)Proxy.newProxyInstance(
list.getClass().getClassLoader(),
新类[]{List.Class},
新的LoggingInvocationHandler(列表)
);
}
私有静态类LoggingInvocationHandler
实现调用处理程序
{
最终清单,参考清单;
公共日志处理程序(列表){
this.underyinglist=列表;
}
@凌驾
公共对象调用(对象代理、方法、对象[]参数)
扔掉的
{
//这些是我们要记录的列表接口方法。
//在任何情况下,新元素都恰好是最后一个参数。
//
//布尔加法(对象e)
//void add(int索引,对象元素)
//布尔addAll(集合c)
//布尔addAll(整数索引,集合c)
//对象集(int索引,对象元素)
String methodName=method.getName();
if((“add“.equals(methodName))
|“addAll”.equals(方法名)
|“set”.equals(方法名)
)
//a