Це дуже різні мови, особливо в цій галузі. Скажімо, у вас клас. У цьому випадку ми зробимо його керуванням користувачем, чимось на зразок текстового поля. Назвіть це UIControl. Тепер ми хочемо поставити це в інший клас. У цьому випадку, оскільки ми використовуємо інтерфейс користувача для нашого прикладу, ми будемо називати його класом 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 не є глибокою. Однак у нас є інтерфейс DoSomething, який не потрібен у C #. Також цей інтерфейс може містити безліч методів, які не потрібні більшу частину часу. У C # ми просто не обробляємо цю подію. У Java ми створюємо клас, який забезпечує нульову реалізацію для всіх методів інтерфейсу, DoSomethingAdapter. Тепер ми замінюємо DoSomething на DoSomethingAdapter, і нам не потрібно писати жодних методів для чистого компіляції. Ми закінчуємо лише переосмислення методів, необхідних для правильної роботи програми. Отже, нам потрібен інтерфейс та використання успадкування на Java, щоб відповідати тому, що ми робили з подіями в C #.
Це приклад, а не всебічна дискусія, але він дає основи того, чому в Java так багато спадку на відміну від C #.
Тепер, чому Java працює таким чином? Гнучкість. Об'єкт передається, колиSomethingHappens міг би бути переданий 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 та C #. У цьому відношенні вони дуже різні мови. Це не ваша уява.