这些是非常不同的语言,尤其是在该领域。假设您有一堂课。在这种情况下,我们将其设为用户控件,例如文本框。称之为UIControl。现在我们要把它放在另一个类中。在这种情况下,由于我们在示例中使用的是UI,因此我们将其称为CleverPanel类。我们的CleverPanel实例将由于各种原因想知道其UIControl实例发生的事情。这该怎么做?
在C#中,基本方法是检查各种事件,设置将在触发每个有趣事件时执行的方法。在缺少事件的Java中,通常的解决方案是将具有各种“事件”处理方法的对象传递给UIControl方法:
boolean stillNeedIt = ... ;
uiControl.whenSomethingHappens( new DoSomething() {
public void resized( Rectangle r ) { ... }
public boolean canICloseNow() { return !stillNeedIt; }
public void closed() { ... }
...
} );
到目前为止,C#和Java之间的区别并不深远。但是,我们拥有C#不需要的DoSomething接口。同样,此接口可能包含很多在大多数时候不需要的方法。在C#中,我们只是不处理该事件。在Java中,我们创建一个为所有接口方法DoSomethingAdapter提供空实现的类。现在,我们将DoSomething替换为DoSomethingAdapter,并且完全不需要编写任何方法即可进行干净的编译。我们最终只是覆盖使程序正常运行所需的方法。因此,我们最终需要一个接口,并在Java中使用继承来匹配我们对C#中的事件所做的操作。
这是一个示例,而不是全面的讨论,但它提供了Java为什么与C#相比继承如此之多的基础。
现在,为什么Java这样工作?灵活性。传递给whenSomethingHappens的对象可以完全从其他地方传递给CleverPanel。可能是几个CleverPanel实例应将其传递给类似UIControl的对象,以帮助某个地方的CleverWindow对象。 或者,UIControl可以将其交给其组件之一。
另外,在某处可能会有DoSomething实现,而不是适配器,后面有成千上万行代码。我们可以创建一个新的实例是和传递。我们可能需要重写一种方法。Java中的一个常见技巧是使用一个类似以下方法的大型类:
public class BigClass implements DoSomething {
...many long methods...
protected int getDiameter() { return 5; }
}
然后在CleverlPanel中:
uiControl.whenSomethingHappens( new BigClass() {
@Override
public int getDiameter() { return UIPanel.currentDiameter; }
} );
开源Java平台做了很多这样的工作,这往往促使程序员做更多的事情-都是因为他们以它为例,只是为了使用它。我确实认为该语言的基本设计落后于Sun的框架设计,而 Java程序员则在不使用该框架时使用这些技术。
在Java中动态创建类确实很容易。匿名或已命名的类仅需要在用一种方法深层埋藏的一小段代码中进行引用。它可以是全新创建的,也可以通过对非常大的现有类进行少量修改来创建。(现有类可以在其自己的文件中位于顶层,也可以嵌套在顶层类中,或者仅在单个代码块中定义)。新的类实例可以完全访问所有创建对象的数据。新实例可以在整个程序中传递和使用,代表创建它的对象。
(顺便说一句,请注意,这里继承的大量使用(就像Java中的其他地方一样)只是出于DRY的目的。它允许不同的类重用相同的代码。还要注意Java中继承的简便性鼓励了这一点。 )
同样,这不是一个全面的讨论。我只是在这里刮擦表面。但是,是的,Java和C#之间使用继承的方式存在惊人的差异。 在这方面,它们是非常不同的语言。这不是你的想象力。