即使没有指定任何接口,也要针对接口编译Java类

时间:2009-11-06 23:03:05

标签: java oop interface

我正在教授编程课程的介绍,我们正在使用Java。我想帮助学生学习如何将书面课程规范翻译成工作程序。我会提供书面说明。它以方法签名的形式指定类的名称和行为。我希望学生将其转换为可用的Java类。

我可以为他们提供一个接口并让他们实现接口,但这会破坏部分目的:阅读和解释书面功能规范文档。我希望他们从头开始编写课程。然后我想评估他们的工作。

我检查他们工作的想法是这样的:根据我自己的界面编译他们的Java类文件。如果它编译,那么至少我会知道他们已经遵循了所有方法合同,我可以开始测试功能。如果它没有编译,我将收到一条错误消息,报告哪些方法没有正确实现。

即使源代码中最初未指定Java类文件,如何强制针对接口编译Java类文件?

换句话说,假设我有以下两个文件:

FooInterface.java

public interface FooInterface
{
    ...
}

Foo.java

public class Foo
{
    ...
}

我想编译Foo,就像它明确地实现了FooInterface一样。但我不想手动编辑一堆源代码文件才能这样做。我该怎么办?

修改

要解决有关使用书面规范与提供界面的价值的问题,这是假设的规范文档的样子:

  

使用以下方法编写一个名为Foo的类:

     

最旧:年龄(int []) - > INT
  鉴于一系列年龄,返回最高的一个。

     

anyAdults:ages(int []) - >布尔
  考虑到一系列年龄,无论他们中的任何一个是18岁还是年龄,都要回归。

IMO,这有很大的教育益处。学生必须批判性地评估他们的课程是否符合规范。如果我提供了接口文件,他们可以拔掉他们的大脑并让编译器告诉他们他们是否遵循规范。使用编译器作为认知拐杖是与较差的学生目前(不成功)用来平衡他们的牙套和括号的技术。

17 个答案:

答案 0 :(得分:11)

你仍然可以让Foo实现FooInterface但只是给你的学生一个空的FooInterface。编译学生时,Foo使用实际的FooInterface。

答案 1 :(得分:11)

你可能会做类似的事情:

public class Bar extends Foo implements FooInterface{}

如果Foo完全满足FooInterface,则Bar不会有任何错误。

答案 2 :(得分:4)

除了在Murali建议编译学生代码时提供完整的界面,我建议您还实施单元测试套件,以使您的评分更顺利。除了测试已满足书面规范的方法合同之外,您还可以测试每种方法是否正常工作。

答案 3 :(得分:3)

我不知道这是否是最优雅的方式,但您的评分程序可以使用反射来加载学生类并查找具有给定名称的方法 - 如果它没有这样的方法,你可以扣除你想要的任何积分。如果该方法确实存在,那么您也可以使用反射调用它,传入您喜欢的任何参数。

Sun在这里有一个相当不错的教程:

http://java.sun.com/docs/books/tutorial/reflect/member/index.html

请参阅有关获取方法信息和调用方法的部分。

标记社区 - 其他人请随时提供更正等。

答案 4 :(得分:3)

根据你的编辑:

您无法使其与现有界面匹配。您必须手动执行此操作,方法是使用reflection查看方法名称。

此代码应该让您知道该类是否实现了规范:

 String studentClassName = args[0];
 Class class = Class.forName( studentClassName );

 Methods [] methods = class.getMethods();

 for( Method m : methods ) {
    if( matchTheSpecs( method ) ){
       markAsAccepted( method.getName() );
    }
 }

matchTheSpecs方法将验证

 method.getName()
 method.getParameterTypes()
 method.getReturnType()

所以,这个:

oldest : ages (int[]) -> int
anyAdults : ages (int[]) -> boolean

应该是

public boolean anyAdults( int [] ages );
public int oldest( int [] ages );

<击> 你不能。

至少不是你描述的方式。

考虑以下情况。该规范的一个陈述可能是:

"... the system saves the user name and ... "

可能的方法签名太多了。

 public void setUserName( String name );
 public void setName( String user );
 public void userName( String user );
 public String saveUserName( String s );
 public void save( String userName );
 ... another 10 more here ... 

等。所有这些都是正确的,因为他们会将这个功能添加到代码中。

您可以做的是添加方法生成的说明,如。

  

注意: 所有方法名称应遵循下一个模式(在此描述模式)

然后你可以编译类并使用反射获取方法名称并评估它们是否符合你的规范。

 String studentClassName = args[0];
 Class class = Class.forName( studentClassName );
 Methods [] methods = class.getMethods();
 for( Method m : methods ) {
    if( matchThePattern( method.getName() ) ){
       markAsAccepted( method.getName() );
    }
 }
 if( allTheMethodsAreWritten() ) {
      grade("A");
 }

要评估它们是否符合您需要验证该类是否包含以下内容的标准:

1)规范声明的方法数量(它们可以有更多) 2)方法名称与规范匹配(方法反映了意图)。

例如,对于我的初始示例,以下所有内容都是有效的条目:

  [setUserName,setName,userName,saveUserName,save]

您的模式可能类似于:

keyAction + Subject(s)+ Other。

或者有意义的事情。

答案 5 :(得分:2)

如果规范包含完全方法签名,您也可以提供界面,因为学生不会真正编写界面,而是从规范中复制它。

如果规范不准确(只描述每个方法的参数),那么您可能不应该使用接口,因为可能存在对同一方法或参数描述的许多有效解释(protected vs. { {1}},不同的参数顺序,public与阵列与ListIterableBitSet等等。)您不应因为即将到来而惩罚您的学生使用与您不完全匹配的有效解决方案。

答案 6 :(得分:2)

除非你处理他们的来源,否则你不能做你想做的事。

如果您真的想要这样做,那么您可以编写一个加载其类的程序,并使用反射来检查方法,以查看它们的签名是否符合您的要求。需要很多肘部油脂。

我个人建议他们在分配项目之前合作定义类中的接口,然后说必须使用THAT接口。

答案 7 :(得分:1)

@ weiji的反思理念听起来确实不错,虽然它可能会让你的结局变得非常复杂 也许您可以编写另一个继承自其类的类,但另外实现指定的接口,并使用虚拟方法填充,只需调用父类中的相应函数

答案 8 :(得分:1)

这是hackish,但你不能只使用像sed这样的工具来插入“实现YourInterface”吗?

我知道如果有一堆具有不同名称的类会很难,但似乎只有一个类供他们提交,所以没关系。

如果这种做法真的很苛刻,那么在评论中为了后代而随意批评。

答案 9 :(得分:1)

你可以做的另一件事是让他们编写接口然后编写类。所以你可以给他们提出要求,并让他们编写一个具有满足这些要求的方法的类,并让他们编写一个表示类实现的接口。所以你会:

InterfaceFoo{
 ....
 }
Foo implements InterfaceFoo{
 ....
 }

然后你可以只使用定义了方法的类,并实现InterfaceFoo,如果它编译然后你知道学生正确创建了正确的方法和签名,如果没有,那么编译器会让你知道它们是什么错过。

答案 10 :(得分:0)

你可以做的一件事就是说你要测试他们程序的输出。为了让它们执行代码,他们需要创建一个像IGradeable这样的空接口。

他们可以按照自己的意愿定义它。当他们把它交给你的时候,你可以像这样定义你的IGradeable界面:

public interface IGradeable extends FooInterface
{
....
}

只是一个建议。我能想到的另一种方法是做一些像创建临时java文件的东西,并做一个正则表达式替换,让所有文件都实现FooInterface。

答案 11 :(得分:0)

您可以使用反射来查看学生的类是否实现了界面定义的所有方法。

答案 12 :(得分:0)

我同意jonnii的回答。学生不必实现Foo界面。这是教会只创建一个扩展Student类并实现接口的类。

答案 13 :(得分:0)

最好的方法是使用反射比较方法或创建here概述的代理类。

答案 14 :(得分:0)

顺便说一下,请务必要求每个学生在课程名称中加入他或她的全名。这样你就可以选择同时编译所有这些东西,这样你就可以节省很多时间。

也要么需要特定的包名,要么更简单,根本不需要包。

答案 15 :(得分:-1)

使用 AOP ,您可以编织学生的课程并综合让他们在运行时实施FooInterface 并针对他们运行您的测试套件。对于每个学生,使用自定义类加载器可以非常简单地自动完成。

但是,我不确定当类实际上没有实现具有正确签名的所有方法时,这将在运行时如何表现,例如如果它只是抛出MethodNotFoundErrors

aspect MakeImplementFooAspect {
  // makes many classes implement FooInterface
  declare parents : edu.teaching.foo.* implements FooInterface;
}

答案 16 :(得分:-1)

我不知道你是否可以在编译时这样做,但这是一个想法。为什么不在运行时通过创建类型为Foo的类检查并检查它是否是instanceof FooInterface?希望这可以帮助。我尝试用注释来考虑某种解决方案,但是在编译时我无法想出任何工作。