【问题标题】:Call implemented interface overriden method from a class从类调用实现的接口覆盖方法
【发布时间】:2014-11-20 19:13:29
【问题描述】:

我开始用 Java 做一些高级的事情(对我来说是高级 xD)。

我有这个:

interface ResultSet {
    public void close();
}

class DbResult {
    ResultSet data;
    Statement statement;

    public void close() {
        this.data.close();
        this.statement.close();
    }
}

我试过这样做:

interface ResultSet { //I think that is abstract or something
    public void close();
}

abstract class DbResult implements ResultSet {
    Statement statement;

    @Override
    public void close() {
        super.close();
        this.statement.close();
    }
}

显然它不起作用,因为 ResultSet 不是超类。我也尝试让 DbResult 成为一个接口并扩展 ResultSet 但它告诉我接口方法不能有一个主体,所以我不知道该怎么做。

我正在尝试这样做,以便我可以关闭结果语句,结果只有一个变量而不是 2 个,因此不太容易因忘记关闭语句而发生内存泄漏。

Database 类以这种方式查询数据库:

class Database {
    private Connection connection;

    /* Here a constructor that
       inits the connection and such things */

    public DbResult query(String q) {
        Statement statement = this.connection.createStatement();
        DbResult result = (DbResult)statement.executeQuery(q);
        result.statement = statement;
        return result;
    }

编辑: 好的,既然我知道我不能,我想知道我是否可以以一种骇人听闻的形式做到这一点,但我:

有没有办法检查一个类中是否调用了一个不存在的方法,捕获它并在另一个变量中调用该方法名?

例如,ResultSet 有一个名为 getString() 的方法。我想知道是否可以调用DbResult.getString("blah");DbResult 会将该方法重定向到this.data,但无需在DbResult 类中实现getString 方法。

我想知道是否可能,因为ResultSet 中有大量函数,并且调用DbResult.data.METHOD 不如DbResult.METHOD 优雅。

【问题讨论】:

  • 解决方法很简单:不要尝试调用不存在的超级方法。话虽如此,为了获得更好更完整的答案,您可能需要提供更多上下文——您为什么要尝试调用一开始不存在的已实现接口的超级方法?
  • 答案已编辑。您的修改一切都发生了巨大变化。

标签: java class inheritance interface


【解决方案1】:

也许您要使用的是抽象类而不是接口,例如:

interface A2 {
   void foo();    
   void otherAbstractMethod();
}

abstract class AbstractA2 implements A2 {
  @Override // implemented metthod
  public void foo() {
     System.out.println("From the default method");
  }

  @Override //unimplemented abstract method
  public abstract void otherAbstractMethod();
}

class B2 extends AbstractA2 {

   @Override
   public void foo() {
       super.foo();
       System.out.println("From the override");
   }

   @Override
   public void otherAbstractMethod() {
      // TODO add some code      

      // the line below won't compile
      // super.otherAbstractMethod();  
   }
}

并进行测试

public class TestA {
   public static void main(String[] args) {
      A2 myA = new B2();
      myA.foo();
   }
}

编辑
关于你的问题的变化,它改变了一切,而且剧烈地改变了,我(再次)感到困惑。 ResultSet 你的接口,还是你试图实现 java.sql.ResultSet?如果是后者,您的代码将充满困难,因为您的类无法扩展,也无法替代查询返回的 ResultSet 的实际类型。我看不到您使用组合和 not 继承的任何替代品。换句话说,继续你最初的工作——创建包含 ResultSet 字段但不实现接口的类。

请注意,如果您使用Decorator Pattern,则可以实现 ResultSet。有了这个,您将创建自己的类,它是原始类型的“包装器”,它要求您使用组合继承,并创建所有需要的接口的方法,然后将它们委托给 ResultSet 组件。

例如,ResultSet 有一个名为 getString() 的方法。我想知道是否可以调用 DbResult.getString("blah"); DbResult 会将该方法重定向到 this.data,但不会在 DbResult 类中实现 getString 方法。

不,您必须在子装饰器类中实现所有这些方法。

【讨论】:

  • 好的,这就是为什么我在 Internet 上找不到任何关于此的内容。我花了很多时间xD谢谢!
  • @JorgeFuentesGonzález:除最后一段外,我的整个答案已因您原始帖子的编辑而无效。这是我试图回答一个不完整的问题的错——吸取的教训。最后一段在这里很重要。
  • @JorgeFuentesGonzález:Decorator 设计模式实际上非常优雅,它是 Java 实现其所有 Streams 的方式。也许这是您应该考虑使用的。
  • 完美,我明白了。刚刚搜索了装饰器模式,它做了我想要的强制转换,只是方法实现失败了,但我想我不能用编程语言问魔法xD你很有帮助,再次感谢。
  • @JorgeFuentesGonzález:不客气,很高兴你能继续前进!
【解决方案2】:

猜猜看:它已经是 Java 的一部分了(从版本 7 开始):

Java API Documentation: java.lang.AutoCloseable

public interface AutoCloseable {
   void close();
}

ResultSetStatement(和许多其他类)已经实现了这个接口。 最棒的是:在 try 语句中由 try 管理的资源是 automatically closed, if they implement this interface

【讨论】:

  • AutoCloseable,很好。我不接受这个作为答案,因为不回答一般问题“从一个类调用实现的接口覆盖方法”,但我会赞成它。谢谢!
  • 单独添加了您的问题的答案
【解决方案3】:

有没有办法检查一个不存在的方法是否被调用 在一个类中,捕获它并在另一个变量中调用该方法名称?

因此,您希望包装对实例的调用,而不必扩展它或实现其每个方法,这实际上是可能的,但仅适用于通过接口公开的方法。 好消息是ResultSet 实际上是一个接口。

这可以通过动态代理来完成(参见ProxyInvocationHandler)。

您可以创建一个由 InvocationHandler 支持的 Proxy,该 ResultSet 包装了 ResultSet。对您的代理实例的任何调用都将委托给 InvocationHandler,它可以直接处理它们,或者在您的情况下,将它们委托给包装的实际 ResultSet 实例。

public class MyResultSetInvocationHandler implements InvocationHandler {

    private final ResultSet wrappedResultSet;

    private MyResultSetInvocationHandler(ResultSet resultSet) {
        wrappedResultSet = resultSet;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        try {
            // call method on delegate
            Object result = method.invoke(wrappedResultSet, args);

            // optionally do something with the result, and return it afterwards
            return result;
        }
        catch (Throwable ex) {
            // handle exception, or rethrow it
            throw ex;
        }
    }

    /**
     * Factory method, creates a dynamic proxy wrapping the given result set.
     */
    public static ResultSet wrap(ResultSet delegate) {
        MyResultSetInvocationHandler handler = new MyResultSetInvocationHandler(delegate);
        return (ResultSet) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] { ResultSet.class }, handler);
    }
}

用法:

// the actual result set
ResultSet resultSet = ...

// and your wrapped proxy/handler as a surrogate
resultSet = MyResultSetInvocationHandler.wrap(resultSet);

【讨论】:

  • 看起来很酷。我怎么知道被调用的方法是resultSet.close() 是否也关闭了Statement
  • 通过检查方法参数的名称: if (method.getName().equals("close")) { ... }
  • 很好。我不会使用它,因为它似乎更消耗资源(每次调用方法时检查是否调用关闭)但它完全符合我的问题。
猜你喜欢
  • 2022-01-01
  • 2011-11-03
  • 1970-01-01
  • 2012-12-04
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 2011-08-04
相关资源
最近更新 更多