Поддерживает ли Java разделение между определениями классов и реализациями, как в C ++?


10

У меня есть домашнее задание, и мне нужно оценить, какой подход лучше в соответствии с GRASP «Защищенное изменение». Я нашел вопрос о переполнении стека о разделении файлов заголовка и кода в C ++ .

Тем не менее, я хочу знать, почему Java не следует C ++ в продвижении разделения между определениями классов и реализациями классов. Есть ли какие-либо преимущества у метода Java по сравнению с методом C ++?


Если вы хотите спросить «Почему Java не использует заголовочные файлы», просто спросите об этом и покончите с «что лучше» - как вы видели, у нас аллергия на это;) Также поиск, я Я уверен, что это (или, по крайней мере, тесно связанные вопросы) были подняты раньше.

К сожалению, ссылка не работает. Я переформулирую, что я хотел знать в основном, это различия между ними, и какой из них имеет тенденцию быть более легким для повторного использования кода или для расширяемости.
Этьен Ноэль

1
C (и, соответственно, C ++) действительно не было другого выбора, кроме как отделить заголовочные файлы от файлов реализации из-за ограниченной технологии однопроходного компилятора во время создания C.
Channel72

2
Java может иметь интерфейсы, которые могут разделять определение класса и реализацию класса, если рассматриваемый класс реализует интерфейс. Не совсем так же, как C ++, хотя.
FrustratedWithFormsDesigner

1
Кроме того, заголовочные файлы C ++ предоставляют значительно больше реализации, чем мне нравится, если только вы не используете идиому PIMPL. Необходимо перечислить все элементы данных, даже если private, поэтому реализация будет знать размер, а также privateфункции-члены.
Дэвид Торнли

Ответы:


13

Сколько строк кода в следующей программе?

#include <iostream>

int main()
{
   std::cout << "Hello, world!\n";
   return 0;
}

Вы, вероятно, ответили 7 (или 6, если вы не считали пустую строку, или 4, если вы не считали скобки).

Ваш компилятор, однако, видит что-то совсем другое:

~$ cpp hello.cpp | wc
  18736   40822  437015

Да, это 18,7 KLOC только для "Привет, мир!" программа. Компилятор C ++ должен проанализировать все это. Это главная причина, почему компиляция C ++ занимает так много времени по сравнению с другими языками, и почему современные языки избегают заголовочных файлов.

Лучший вопрос будет

Почему же C ++ есть файлы заголовков?

C ++ был разработан, чтобы быть надмножеством C, поэтому он должен был хранить заголовочные файлы для обратной совместимости.

Хорошо, так почему C имеет заголовочные файлы?

Из-за своей примитивной отдельной модели компиляции. Объектные файлы, сгенерированные компиляторами C, не содержат никакой информации о типе, поэтому для предотвращения ошибок типа вам необходимо включить эту информацию в ваш исходный код.

~$ cat sqrtdemo.c 
int main(void)
{
    /* implicit declaration int sqrt(int) */
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm -Dsqrt= sqrtdemo.c
sqrtdemo.c: In function main’:
sqrtdemo.c:5:5: warning: implicit declaration of function printf [-Wimplicit-function-declaration]
sqrtdemo.c:5:5: warning: incompatible implicit declaration of built-in function printf [enabled by default]
~$ ./a.out 
2.000000

Добавление правильных объявлений типов исправляет ошибку:

~$ cat sqrtdemo.c 
#undef printf
#undef sqrt

int printf(const char*, ...);
double sqrt(double);

int main(void)
{
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm sqrtdemo.c
~$ ./a.out 
1.414214

Обратите внимание, что нет #includes. Но когда вы используете большое количество внешних функций (что делает большинство программ), их ручное объявление становится утомительным и подверженным ошибкам. Гораздо проще использовать заголовочные файлы.

Как современные языки могут избежать заголовочных файлов?

Используя другой формат объектного файла, который включает информацию о типе. Например, формат файла Java * .class включает «дескрипторы», которые определяют типы полей и параметры метода.

Это не было новым изобретением. Ранее (1987), когда Borland добавил отдельно скомпилированные «модули» в Turbo Pascal 4.0, он решил использовать новый *.TPUформат, а не Turbo C, *.OBJчтобы устранить необходимость в заголовочных файлах.


Хотя интересно, я вполне уверен, что вы могли бы установить Turbo Pascal для вывода OBJфайлов, а не TPUs ...
CVN

7

У Java есть интерфейсы для определения контракта. Это дает более высокий уровень абстракции от того, что нужно вызывающей стороне и фактической реализации. то есть вызывающему не нужно знать реализующий класс, ему нужно только знать контракт, который он поддерживает.

Скажем, вы хотите написать метод, который замедляет все ключи / значения на карте.

public static <K,V> void printMap(Map<K,V> map) {
    for(Entry<K,V> entry: map.entrySet())
        System.out.println(entry);
}

Этот метод может вызывать entrySet () для абстрактного интерфейса, который удален из реализующего его класса. Вы можете вызвать этот метод с помощью.

printMap(new TreeMap());
printMap(new LinkedHashMap());
printMap(new ConcurrentHashMap());
printMap(new ConcurrentSkipListMap());

1
Добро пожаловать в Программисты там, Питер - думал, я узнал имя :-). Я добавлю, что некоторые люди будут утверждать, что абстрактные базовые классы в Java также определяют контракт - но это, вероятно, аргумент для отдельного потока.
Мартейн Вербург

Здравствуйте @MartijnVerburg, Хорошее дополнение. Я думаю, что абстрактные классы стирают различие между интерфейсами без реализаций и конкретными классами. Методы расширения будут еще больше стирать различия. Я предпочитаю использовать интерфейс, если могу, так как они проще.
Питер Лори

Да, Java начнет двигаться по пути Scala, заключающемуся в том, чтобы иметь несколько способов определения публичного контракта - я не уверен, что это хорошо или нет :-)
Martijn Verburg

-1 Это возможно и в C ++, с помощью простого #define interface class.
Sjoerd

@Sjoerd Я не знал, что методам C ++ больше не нужно использовать virtualключевое слово для получения полиморфизма, и это не снижает производительности, если вы используете только один или два конкретных типа, как в Java. Можете ли вы указать мне какую-либо документацию о том, как это работает в C ++?
Питер Лори

5

Заголовки существуют, прямо скажем, как историческая случайность. Это невероятно плохая система, ни на одном другом языке нет ничего настолько ужасного, и любой, кому не приходится иметь с ними дело, должен радоваться.


3

Заголовки предназначены для отдельной компиляции. За счет #include заголовков компилятору не нужно ничего знать о двоичной структуре скомпилированного кода C ++, и он может оставить это задание отдельному компоновщику. Java не использует отдельный компоновщик со своим компилятором, и поскольку файлы .class строго определены, компилятор может читать их, чтобы определить всех их членов со всеми их типами, без необходимости повторного объявления их в каждом модуле компиляции.

Вы можете включить всю реализацию в заголовок C ++, но это заставляет компилятор перекомпилировать его каждый раз, когда он #included, заставляя компоновщик разбирать и отбрасывать дубликаты.


0

Java способствует разделению определения класса и реализации, это просто зависит от того, откуда вы смотрите.

Когда вы являетесь автором класса Java, вы можете увидеть определение класса и его реализацию в одном файле. Это упрощает процесс разработки, так как вам нужно только перейти в одно место для поддержки класса, вам не нужно переключаться между двумя файлами (.h и .cpp, как в C ++). Однако, когда вы являетесь потребителем класса, вы имеете дело только с определением через файл .class, который упакован в .jar или в отдельный .class

C ++ позволяет разделить определение и реализацию, но это специальное решение. Например, ничто не мешает вам писать метод, встроенный в заголовочный файл, а для шаблонных классов это обязательно. В заголовочном файле также перечислены все переменные-члены, которые видны всем, кто просматривает заголовочный файл, даже если они являются подробностями реализации класса и не имеют отношения к потребителю.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.