Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

В этой статье сравниваются два языка программирования : C # и Java . Хотя в этой статье основное внимание уделяется языкам и их функциям, при таком сравнении обязательно будут рассмотрены некоторые особенности платформ и библиотек . Для более подробного сравнения платформ см. Сравнение платформ Java и .NET .

C # и Java - похожие языки, типизированные статически, строго и явно . Оба объектно-ориентированный , и разработан с полу интерпретации или выполнения точно в срок компиляции , и оба являются фигурные скобки языков , таких как C и C ++ .

Типы [ править ]

Единая система типов [ править ]

Оба языка имеют статическую типизацию с объектной ориентацией на основе классов. В Java примитивные типы отличаются тем, что они не объектно-ориентированы и не могут быть определены с использованием самого языка. У них также нет общего предка со ссылочными типами. Все ссылочные типы Java являются производными от общего корневого типа. C # имеет унифицированную систему типов, в которой все типы (кроме небезопасных указателей [16] ) в конечном итоге являются производными от общего корневого типа. Следовательно, все типы реализуют методы этого корневого типа, а методы расширения, определенные для objectтипа, применяются ко всем типам, даже к примитивным intлитералам и делегатам.. Это позволяет C #, в отличие от Java, поддерживать объекты с инкапсуляцией, которые не являются ссылочными типами.

В Java составные типы являются синонимами ссылочных типов; методы не могут быть определены для типа, если он также не является ссылочным типом класса . В C # концепции инкапсуляции и методов были отделены от требований ссылки, так что тип может поддерживать методы и инкапсуляцию, не являясь ссылочным типом. Однако только ссылочные типы поддерживают виртуальные методы и специализацию.

Оба языка поддерживают множество встроенных типов , которые копируются и передаются по значению, а не по ссылке. Java называет эти типы примитивными типами , тогда как в C # они называются простыми типами . Примитивные / простые типы обычно имеют встроенную поддержку со стороны базовой архитектуры процессора.

Простые типы C # реализуют несколько интерфейсов и, следовательно, предлагают множество методов непосредственно для экземпляров типов, даже для литералов. Имена типов C # также являются всего лишь псевдонимами для типов Common Language Runtime (CLR). Тип C # System.Int64точно такой же, как и longтип; единственное отличие состоит в том, что первое является каноническим именем .NET, а второе - псевдонимом C #.

Java не предлагает методов непосредственно для примитивных типов. Вместо этого методы, которые работают с примитивными значениями, предлагаются через сопутствующие примитивные классы-оболочки . Существует фиксированный набор таких классов-оболочек, каждый из которых является оболочкой для одного из фиксированного набора примитивных типов. Например, Longтип Java - это ссылочный тип, который является оболочкой для примитивного longтипа. Однако они не одного типа.

Типы данных [ править ]

Числовые типы [ править ]

Целые числа со знаком [ править ]

Как и Java , C # , поддержка подписаны целые числа с битовой шириной 8, 16, 32 и 64 бита. Они используют одно и то же имя / псевдонимы для типов, за исключением 8-битного целого числа, которое называется a byteв Java и sbyte(байт со знаком) в C #.

Целые числа без знака [ править ]

C # поддерживает без знака в дополнении к подписанным целочисленным типам. Эти типы без знака byte, ushort, uintи ulongдля 8, 16, 32 и 64 бит ширины, соответственно. Также поддерживаются беззнаковые арифметические операции с типами. Например, добавление двух целых чисел без знака uintвсе равно дает uintрезультат; не длинное целое число со знаком.

В Java нет целочисленных типов без знака. В частности, в Java отсутствует примитивный тип для беззнакового байта . Вместо этого byteтип Java является расширенным знаком , что является частым источником ошибок и путаницы. [17]

Целые числа без знака были намеренно исключены из Java, потому что Джеймс Гослинг считал, что программисты не поймут, как работает беззнаковая арифметика.

При разработке языков программирования одна из стандартных проблем заключается в том, что язык становится настолько сложным, что никто не может его понять. Один из небольших экспериментов, которые я провел, - это расспрашивать людей о правилах беззнаковой арифметики в C. Оказывается, никто не понимает, как работает беззнаковая арифметика в C. Есть несколько очевидных вещей, которые люди понимают, но многие этого не понимают. [9] [18]

Десятичные числа высокой точности [ править ]

В C # есть тип и буквальная нотация для высокоточной (28 десятичных цифр) десятичной арифметики, которая подходит для финансовых и денежных расчетов. [19] [20] [21] В отличие от floatи doubleтипов данных, десятичные дробные числа , такие как 0,1 могут быть представлены точно в десятичном представлении. В представлениях float и double такие числа часто имеют неограниченные двоичные расширения, что делает эти представления более подверженными ошибкам округления. [20]

Хотя в Java отсутствует такой встроенный тип, в библиотеке Java есть десятичный тип произвольной точности . Это не считается языковым типом и не поддерживает обычные арифметические операторы; скорее это ссылочный тип, которым нужно управлять с помощью методов типа. Подробнее о числах произвольного размера и точности см . Ниже .

Расширенные числовые типы [ править ]

Оба языка предлагают определяемые библиотекой арифметические типы произвольной точности для целых чисел произвольного размера и вычислений с десятичной запятой.

Только в Java есть тип данных для вычислений с десятичной точкой произвольной точности. Только в C # есть тип для работы с комплексными числами .

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

C # позволяет интегрировать определяемые библиотекой типы с существующими типами и операторами с помощью настраиваемых неявных / явных преобразований и перегрузки операторов. См. Пример в разделе Интеграция типов, определенных библиотекой

Персонажи [ править ]

Оба языка имеют собственный char(символьный) тип данных как простой тип. Хотя charтип может использоваться с побитовыми операторами, это выполняется путем charпреобразования значения в целое значение перед операцией. Таким образом, результатом побитовой операции в обоих языках является числовой тип, а не символ.

Встроенные составные типы данных [ править ]

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

Библиотеки обоих языков определяют классы для работы с датами и календарями в разных культурах. Java java.util.Date- это изменяемый ссылочный тип, тогда как C # System.DateTime- это тип структурного значения. C # дополнительно определяет TimeSpanтип для работы с периодами времени. Оба языка поддерживают арифметику даты и времени в соответствии с различными культурами.

Пользовательский тип значения (структура) [ править ]

C # позволяет программисту создавать определяемые пользователем типы значений с помощью structключевого слова. В отличие от классов и, как и стандартные примитивы, такие типы значений передаются и присваиваются по значению, а не по ссылке. Они также могут быть частью объекта (в виде поля или в рамке ) или храниться в массиве без косвенного обращения к памяти, которое обычно существует для типов классов.

Поскольку типы значений не имеют понятия о nullзначении и могут использоваться в массивах без инициализации, они всегда поставляются с неявным конструктором по умолчанию, который по существу заполняет пространство памяти структуры нулями. Программист может определять дополнительные конструкторы только с одним или несколькими аргументами. Типы значений не имеют таблиц виртуальных методов , и из-за этого (и фиксированного объема памяти) они неявно запечатаны. Однако типы значений могут (и часто реализуют) интерфейсы . Например, встроенные целочисленные типы реализуют несколько интерфейсов .

Помимо встроенных примитивных типов, Java не включает концепцию типов значений.

Перечисления [ править ]

Оба языка определяют перечисления, но реализуются принципиально по-разному. Таким образом, перечисления - это одна из областей, где инструменты, разработанные для автоматического перевода кода между двумя языками (например, преобразователи Java в C #), терпят неудачу.

В C # перечисления реализованы аналогично C, то есть в виде оберток вокруг битовых флагов, реализованных в примитивных целочисленных типах (int, byte, short и т. Д.). Это дает преимущества в производительности и улучшает взаимодействие с скомпилированным кодом C / C ++, но предоставляет меньше функций и может привести к ошибкам, если типы значений низкого уровня напрямую приводятся к типу перечисления, как это разрешено в языке C #. Следовательно, это рассматривается как синтаксический сахар . [22] В отличие от этого, Java реализует перечисления как полнофункциональную коллекцию экземпляров, требующую большего объема памяти и не способствующую взаимодействию с кодом C / C ++, но обеспечивающую дополнительные функции в отражении и внутреннем поведении. Реализация на каждом языке описана в таблице ниже.

И в C #, и в Java программисты могут использовать перечисления в операторе switch без преобразования в строковый или примитивный целочисленный тип. Однако C # не допускает неявного провала, если оператор case не содержит никакого кода, поскольку это частая причина труднодоступных ошибок. [25] Прохождение должно быть явно объявлено с помощью оператора goto. [26]

Делегаты, ссылки на методы [ править ]

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

Не следует путать делегатов с закрытием и встроенными функциями. Эти концепции связаны, потому что ссылка на закрывающую / встроенную функцию должна быть зафиксирована в ссылке на делегат, чтобы быть полезной вообще. Но делегат не всегда ссылается на встроенную функцию; он также может ссылаться на существующие статические методы или методы экземпляра. Делегаты составляют основу событий C # , но их не следует путать с ними.

Делегаты были намеренно исключены из Java, потому что они считались ненужными и вредными для языка, а также из-за потенциальных проблем с производительностью. [27] Вместо этого используются альтернативные механизмы. Шаблон обертки , который напоминает делегат C # в том , что она позволяет клиент одного доступа или несколько клиентских определенные методам через известный интерфейс , является одним из таких механизмов. [ необходима цитата ] Другой вариант - использование объектов- адаптеров, использующих внутренние классы, что, по мнению разработчиков Java, является лучшим решением, чем ссылки на связанные методы. [27]

См. Также примеры делегатов C # и эквивалентных конструкций Java .

Поднятые (допускающие значение NULL) типы [ править ]

C # позволяет «поднять» значения / примитивные / простые типы, чтобы допустить специальное nullзначение в дополнение к собственным значениям типа. Тип повышается добавлением ?суффикса к имени типа; это эквивалентно использованию Nullable<T> универсального типа, где T- тип, который нужно поднять. Неявно определены преобразования для преобразования между значениями базового и повышенного типов. Поднятый тип можно сравнить nullили проверить HasValue. Кроме того, поднятые операторы неявно и автоматически определяются на основе их не поднятого основания, где - за исключением некоторых логических операторов - нулевой аргумент будет распространяться на результат.

Java не поддерживает подъем типов как концепцию, но все встроенные примитивные типы имеют соответствующие типы-оболочки, которые поддерживают nullзначение в силу того, что они являются ссылочными типами (классами).

Согласно спецификации Java, любая попытка разыменования nullссылки должна приводить к возникновению исключения во время выполнения, в частности файла NullPointerException. (В противном случае не было бы смысла разыменовать его, потому что, по определению, он не указывает ни на один объект в памяти.) Это также применяется при попытке распаковать переменную типа оболочки, которая оценивается как null: программа выдаст исключение, потому что нет объекта, который нужно распаковать, и, следовательно, нет упакованного значения, которое могло бы участвовать в последующих вычислениях.

В следующем примере показано различное поведение. В C # оператор с поднятым * передает nullзначение операнда; в Java при распаковке пустой ссылки возникает исключение.

Не все операторы C # с лифтом были определены для nullбезусловного распространения , если один из операндов null. В частности, булевы операторы были расширены для поддержки тернарной логики, таким образом сохраняя импеданс с SQL .

Логические операторы Java не поддерживают троичную логику и не реализованы в библиотеке базовых классов.

Поздний (динамический) тип [ править ]

В C # есть динамический тип с поздним связыванием, который поддерживает динамический вызов без отражения, взаимодействие с динамическими языками и специальную привязку (например) к объектным моделям документов. dynamicДоступа рассасывается типа члена динамически во время выполнения , в отличие от статический / виртуальных во время компиляции. Механизм поиска членов расширяем за счет традиционного отражения в качестве механизма отката.

В dynamicC # есть несколько вариантов использования этого типа:

  • Менее подробное использование отражения: путем приведения экземпляра к dynamicтипу члены, такие как свойства, методы, события и т. Д., Могут быть напрямую вызваны в экземпляре без прямого использования API отражения.
  • Взаимодействие с динамическими языками: динамический тип поставляется с поддержкой узлового типа для реализации динамически типизированных объектов и общей инфраструктуры времени выполнения для эффективного поиска членов.
  • Создание динамических абстракций на лету: например, динамический объект может обеспечить более простой доступ к объектным моделям документов, таким как документы XML или XHTML .

Java не поддерживает тип с поздним связыванием. Варианты использования динамического типа C # имеют разные соответствующие конструкции в Java:

  • Для динамического вызова уже существующих типов по имени с поздним связыванием следует использовать отражение.
  • Для взаимодействия с динамическими языками необходимо использовать некоторую форму API взаимодействия, специфичную для этого языка. Платформа виртуальной машины Java действительно имеет несколько динамических языков, реализованных на ней, но не существует общего стандарта для того, как передавать объекты между языками. Обычно это включает в себя некоторую форму отражения или подобного отражению API. В качестве примера использования объектов JavaFX из Java. [28]
  • Для создания и взаимодействия с объектами полностью во время выполнения, например, взаимодействия с абстракцией объектной модели документа, необходимо использовать специфический API абстракции.

См. Также пример # Совместимость с динамическими языками .

Указатели [ править ]

Java исключает указатели и арифметику указателей в среде выполнения Java. Разработчики языка Java рассудили, что указатели являются одной из основных функций, позволяющих программистам вставлять ошибки в свой код, и решили не поддерживать их. [9] Java не позволяет напрямую передавать и получать объекты / структуры в / из базовой операционной системы и, таким образом, не нуждается в моделировании объектов / структур для такого конкретного макета памяти, макетов, которые часто включают указатели. Связь Java с базовой операционной системой вместо этого основана на Java Native Interface (JNI), где связь с базовой операционной системой / адаптация к ней осуществляется через внешний связующий слой.

Хотя C # действительно позволяет использовать указатели и соответствующую арифметику указателей, разработчики языка C # обеспокоены тем, что указатели потенциально могут использоваться для обхода строгих правил доступа к объектам. Таким образом, C # по умолчанию также исключает указатели. [29] Однако, поскольку указатели необходимы при вызове многих собственных функций, указатели разрешены в явном небезопасном режиме. Блоки кода или методы, использующие указатели, должны быть помечены unsafeключевым словом, чтобы иметь возможность использовать указатели, а компилятору требуется /unsafeпереключатель, чтобы разрешить компиляцию такого кода. Сборки, скомпилированные с использованием/unsafeswitch помечены как таковые и могут выполняться только в случае явного доверия. Это позволяет использовать указатели и арифметику указателей для прямой передачи и получения объектов в / из операционной системы или других собственных API-интерфейсов с использованием внутренней структуры памяти для этих объектов, а также изолировать такой потенциально небезопасный код в специально доверенных сборках.

Типы справочников [ править ]

В обоих языках ссылки являются центральной концепцией. Все экземпляры классов даны по ссылке .

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

Помимо слабых ссылок, в Java есть мягкие ссылки . Они очень похожи на слабые ссылки, но JVM не освобождает объекты с мягкими ссылками до тех пор, пока не потребуется память.

Массивы и коллекции [ править ]

Массивы и коллекции - это концепции, представленные обоими языками.

Синтаксис, используемый для объявления массивов и доступа к ним, идентичен, за исключением того, что в C # добавлен синтаксис для объявления многомерных массивов и управления ими.

В некоторых случаях многомерные массивы могут повысить производительность из-за повышенной локальности (поскольку для каждого измерения массива используется одно разыменование указателя вместо одного, как в случае массивов с зубчатыми краями). Однако, поскольку доступ ко всем элементам массива в многомерном массиве требует умножения / сдвига между двумя или более измерениями, это является преимуществом только в сценариях с очень произвольным доступом.

Другое отличие состоит в том, что весь многомерный массив можно выделить с помощью одного приложения оператора new, в то время как массивы с зазубринами требуют циклов и выделений для каждого измерения. Однако Java предоставляет синтаксическую конструкцию для выделения зубчатого массива регулярной длины; затем циклы и множественные выделения выполняются виртуальной машиной и не обязательно должны быть явными на уровне источника.

Оба языка имеют обширный набор типов коллекций, который включает в себя различные упорядоченные и неупорядоченные типы списков, карт / словарей, наборов и т. Д.

Java также поддерживает синтаксис C / C ++: [38]

Выражения и операторы [ править ]

Бокс и распаковка [ править ]

Оба языка допускают автоматическую упаковку и распаковку, т.е. они допускают неявное преобразование между любыми примитивными типами и соответствующими ссылочными типами.
В C # примитивные типы являются подтипами типа Object. В Java это не так; любой заданный примитивный тип и соответствующий тип оболочки не имеют конкретных отношений друг с другом, за исключением автобокса и распаковки, которые действуют как синтаксический сахар для обмена между ними. Это было сделано намеренно, чтобы сохранить обратную совместимость с предыдущими версиями Java, в которых не разрешалось автоматическое приведение типов, и программист работал с двумя отдельными наборами типов: примитивными типами и иерархией типов-оболочек (ссылочных). [42]

Это различие имеет следующие последствия. Прежде всего, в C # примитивные типы могут определять методы, такие как переопределение метода Object ToString(). В Java эту задачу выполняют примитивные классы-оболочки .
Во-вторых, в Java требуется дополнительное приведение всякий раз, когда кто-то пытается напрямую разыменовать примитивное значение, поскольку оно не будет упаковано автоматически. Выражение ((Integer)42).toString()преобразует целочисленный литерал в строку в Java, 42.ToString()выполняя ту же операцию в C #. Это связано с тем, что последний является вызовом экземпляра примитивного значения 42, а первый - вызовом экземпляра объекта типа java.lang.Integer.

Наконец, еще одно отличие состоит в том, что Java активно использует упакованные типы в универсальных шаблонах (см. Ниже ).

Заявления [ править ]

Синтаксис [ править ]

Оба языка считаются языками с фигурными скобками в семействе C / C ++. В целом синтаксис языков очень похож. Синтаксис на уровне операторов и выражений практически идентичен, очевидно, навеянным традицией C / C ++. На уровне определения типа (классы и интерфейсы ) существуют некоторые незначительные различия. В Java явно говорится о расширении классов и реализации интерфейсов , в то время как в C # это делается исходя из типа типов, от которых наследуется новый класс / интерфейс .

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

Ключевые слова и обратная совместимость [ править ]

По мере развития языков разработчики языков для обоих языков сталкивались с ситуациями, когда они хотели расширить языки с помощью новых ключевых слов или синтаксиса. В частности, новые ключевые слова могут нарушить существующий код на уровне исходного кода, т. Е. Более старый код может больше не компилироваться, если он представлен компилятору для более поздней версии языка. Разработчики языков стараются избегать таких регрессов. При решении этой проблемы разработчики двух языков пошли разными путями.

Разработчики языка Java по возможности избегали новых ключевых слов, предпочитая вместо этого вводить новые синтаксические конструкции, которые ранее были недопустимы, или повторно использовать существующие ключевые слова в новых контекстах. Таким образом, они не поставили под угрозу обратную совместимость. Пример первого можно найти в том, как forцикл был расширен для приема итерируемых типов. Пример последнего можно найти в том, как повторно использовались ключевые слова extendsи (особенно) superключевые слова для определения границ типов, когда в Java 1.5 были введены дженерики. Одно время (Java 1.4) assertбыло введено новое ключевое слово, которое ранее не зарезервировалось как ключевое слово. Это могло сделать ранее действующий код недействительным, если, например, использованный кодassertкак идентификатор. Разработчики решили решить эту проблему с помощью четырехэтапного решения: 1) Внедрение переключателя компилятора, который указывает, следует ли использовать Java 1.4 или новее, 2) Только маркировка assertкак ключевое слово при компиляции как Java 1.4 и новее, 3) По умолчанию 1.3, чтобы не отображать предыдущий (не поддерживающий 1.4 код) недействительным и 4) Выдавать предупреждения, если ключевое слово используется в режиме Java 1.3, чтобы разработчики могли изменить код.

Разработчики языка C # ввели несколько новых ключевых слов, начиная с первой версии. Однако вместо того, чтобы определять эти ключевые слова как глобальные ключевые слова, они определяют их как контекстно-зависимые ключевые слова. Это означает , что даже если они введены (среди других) partialи yieldключевых слов в C # 2.0, использование этих слов в качестве идентификаторов до сих пор действует как нет столкновения возможно между использованием в качестве ключевого слова и использование в качестве идентификатора, учитывая контекст. Таким образом, существующий синтаксис C # полностью обратно совместим с исходным кодом, написанным для любой предыдущей версии, без указания используемой языковой версии.

Объектно-ориентированное программирование [ править ]

И C #, и Java изначально разрабатывались как объектно-ориентированные языки с использованием динамической диспетчеризации с синтаксисом, аналогичным C ++ (C ++, в свою очередь, является производным от C ). Однако ни один из языков не является надмножеством C или C ++.

Неполный класс [ править ]

C # позволяет разделить определение класса на несколько исходных файлов с помощью функции, называемой частичными классами . Каждая часть должна быть помечена ключевым словом partial. Все части должны быть представлены компилятору как часть одной компиляции. Детали могут ссылаться на элементы из других деталей. Части могут реализовывать интерфейсы, а одна часть может определять базовый класс. Эта функция полезна в сценариях генерации кода (таких как дизайн пользовательского интерфейса (UI)), где генератор кода может предоставить одну часть, а разработчик - другую часть для совместной компиляции. Таким образом, разработчик может редактировать свою часть без риска того, что генератор кода перезапишет этот код позже. В отличие от механизма расширения классов, частичный класс позволяет циклическизависимости между его частями, поскольку они гарантированно разрешаются во время компиляции. В Java нет соответствующей концепции.

Внутренние и локальные классы [ править ]

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

В Java, если внутренний класс не объявлен static, ссылка на экземпляр внутреннего класса несет с собой ссылку на внешний класс. В результате код внутреннего класса имеет доступ как к статическим, так и к нестатическим членам внешнего класса. Чтобы создать экземпляр нестатического внутреннего класса, необходимо дать имя экземпляру охватывающего внешнего класса. [49] Это делается с помощью нового new-оператора , введенной в JDK 1.3: outerClassInstance.new Outer.InnerClass(). Это можно сделать в любом классе, который имеет ссылку на экземпляр внешнего класса.

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

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

C # также предоставляет функцию, называемую анонимными типами / классами , но она сильно отличается от концепции Java с тем же именем. Это позволяет программисту создать экземпляр класса, предоставив только набор имен для свойств, которые должен иметь класс, и выражение для инициализации каждого из них. Типы свойств выводятся из типов этих выражений. Эти неявно объявленные классы являются производными непосредственно от объекта .

Событие [ править ]

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

См. Здесь информацию о том, как события реализованы в Java.

Перегрузка операторов и преобразования [ править ]

Перегрузка оператора и определяемое пользователем приведение - это отдельные функции, цель которых - позволить новым типам стать первоклассными гражданами в системе типов. Благодаря использованию этих функций в C # такие типы, как Complexи decimal, были интегрированы, чтобы обычные операторы, такие как сложение и умножение, работали с новыми типами. В отличие от C ++, C # делает ограничить использование перегрузки операторов, запрещая его для операторов new, ( ), ||, &&, =, и любые вариации сложных утверждений типа +=. Но составные операторы будут вызывать перегруженные простые операторы, такие как -=вызов -и =. [50]

Java не включает перегрузку операторов или настраиваемые преобразования, чтобы предотвратить злоупотребление этой функцией и сохранить простой язык. [51]

Индексатор [ править ]

C # также включает индексаторы, которые можно рассматривать как частный случай перегрузки операторов (например, C ++ operator[]) или параметризованных get/ setсвойств. Индексатор - это свойство с именем, this[]которое использует один или несколько параметров (индексов); индексы могут быть объектами любого типа:

myList [ 4 ]  =  5 ; имя строки  = xmlNode . Атрибуты [ "имя" ]; orders = customerMap [ theCustomer ];    

Java не включает индексаторы. Обычный шаблон Java включает в себя написание явных методов получения и установки, в которых программист на C # будет использовать индексатор.

Поля и инициализация [ править ]

Инициализация объекта [ править ]

И в C #, и в Java поля объекта могут быть инициализированы либо инициализаторами переменных (выражениями, которые могут быть присвоены переменным, в которых они определены), либо конструкторами (специальными подпрограммами, которые выполняются при создании объекта). Кроме того, Java содержит инициализаторы экземпляров , которые представляют собой анонимные блоки кода без аргументов, которые запускаются после явного (или неявного) вызова конструктора суперкласса, но до его выполнения.

C # инициализирует поля объекта в следующем порядке при создании объекта:

  1. Производные статические поля
  2. Производный статический конструктор
  3. Поля производных экземпляров
  4. Базовые статические поля
  5. Базовый статический конструктор
  6. Поля базового экземпляра
  7. Конструктор базового экземпляра
  8. Конструктор производного экземпляра

Некоторые из вышеперечисленных полей могут быть неприменимы (например, если объект не имеет статических полей ). Производные поля - это те, которые определены в прямом классе объекта, а базовое поле - это термин для полей, определенных в одном из суперклассов объекта. Обратите внимание, что представление объекта в памяти содержит все поля, определенные в его классе или любом из его суперклассов, даже если некоторые поля в суперклассах определены как частные.

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

В Java порядок инициализации следующий:

  1. Вызов другого конструктора (либо класса объекта, либо суперкласса объекта)
  2. Инициализаторы переменных экземпляра и инициализаторы экземпляра (в том порядке, в котором они появляются в исходном коде)
  3. Тело конструктора

Как и в C #, новый объект создается путем вызова определенного конструктора. Внутри конструктора первая инструкция может быть вызовом другого конструктора. Если это опущено, вызов конструктора суперкласса без аргументов неявно добавляется компилятором. В противном случае можно явно вызвать либо другой перегруженный конструктор класса объекта, либо конструктор суперкласса. В первом случае вызываемый конструктор снова вызовет другой конструктор (либо класса объекта, либо его подкласса), и цепочка рано или поздно завершится вызовом одного из конструкторов суперкласса.

После вызова другого конструктора (который вызывает прямой вызов конструктора суперкласса и т.д., вплоть до класса Object) инициализируются переменные экземпляра, определенные в классе объекта. Даже если для некоторых переменных явно не определены инициализаторы переменных, эти переменные инициализируются значениями по умолчанию. Обратите внимание, что переменные экземпляра, определенные в суперклассах, уже инициализированы к этому моменту, потому что они были инициализированы конструктором суперкласса при его вызове (либо кодом конструктора, либо инициализаторами переменных, выполненными перед кодом конструктора или неявно значениями по умолчанию). В Java инициализаторы переменных выполняются в соответствии с их текстовым порядком в исходном файле.

Наконец, выполняется тело конструктора. Это обеспечивает правильный порядок инициализации, то есть поля базового класса завершают инициализацию до начала инициализации полей объектного класса.

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

Удаление ресурсов [ править ]

Оба языка в основном используют сборку мусора как средство освобождения ресурсов памяти, а не явное освобождение памяти. В обоих случаях, если объект содержит ресурсы разных типов, помимо памяти, такие как дескрипторы файлов, графические ресурсы и т. Д., То он должен быть явно уведомлен, когда приложение больше не использует его. И C #, и Java предлагают интерфейсы для такого детерминированного удаления, и как C #, так и Java (начиная с Java 7) содержат операторы автоматического управления ресурсами, которые автоматически вызывают методы удаления / закрытия на этих интерфейсах.

Методы [ править ]

Методы расширения и методы по умолчанию [ править ]

Используя специальный указатель this для первого параметра метода, C # позволяет методу действовать так, как если бы он был методом-членом типа первого параметра. Это расширение внешнего класса чисто синтаксическое. Метод расширения должен быть объявлен staticи определен внутри чисто статического класса. Метод должен подчиняться любому ограничению доступа к члену, как и любой другой метод, внешний по отношению к классу; таким образом, статические методы не могут нарушить инкапсуляцию объекта. [57] [58] «Расширение» активно только в тех областях, где было импортировано пространство имен статического хост-класса.

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

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

Правила области C # определяют, что если соответствующий метод найден в классе, он имеет приоритет над подходящим методом расширения. В Java предполагается, что любой класс, объявленный для реализации интерфейса с методом по умолчанию, имеет реализации методов по умолчанию, если только класс не реализует сам метод.

Частичные методы [ править ]

Связанный с частичными классами C # позволяет указывать частичные методы внутри частичных классов. Частичный метод - это намеренное объявление метода с несколькими ограничениями на подпись. Ограничения гарантируют, что если определение не предоставляется какой-либо частью класса, то метод и каждый его вызов можно безопасно стереть. [59] Эта функция позволяет коду предоставлять большое количество точек перехвата (например, шаблонный метод GoF design pattern) без дополнительных затрат времени выполнения, если эти точки расширения не используются другой частью класса во время компиляции. В Java нет соответствующей концепции.

Виртуальные методы [ править ]

Методы в C # по умолчанию не являются виртуальными и при желании должны быть объявлены виртуальными явно. В Java все нестатические неприватные методы являются виртуальными. Виртуальность гарантирует, что всегда будет вызываться самое последнее переопределение для метода, но при вызове возникают определенные затраты времени выполнения, поскольку эти вызовы не могут быть обычно встроены и требуют косвенного вызова через таблицу виртуальных методов . Однако некоторые реализации JVM, включая эталонную реализацию Oracle, реализуют встраивание наиболее часто называемых виртуальных методов.

По умолчанию методы Java являются виртуальными (хотя их можно запечатать с помощью finalмодификатора, запрещающего переопределение). Невозможно позволить производным классам определять новый несвязанный метод с тем же именем.

Это означает, что по умолчанию в Java и только при явном включении в C # новые методы могут быть определены в производном классе с тем же именем и подписью, что и в его базовом классе. Когда метод вызывается для ссылки на суперкласс такого объекта, будет вызываться «самая глубокая» переопределенная реализация метода базового класса в соответствии с конкретным подклассом объекта, на который ссылаются.

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

Чтобы смягчить это, C # требует, чтобы, если метод предназначен для переопределения унаследованного метода, overrideдолжно быть указано ключевое слово. В противном случае метод «скроет» унаследованный метод. Если ключевое слово отсутствует, компилятор выдает предупреждение об этом, которое можно отключить, указав newключевое слово. Это позволяет избежать проблемы, которая может возникнуть из-за расширения базового класса с помощью не частного метода (т. Е. Унаследованной части пространства имен), сигнатура которого уже используется производным классом. В Java есть аналогичная проверка компилятора в виде @Overrideаннотации метода, но она не является обязательной, и в ее отсутствие большинство компиляторов не предоставляют комментарии (но метод будет переопределен).

Постоянные / неизменяемые параметры [ править ]

В Java можно предотвратить переназначение локальной переменной или параметра метода с помощью finalключевого слова. Применение этого ключевого слова к переменной примитивного типа приводит к тому, что переменная становится неизменной. Однако применение finalк переменной ссылочного типа только предотвращает присвоение ей другого объекта. Это не предотвратит изменение данных, содержащихся в объекте. Начиная с C # 7, можно предотвратить переназначение параметра метода с помощью inключевого слова, однако это ключевое слово не может использоваться для локальных переменных. Как и в случае с Java, применение inк параметру только предотвращает переназначение параметра другому значению. По-прежнему можно изменять данные, содержащиеся в объекте. [60]

Оба языка не поддерживают существенную функцию константной корректности, которая существует в C / C ++ , которая делает метод постоянным.

В Java слово «константа» произвольно определяется как поле. Только эти переменные являются переменными только с заглавной буквы, имена которых разделены подчеркиванием [ необходима ссылка ] . Параметр, который только есть, не считается константой, хотя это может быть так в случае примитивного типа данных или неизменного класса , такого как .static finalfinalString

Генераторные методы [ править ]

Любой метод C #, объявленный как возвращающий IEnumerable, IEnumeratorили общие версии этих интерфейсов могут быть реализованы с использованием yieldсинтаксиса. Это форма ограниченных продолжений, генерируемых компилятором, которые могут значительно сократить код, необходимый для обхода или генерации последовательностей, хотя вместо этого этот код просто генерируется компилятором. Эта функция также может использоваться для реализации бесконечных последовательностей, например, последовательности чисел Фибоначчи .

В Java нет эквивалентной функции. Вместо этого генераторы обычно определяются путем предоставления специализированной реализации хорошо известной коллекции или итеративного интерфейса, который будет вычислять каждый элемент по запросу. Чтобы такой генератор можно было использовать в выражении для каждого оператора, он должен реализовывать интерфейс java.lang.Iterable.

См. Также пример последовательности Фибоначчи ниже.

Явная реализация интерфейса [ править ]

В C # также есть явная реализация интерфейса, которая позволяет классу специально реализовывать методы интерфейса отдельно от собственных методов класса или предоставлять разные реализации для двух методов с одинаковым именем и сигнатурой, унаследованных от двух базовых интерфейсов.

На любом языке, если метод (или свойство в C #) указан с тем же именем и подписью в нескольких интерфейсах, члены будут конфликтовать, когда будет разработан класс, реализующий эти интерфейсы. Реализация по умолчанию реализует общий метод для всех интерфейсов. Если требуются отдельные реализации (потому что методы служат разным целям или потому что возвращаемые значения различаются между интерфейсами) явная реализация интерфейса C # решит проблему, хотя и допускает разные результаты для одного и того же метода в зависимости от текущего приведения объекта. В Java нет другого способа решить эту проблему, кроме рефакторинга одного или нескольких интерфейсов, чтобы избежать конфликтов имен. [54]

Справочные (входные / выходные) параметры [ править ]

Аргументы примитивных типов (например, int, double) методу передаются по значению в Java, тогда как объекты передаются по ссылке. Это означает, что метод работает с копиями переданных ему примитивов, а не с фактическими переменными. Напротив, реальные объекты в некоторых случаях могут быть изменены. В следующем примере объект String не изменяется. Объект класса «а» изменен.

В C # можно указать ссылку с refключевым словом, аналогично C ++ и в некотором смысле C. Эта функция C # особенно полезна, когда нужно создать метод, возвращающий более одного объекта. В Java попытка вернуть несколько значений из метода не поддерживается, если не используется оболочка, в данном случае с именем «Ref». [61]

Исключения [ править ]

Проверенные исключения [ править ]

Java поддерживает проверенные исключения (наряду с неотмеченными исключениями). C # поддерживает только непроверенные исключения. Проверенные исключения вынуждают программиста либо объявить исключение, созданное в методе, либо перехватить выброшенное исключение с помощью try-catchпредложения.

Проверенные исключения могут способствовать правильной практике программирования, гарантируя устранение всех ошибок. Однако Андерс Хейлсберг , главный архитектор языка C #, утверждает, что они были до некоторой степени экспериментом в Java и что они не показали никакой ценности , за исключением небольших программ-примеров. [62] [63]

Одна критика состоит в том, что проверенные исключения побуждают программистов использовать пустой блок catch ( catch (Exception e) {}) [64], который молча поглощает исключения, вместо того, чтобы позволить исключениям распространяться в подпрограмму обработки исключений более высокого уровня. Однако в некоторых случаях вместо этого может применяться цепочка исключений , повторно генерируя исключение в исключении оболочки. Например, если объект изменен для доступа к базе данных, а не к файлу, он SQLExceptionможет быть перехвачен и повторно брошен как объект IOException, поскольку вызывающему может не потребоваться знать внутреннюю работу объекта.

Однако не все программисты согласны с такой позицией. Джеймс Гослинг и другие утверждают, что проверенные исключения полезны, и неправильное их использование вызвало проблемы. Бесшумный перехват исключений возможен, да, но необходимо явно указать, что делать с исключением, в отличие от непроверенных исключений, которые по умолчанию не позволяют ничего делать. Его можно игнорировать, но код должен быть написан явно, чтобы его игнорировать. [65] [66]

Попробуй-поймать-наконец [ править ]

Существуют также различия между двумя языками в трактовке try-finallyутверждения. finallyБлок всегда выполняется, даже если tryблок содержит контрольные обходя утверждения типа throwили return. В Java это может привести к неожиданному поведению, если tryблок покидает returnоператор с некоторым значением, а затем finallyблок, который выполняется после этого, также остается returnоператором с другим значением. C # решает эту проблему, запрещая любые операторы передачи управления, такие как returnили breakв finallyблоке.

Распространенной причиной использования try-finallyблоков является защита кода управления ресурсами, что гарантирует высвобождение ценных ресурсов в блоке finally. В C # этот usingоператор является синтаксическим сокращением этого распространенного сценария, в котором всегда вызывается Dispose()метод объекта using.

Довольно тонкое различие - момент создания трассировки стека при возникновении исключения. В Java трассировка стека создается в момент создания исключения.

class  Foo  {  Исключение  вверх  =  новое  исключение ();  INT  Foo ()  бросает  исключение  {  бросить  вверх ;  } }

Исключение в приведенном выше заявлении всегда будет содержать трассировку стека конструктора - независимо от того, как часто вызывается foo. С другой стороны, в C # трассировка стека создается в момент выполнения throw.

class  Foo {  Исключение  e  =  новое  исключение ();  int  foo ()  {  попробуйте  {  бросить  е ;  }  catch  ( исключение  e )  {  бросить ;  }  } }

В приведенном выше коде исключение будет содержать трассировку стека первой строки выброса. При перехвате исключения есть два варианта на случай, если исключение должно быть повторно создано: throwпросто повторно вызовет исходное исключение с исходным стеком, а при этом throw eбудет создана новая трассировка стека.

Наконец блоки [ править ]

Java позволяет потоку управления покинуть finallyблок tryоператора, независимо от того, как он был введен. Это может привести returnк прекращению выполнения другого оператора потока управления (например, ) в середине выполнения. Например:

int  foo ()  {  попробуйте  {  вернуть  0 ;  }  наконец  {  возврат  1 ;  } }

В приведенном выше коде returnоператор внутри tryблока заставляет управление покинуть его, и, таким образом, finallyблок выполняется до того, как произойдет фактический возврат. Однако сам finallyблок также выполняет возврат. Таким образом, исходный возврат, который вызвал его ввод, не выполняется, и вышеупомянутый метод возвращает 1, а не 0. Неформально говоря, он пытается вернуть 0, но в итоге возвращает 1.

C # не допускает никаких операторов, которые позволяют потоку управления finallyпреждевременно покинуть блок, за исключением throw. В частности, returnне допускаются вообще, gotoне допускаются , если целевая метка находится вне finallyблока, и , continueи breakне допускаются , если ближайший цикл вшиты находится за пределами finallyблока.

Дженерики [ править ]

В области дженериков два языка демонстрируют внешнее синтаксическое сходство, но у них есть глубокие различия.

Стирание типов по сравнению с обобщенными типами [ править ]

Дженерики в Java - это конструкция, предназначенная только для языка; они реализованы только в компиляторе. Сгенерированные файлы классов включают общие подписи только в форме метаданных (позволяя компилятору компилировать для них новые классы). Среда выполнения ничего не знает о системе универсальных типов; дженерики не являются частью JVM . Вместо этого универсальные классы и методы преобразуются во время компиляции с помощью процесса, называемого стиранием типа . Во время этого компилятор заменяет все универсальные типы их необработанной версией и соответствующим образом вставляет приведение / проверку в клиентский код, в котором используются тип и его методы. Результирующий байт-код не будет содержать ссылок на какие-либо общие типы или параметры (см. Также Generics in Java ).

Спецификация языка Java намеренно запрещает использование универсальных шаблонов; это необходимо для реализации универсальных шаблонов посредством стирания типов и для обеспечения совместимости при миграции. [67] Исследования по добавлению обобщенных универсальных шаблонов на платформу Java продолжаются в рамках проекта Valhalla .

C # основан на поддержке универсальных шаблонов из виртуальной исполнительной системы, т. Е. Это не просто языковая функция. Язык - это просто интерфейс для поддержки кросс-языковых универсальных шаблонов в CLR . Во время компиляции универсальные шаблоны проверяются на правильность, но генерация кода для реализации универсальных шаблонов откладывается до времени загрузки класса. Клиентский код (код, вызывающий универсальные методы / свойства) полностью скомпилирован и может безопасно предполагать, что универсальные типы являются безопасными по типу. Это называется овеществлением. Во время выполнения, когда уникальный набор параметров типа для универсального класса / метода / делегата встречается впервые, загрузчик / проверяющий класс синтезирует конкретный дескриптор класса и сгенерирует реализации методов. Во время генерации реализаций методов все ссылочные типы будут считаться одним типом, поскольку ссылочные типы могут безопасно совместно использовать одни и те же реализации. Это просто для реализации кода. Различные наборы ссылочных типов по-прежнему будут иметь уникальные дескрипторы типов; их таблицы методов будут просто указывать на один и тот же код.

В следующем списке показаны некоторые различия между Java и C # при управлении универсальными шаблонами. Он не является исчерпывающим: [68]

C # позволяет использовать универсальные шаблоны непосредственно для примитивных типов. Вместо этого Java позволяет использовать упакованные типы в качестве параметров типа (например, List<Integer>вместо List<int>). За это приходится платить, поскольку все такие значения должны быть упакованы / распакованы при использовании, и все они должны быть размещены в куче. Однако универсальный тип может быть специализирован с типом массива примитивного типа в Java, например List<int[]>, разрешено. [73] Несколько сторонних библиотек реализовали базовые коллекции на Java с резервными примитивными массивами, чтобы сохранить время выполнения и оптимизацию памяти, обеспечиваемую примитивными типами. [74]

Совместимость с миграцией [ править ]

Дизайн стирания типов в Java был мотивирован требованием к дизайну обеспечить совместимость миграции - не путать с обратной совместимостью . В частности, исходное требование было: « … должен быть чистый, очевидный путь миграции для API коллекций, которые были введены в платформу Java 2 ». [42] Это было разработано таким образом, чтобы любые новые общие коллекции могли передаваться методам, ожидающим одного из уже существующих классов коллекций. [75]

Дженерики C # были введены в язык с сохранением полной обратной совместимости, но не сохранили полную совместимость с миграцией : старый код (до C # 2.0) работает без изменений в новой среде выполнения с поддержкой дженериков без перекомпиляции. Что касается совместимости миграции , были разработаны новые универсальные классы коллекций и интерфейсы, которые дополняли неуниверсальные коллекции .NET 1.x, а не заменяли их. Помимо универсальных интерфейсов коллекций, новые универсальные классы коллекций по возможности реализуют неуниверсальные интерфейсы коллекций. Это предотвращает использование новых общих коллекций с уже существующими (не имеющими общего характера) методами, если эти методы закодированы для использования классов коллекций .

Ковариация и контравариантность [ править ]

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

Функциональное программирование [ править ]

Закрытия [ править ]

Замыкание - это встроенная функция, которая захватывает переменные из своей лексической области видимости.

C # поддерживает замыкания как анонимные методы или лямбда-выражения с полнофункциональной семантикой замыкания . [79] [80]

В Java анонимные внутренние классы останутся предпочтительным способом имитации замыканий до тех пор, пока Java 8 не станет новым стандартом. Это более многословная конструкция. Этот подход также имеет некоторые отличия от реальных замыканий, в частности, более контролируемый доступ к переменным из охватывающих областей: можно ссылаться только на конечные члены. Однако в Java 8 представлены лямбда-выражения, которые полностью наследуют текущую область видимости и, по сути, не вводят новую область видимости.

Когда ссылку на метод можно передать для последующего выполнения, возникает проблема, что делать, когда метод имеет ссылки на переменные / параметры в своей лексической области видимости. Замыкания C # могут обращаться к любой переменной / параметру из своей лексической области видимости. В анонимных внутренних классах Java разрешены только ссылки на конечные члены лексической области видимости, что требует от разработчика отмечать, какие переменные сделать доступными и в каком состоянии (возможно, требуя упаковки).

Лямбды и деревья выражений [ править ]

В C # и Java есть специальный тип встроенных замыканий, называемый лямбдами . Это анонимные методы: у них есть подпись и тело, но нет имени. Они в основном используются для указания локальных аргументов, имеющих значение функции, в вызовах других методов, техника, в основном связанная с функциональным программированием .

C #, в отличие от Java, позволяет использовать лямбда-функции как способ определения специальных структур данных, называемых деревьями выражений. Видны ли они как исполняемая функция или как структура данных, зависит от вывода типа компилятора и от того, какой тип переменной или параметра им присваиваются или приводятся. Лямбда-выражения и деревья выражений играют ключевую роль в Language Integrated Query (LINQ).

Метаданные [ править ]

Предварительная обработка, компиляция и упаковка [ править ]

Пространства имен и содержимое файла [ править ]

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

Оба языка позволяют импортировать классы (например, import java.util.*в Java), позволяя ссылаться на класс, используя только его имя. Иногда классы с одинаковыми именами существуют в нескольких пространствах имен или пакетах. На такие классы можно ссылаться, используя полностью определенные имена или импортируя только выбранные классы с другими именами. Для этого Java позволяет импортировать один класс (например, import java.util.List). C # позволяет импортировать классы под новым локальным именем , используя следующий синтаксис: using Console = System.Console. Также он позволяет импортировать специализации классов в виде файлов .using IntList = System.Collections.Generic.List<int>

Оба языка имеют статический синтаксис импорта, который позволяет использовать краткое имя некоторых или всех статических методов / полей в классе (например, разрешая, foo(bar)где foo()можно статически импортировать из другого класса). C # имеет синтаксис статического класса (не путать со статическими внутренними классами в Java), который ограничивает класс только статическими методами. В C # 3.0 представлены методы расширения, позволяющие пользователям статически добавлять метод к типу (например, разрешая, foo.bar()где bar()может быть импортированный метод расширения, работающий с типом foo).

Sun Microsystems компилятор Java требует , чтобы имя исходного файла должно соответствовать только публичный класс внутри него, в то время как C # позволяет использовать несколько общественных классов в одном файле, и накладывает ограничений на имя файла. C # 2.0 и более поздние версии позволяют разделить определение класса на несколько файлов с помощью partialключевого слова в исходном коде. В Java открытый класс всегда находится в собственном исходном файле. В C # файлы исходного кода и разделение логических единиц не связаны тесно.

Условная компиляция [ править ]

В отличие от Java, C # реализует условную компиляцию с помощью директив препроцессора . Он также предоставляет Conditional атрибут для определения методов, которые вызываются только тогда, когда определена заданная константа компиляции. Таким образом, утверждения могут быть предоставлены как фреймворк с методом Debug.Assert(), который оценивается только при определении DEBUGконстанты. Начиная с версии 1.4, Java предоставляет возможность языка для утверждений, которые по умолчанию отключены во время выполнения, но могут быть включены с помощью переключателя -enableassertionsили -eaпри вызове JVM.

Потоковые и асинхронные функции [ править ]

Оба языка включают механизмы синхронизации потоков как часть синтаксиса языка.

Параллелизм на основе задач для C # [ править ]

В .NET Framework 4.0 была представлена ​​новая модель программирования на основе задач, которая заменила существующую асинхронную модель на основе событий. API базируется вокруг Taskи Task<T>классов. Задачи можно составлять и объединять в цепочки.

По соглашению, каждый метод, который возвращает a, Taskдолжен иметь в своем имени постфикс Async .

общедоступный  статический  класс  SomeAsyncCode {  общедоступная  статическая  задача < XDocument >  GetContentAsync ()  {  HttpClient  httpClient  =  new  HttpClient ();  вернуть  httpClient . GetStringAsync ( «www.contoso.com» ). ContinueWith (( task )  =>  {  string  responseBodyAsText  =  task . Result ;  return  XDocument . Parse (responseBodyAsText );  });  } }var  t  =  SomeAsyncCode . GetContentAsync (). ContinueWith (( задача )  =>  {  var  xmlDocument  =  task . Result ; });т . Старт ();

В C # 5 был представлен набор расширений языка и компилятора, чтобы упростить работу с моделью задач. Эти языковые расширения включают понятие asyncметодов и awaitинструкции, которые делают выполнение программы синхронным.

общедоступный  статический  класс  SomeAsyncCode {  общедоступная  статическая  асинхронная  задача < XDocument >  GetContentAsync ()  {  HttpClient  httpClient  =  new  HttpClient ();  строка  responseBodyAsText  =  ждать  httpClient . GetStringAsync ( «www.contoso.com» );  вернуть  XDocument . Разбор ( responseBodyAsText );  } }var  xmlDocument  =  ждать  SomeAsyncCode . GetContentAsync ();// Задача будет запускаться по вызову с ожиданием.

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

Параллелизм на основе задач для Java [ править ]

Java поддерживает потоки, начиная с JDK 1.0. Java предлагает высокую гибкость для выполнения потоков, часто называемых задачами. Это делается путем реализации функционального интерфейса ( java.lang.Runnableинтерфейса), определяющего единственный метод void no-args, как показано в следующем примере:

вар  MyThread  =  новую  тема (()  ->  {  вар  threadName  =  Thread . currentThread (). GetName ();  система . из . Println ( "Hello"  +  threadName ); });myThread . start ();

Подобно C #, в Java есть механизм более высокого уровня для работы с потоками. Executorsможет выполнять асинхронные задачи, а также управлять группой подпроцессов. Все потоки ExecutorServicesэкземпляра обрабатываются в пуле . Этот ExecutorServiceэкземпляр будет повторно использоваться «под капотом» для реванантных задач, поэтому можно запускать столько параллельных задач, сколько хочет программист, на протяжении всего жизненного цикла приложения, используя один экземпляр службы-исполнителя.

Вот так выглядит первый пример потока с использованием исполнителей:

ExecutorService  исполнитель  =  Исполнители . newSingleThreadExecutor ();исполнитель . submit (()  ->  {  var  threadName  =  Thread . currentThread (). getName ();  System . out . println ( "Hello"  +  threadName ); });

ExecutorServiceЭкземпляр также поддерживает Callableинтерфейс, другой единый интерфейс метода , как , Runnableно подпись содержащегося метода Callableвозвращает значение. Таким образом, лямбда-выражение также должно возвращать значение.

общедоступный  статический  класс  SomeAsyncCode  { ExecutorService  исполнитель  =  Исполнители . newSingleThreadExecutor (); public  static  Future < String >  getContentAsync () {  исполнитель возврата  . submit (() -> { HttpRequest httpReq = HttpRequest . newBuilder () . uri ( новый URI ( "https://www.graalvm.org" )) . build ();           вернуть  HttpClient . newHttpClient ()  . отправить ( httpReq ,  BodyHandlers . ofString ())  . тело ();  });  }}var  webPageResult  =  SomeAsyncCode . getContentAsync (). получить ();

Вызов метода get() блокирует текущий поток и ожидает завершения вызываемого объекта перед возвратом значения (в примере - содержимого веб-страницы):

Дополнительные возможности [ править ]

Числовые приложения [ править ]

Для адекватной поддержки приложений в области математических и финансовых вычислений существует несколько языковых функций. [87]

Ключевое слово strictfp в Java позволяет выполнять строгие вычисления с плавающей запятой для области кода. Строгие вычисления с плавающей запятой требуют, чтобы даже если платформа обеспечивает более высокую точность вычислений, промежуточные результаты должны быть преобразованы в одинарные / двойные. Это гарантирует, что строгие вычисления с плавающей запятой возвращают точно такой же результат на всех платформах. Без строгой плавающей запятой реализация платформы может свободно использовать более высокую точность для промежуточных результатов во время вычислений. C # позволяет реализации для данной аппаратной архитектуры всегда использовать более высокую точность для промежуточных результатов, если они доступны, т. Е. C # не позволяет программисту дополнительно принудительно использовать промежуточные результаты с потенциально более низкой точностью single / double. [88]

Хотя арифметика с плавающей запятой в Java в значительной степени основана на IEEE 754 (Стандарт для двоичной арифметики с плавающей запятой), некоторые функции не поддерживаются даже при использовании модификатора strictfp, например, флаги исключений и направленные округления, возможности, предусмотренные стандартом IEEE 754 (см. Критика Java, арифметика с плавающей запятой ).

C # предоставляет встроенный десятичный тип [89], который имеет более высокую точность (но меньший диапазон), чем двойной Java / C #. Тип decimal - это 128-битный тип данных, подходящий для финансовых и денежных расчетов. Десятичный тип может представлять значения в диапазоне от 1,0 × 10 −28 до приблизительно 7,9 × 10 28 с 28–29 значащими цифрами. [90] В структуре используется перегрузка операторов C #, чтобы можно было управлять десятичными числами с помощью таких операторов, как +, -, * и /, как и с другими примитивными типами данных.

BigDecimalИ BigIntegerтипы , поставляемые с Java позволяют произвольной точности представления десятичных чисел и целых чисел соответственно. В стандартной библиотеке Java нет классов для работы с комплексными числами.

BigInteger, [3] и Complex[91] типа , снабженные C # позволяют представление и обработку произвольной точности целых и комплексных чисел соответственно. Структуры использовать C # оператора перегрузки , так что экземпляры можно манипулировать с помощью операторов , таких как +, -, *, и /, как и других примитивных типов данных. В стандартной библиотеке C # нет классов для работы с числами с плавающей запятой произвольной точности (см. Программное обеспечение для арифметики произвольной точности ).

C # может помочь математическим приложениям с checkedи uncheckedоператорами , которые позволяют включить или отключение проверки времени выполнения для арифметического переполнения для области кода.

Интегрированный языковой запрос (LINQ) [ править ]

Интегрированный запрос языка C # (LINQ) - это набор функций, разработанных для совместной работы, позволяющих выполнять запросы на языке, и является отличительной особенностью C # и Java.

LINQ состоит из следующих функций:

  • Методы расширения позволяют расширять существующие интерфейсы или классы новыми методами. Реализации могут быть общими, или интерфейс может иметь специальную реализацию.
  • Лямбды позволяют функционально выражать критерии.
  • Деревья выражений позволяют конкретной реализации захватывать лямбду как абстрактное синтаксическое дерево, а не как исполняемый блок. Это может быть использовано реализациями для представления критериев на другом языке, например, в форме предложения SQL where, как в случае, например, Linq, LINQ to SQL .
  • Анонимные типы и вывод типов поддерживают захват и работу с типом результата запроса. Запрос может как присоединяться, так и проецироваться на источники запросов, что может привести к типу результата, который не может быть назван.
  • Выражения запроса для поддержки синтаксиса, знакомого пользователям SQL .
  • Типы, допускающие значение NULL (повышенные), чтобы обеспечить лучшее соответствие с поставщиками запросов, которые поддерживают типы, допускающие значение NULL, например, SQL .

Собственная совместимость [ править ]

Функция Java Native Interface (JNI) позволяет программам Java вызывать код, отличный от Java. Однако JNI требует, чтобы вызываемый код следовал нескольким соглашениям, и налагает ограничения на используемые типы и имена. Это означает, что часто требуется дополнительный уровень адаптации между устаревшим кодом и Java. Этот код адаптации должен быть написан на языке, отличном от Java, часто на C или C ++. Java Native Access (JNA) позволяет упростить вызов собственного кода, который требует только написания кода Java, но требует снижения производительности.

Кроме того, сторонние библиотеки обеспечивают мостовую связь Java- Component Object Model (COM), например JACOB ( бесплатно ) и J-Integra для COM ( проприетарный ).

.NET Platform Invoke ( P / Invoke ) предлагает те же возможности, разрешая вызовы из C # в то, что Microsoft называет неуправляемым кодом . С помощью атрибутов метаданных программист может точно контролировать порядок упорядочивания параметров и результатов , избегая, таким образом, внешнего связующего кода, необходимого для эквивалентного JNI в Java. P / Invoke обеспечивает почти полный доступ к процедурным API (таким как Win32 или POSIX), но ограниченный доступ к библиотекам классов C ++.

Кроме того, .NET Framework также предоставляет мост .NET-COM, позволяющий доступ к COM-компонентам, как если бы они были первоклассными объектами .NET.

C # также позволяет программисту отключать обычную проверку типов и другие функции безопасности среды CLR , что затем позволяет использовать переменные-указатели . При использовании этой функции программист должен пометить код, используяunsafeключевое слово. JNI, P / Invoke и «небезопасный» код являются одинаково опасными функциями, открывая возможные дыры в безопасности и нестабильность приложения. Преимущество небезопасного управляемого кода перед P / Invoke или JNI состоит в том, что он позволяет программисту продолжать работать в знакомой среде C # для выполнения некоторых задач, которые в противном случае потребовали бы вызова неуправляемого кода. Сборка (программа или библиотека), использующая небезопасный код, должна быть скомпилирована с помощью специального переключателя и будет отмечена как таковая. Это позволяет средам выполнения принимать особые меры предосторожности перед выполнением потенциально опасного кода.

Среда выполнения [ править ]

Java (язык программирования) предназначен для выполнения на платформе Java через среду выполнения Java (JRE). Платформа Java включает виртуальную машину Java (JVM) и общий набор библиотек. Изначально JRE была разработана для поддержки интерпретируемого выполнения с окончательной компиляцией в качестве опции. Большинство сред JRE выполняют полностью или, по крайней мере, частично скомпилированные программы, возможно, с адаптивной оптимизацией . Компилятор Java создает байт-код Java . После выполнения байт-код загружается средой выполнения Java и либо интерпретируется напрямую, либо компилируется в машинные инструкции, а затем выполняется.

C # разработан для выполнения в среде CLR. CLR предназначена для выполнения полностью скомпилированного кода. Компилятор C # создает инструкции Common Intermediate Language . После выполнения среда выполнения загружает этот код и компилирует в машинные инструкции целевой архитектуры.

Примеры [ править ]

Ввод / вывод [ править ]

Пример, показывающий, как копировать текст по одной строке из одного файла в другой, используя оба языка.

Интеграция типов, определяемых библиотекой [ править ]

C # позволяет интегрировать типы, определяемые библиотекой, с существующими типами и операторами, используя настраиваемые неявные / явные преобразования и перегрузку операторов, как показано в следующем примере:

Делегаты C # и эквивалентные конструкции Java [ править ]

Тип поднятия [ править ]

Совместимость с динамическими языками [ править ]

В этом примере показано, как можно использовать Java и C # для создания и вызова экземпляра класса, реализованного на другом языке программирования. Класс «Глубокая мысль» реализован с использованием языка программирования Ruby и представляет собой простой калькулятор, который умножает два входных значения ( aи b) при Calculateвызове метода. В дополнение к традиционному способу Java имеет GraalVM , виртуальную машину, способную запускать любой реализованный язык программирования.

Последовательность Фибоначчи [ править ]

Этот пример показывает, как последовательность Фибоначчи может быть реализована с использованием двух языков. Версия C # использует преимущества методов генератора C # . Версия Java использует преимущества Streamинтерфейсов и ссылок на методы. И в Java, и в C # примерах используется стиль K&R для форматирования кода классов, методов и операторов.

См. Также [ править ]

  • Сравнение C # и VB.NET
  • Сравнение Java и C ++
  • Сравнение платформ Java и .NET
  • Язык программирования Java

Ссылки [ править ]

  1. ^ «BigDecimal (Java 2 Platform SE 5.0)» . Docs.oracle.com . Проверено 24 февраля 2015 года .
  2. ^ "Mpir.NET" . Проверено 17 июля 2015 года .
  3. ^ a b «Структура BigInteger (System.Numerics)» . Msdn.microsoft.com. 18 февраля 2015 . Проверено 24 февраля 2015 года .
  4. ^ «Коллекция (Java 2 Platform SE 5.0)» . Docs.oracle.com . Проверено 20 мая 2015 .
  5. ^ «Строка (Java 2 Platform SE 5.0)» . Docs.oracle.com . Проверено 20 мая 2015 .
  6. ^ «Математика - Руководство пользователя математики Commons - Комплексные числа» . Проверено 17 июля 2015 года .
  7. ^ «Дата (Java 2 Platform SE 5.0)» . Docs.oracle.com . Проверено 20 мая 2015 .
  8. ^ "десятичный (Справочник по C #)" . Microsoft . Проверено 30 ноября 2015 года .
  9. ^ a b c «Языковая среда Java» . Oracle.com . Проверено 18 августа 2013 года .
  10. ^ a b «Ссылки на методы (Учебники по Java> Изучение языка Java> Классы и объекты)» . Docs.oracle.com. 28 февраля 2012 . Проверено 24 февраля 2015 года .
  11. ^ Доступно только в небезопасном режиме или черезуправляемый тип IntPtr
  12. ^ Система типов унифицирована по умолчанию, если компилятор не переключен в небезопасный режим, в котором необработанные указатели доступны как тип данных. Указатели не являются производными от объекта и не имеют неявных преобразований в / из типа данных объекта.
  13. ^ "org.apache.commons.lang3.tuple (Apache Commons Lang 3.4-SNAPSHOT API)" . Commons.apache.org. 15 января 2014 . Проверено 24 февраля 2015 года .
  14. ^ Петруша, Рон. «Писатель-программист» . Сеть разработчиков Microsoft . Корпорация Microsoft . Проверено 11 сентября 2015 года .
  15. ^ "Беззнаковый целочисленный арифметический API теперь в JDK 8 (Oracle Weblog Джозефа Д. Дарси)" . Blogs.oracle.com . Проверено 24 февраля 2015 года .
  16. ^ «Типы указателей (Руководство по программированию на C #)» . Msdn.microsoft.com. 18 февраля 2015 . Проверено 24 февраля 2015 года .
  17. Джошуа Блох; Нил Гафтер (2005). Головоломки Java: ловушки, подводные камни и угловые случаи (5. печатное изд.). Река Аппер Сэдл, Нью-Джерси [ua]: Аддисон-Уэсли. п. 36. ISBN 978-0-321-33678-1. Урок для разработчиков языков состоит в том, что знаковое расширение байтовых значений является частым источником ошибок и путаницы. Маскирование, необходимое для подавления загромождения программ расширением знаков, делает их менее читаемыми. Следовательно, байтовый тип должен быть беззнаковым.CS1 maint: multiple names: authors list (link)
  18. ^ «Джеймс Гослинг на Яве, май 2001 г.» . Artima.com. 10 мая 2001 . Проверено 24 февраля 2015 года .
  19. ^ "десятичный" . Справочник по C # . Microsoft.
  20. ^ a b Сестофт, Джон Джаггер, Найджел Перри, Питер (2007). «11.1.7 Десятичный тип». C? аннотированный стандарт . Амстердам: Издательство Elsevier / Morgan Kaufmann. ISBN 978-0-12-372511-0.
  21. ^ Мок, Heng Ngee (2003). «9.5. Десятичный тип». С Java на C? : руководство разработчика . Харлоу, Англия: Эддисон-Уэсли. ISBN 978-0-321-13622-0.
  22. ^ "Enum" . Интернет: .NET Perls . Проверено 14 ноября +2016 . Спектакль. Перечисления быстрые. Они почти никогда не влияют на производительность. Это просто синтаксический сахар для такого типа, как int, что тоже быстро. […] Тип. Перечисление имеет базовый тип. Каждый раз, когда мы используем перечисление, мы используем базовый тип. У перечисления сверху есть синтаксический сахар.
  23. ^ Б Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 6 сентября 2012 года . В Java перечисляемые типы представляют собой полноценный класс, что означает, что они безопасны по типу и могут быть расширены путем добавления методов, полей или даже реализации интерфейсов. В то время как в C # перечислимый тип - это просто синтаксический сахар вокруг интегрального типа (обычно int), что означает, что они не могут быть расширены и не являются типобезопасными.
  24. Проф. Д-р Грунц, Доминик (8 апреля 2005 г.). «Java 5: Укрощение тигра: синтаксический сахар» (на немецком языке). Fachhochschule Aargau, Nordwestschweiz. Архивировано из оригинала 8 июля 2012 года . Проверено 10 сентября 2012 года . Enumerationen sind die heimlichen Sieger von Java 1.5. Nach vielen Beteuerungen durch Sun, Enums seien in Java überflüssig und können einfach nachgebildet werden, wurden sie nun doch eingeführt. Die einfachste Möglichkeit einer Enumeration der Jahreszeiten sieht wie folgt aus… Das Schlüsselwort enum steht für eine spezielle Art von Klasse, die eine Enumeration Definiert. Im Gegensatz zu anderen Programmiersprachen wie C / C ++ и C # kann man ihnen per Gleichheitszeichen keine ganzen Zahlen zuordnen.
  25. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: C. Незначительное ощущение дежавю: 4. Заявление о переключении» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 10 сентября 2012 года .
  26. ^ "goto (C #)" . Msdn.microsoft.com . Проверено 18 августа 2013 года .
  27. ^ a b "Технологическая сеть Oracle для разработчиков Java | Технологическая сеть Oracle | Oracle" . Java.sun.com. Архивировано из оригинального 27 июня 2012 года . Проверено 24 февраля 2015 года .
  28. ^ [1] Архивировано 4 марта 2009 года в Wayback Machine.
  29. ^ «Небезопасный код и указатели (Руководство по программированию на C #)» . Microsoft . Проверено 11 марта 2013 года .
  30. ^ "SortedDictionary (TKey, TValue) Класс (System.Collections.Generic)" . Msdn.microsoft.com . Проверено 18 августа 2013 года .
  31. ^ "Класс SortedSet (T) (System.Collections.Generic)" . Msdn.microsoft.com . Проверено 18 августа 2013 года .
  32. ^ "Силовые собрания" . Wintellect. 27 августа 2008 г. Проект сообщества по разработке лучших классов коллекций, безопасных для общедоступных лицензий для .NET. Power Collections активно использует .NET Generics. Цель проекта - предоставить общие классы коллекций, которые недоступны в платформе .NET. Некоторые из включенных коллекций: Deque, MultiDictionary, Bag, OrderedBag, OrderedDictionary, Set, OrderedSet и OrderedMultiDictionary. В Сила Коллекция для .NET содержит очереди приоритетов в рамках классов от и .
    OrderedBagOrderedSet
  33. ^ "Библиотека общей коллекции C5" . Архивировано из оригинала 10 декабря 2015 года С5 обеспечивает функциональные возможности и структуры данных , не предусмотренные стандартного пространством имен .Net System.Collections.Generic, такие как стойкие структуры дерева данных, очереди приоритетов на основе кучи, хэш проиндексированы списки массивов и связанные списки, и события по изменению коллекции. Кроме того, он более всеобъемлющий, чем библиотеки классов коллекций на других подобных платформах, таких как Java. В отличие от многих других библиотек классов коллекций, C5 разработан со строгой политикой поддержки «кода для интерфейса, а не реализации». Класс реализует интерфейс
    IntervalHeap<T> IPriorityQueue<T>используя интервальную кучу, хранящуюся в виде массива пар. Операции FindMin и FindMax, а также метод доступа get индексатора занимают время O (1). Операции DeleteMin, DeleteMax, Add и Update, а также set-accessor индексатора занимают время O (log n). В отличие от обычной очереди с приоритетом, интервальная куча предлагает как минимальные, так и максимальные операции с одинаковой эффективностью.
    Альтернативный URL
  34. ^ "System.Collections.Concurrent Namespace" . Microsoft . Проверено 12 марта 2013 года .
  35. ^ "foreach, в (справочник по C #)" . Microsoft. 2018. Архивировано 12 января 2019 года . Проверено 26 января 2019 . Оператор foreach выполняет оператор или блок операторов для каждого элемента в экземпляре типа, который реализует интерфейс System.Collections.IEnumerable или System.Collections.Generic.IEnumerable <T>.
  36. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: C. Когда-либо такое легкое ощущение дежавю: 6. Коллекции» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 10 сентября 2012 года .Инфраструктура коллекций Java не только имеет методы, позволяющие получать доступ к небезопасным коллекциям потокобезопасным способом, но также содержит поточно-ориентированные версии большинства структур данных. Фреймворк коллекций Java имеет ряд алгоритмов для манипулирования элементами в структурах данных, включая алгоритмы, которые могут делать следующее; найти самый большой элемент на основе некоторого компаратора, найти самый маленький элемент, найти подсписки в списке, перевернуть содержимое списка, перетасовать содержимое списка, создать неизменяемые версии коллекции, выполнить сортировку и двоичный поиск.
  37. ^ Dare Обасанджо (март 2007 г.). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: C. Когда-либо такое легкое ощущение дежавю: 6. Коллекции» . Не бойтесь Обасанджо. Архивировано из оригинального 2 -го января 2013 года . Проверено 10 сентября 2012 года . Фреймворк коллекций C # состоит из классов в System. Коллекции и пространства имен System.Collections.Generic. Пространство имен Systems.Collections содержит интерфейсыи абстрактные классы, представляющие абстрактные типы данных, такие как IList, IEnumerable, IDictionary, ICollection и CollectionBase, которые позволяют разработчикам манипулировать структурами данных независимо от того, как они фактически реализованы, если структуры данных наследуются от абстрактных типов данных. Пространство имен System.Collections также содержит некоторые конкретные реализации структур данных, такие как ArrayList, Stack, Queue, HashTable и SortedList. Все четыре реализации конкретной структуры данных позволяют получить синхронизированные оболочки для коллекции, что обеспечивает доступ в потокобезопасном режиме. Пространство имен System.Collections.Generic имеет общие реализации ключевых структур данных в пространстве имен System.Collections, включая общие List <T>, Stack <T>, Queue <T>, Dictionary <K, T>и классы SortedDictionary <K, T>.
  38. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 6 сентября 2012 года .
  39. ^ Эрик Флигал (2004). «Оптимизация с плавающей точкой Microsoft Visual C ++» . MSDN . Проверено 1 января 2016 года .
  40. ^ «JEP 378: текстовые блоки» . Дата обращения 5 августа 2020 .
  41. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: D. Теперь о чем-то совершенно другом: 13. Дословные строки» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 11 сентября 2012 года .
  42. ^ a b «Программа Java Community Process (SM) - JSR: запросы спецификации Java - деталь JSR # 14» . Jcp.org . Проверено 24 февраля 2015 года .
  43. ^ "JEP 286: Вывод типа локальной переменной" . Проверено 25 апреля 2018 года .
  44. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: D. Теперь кое-что совершенно другое: 14. Обнаружение переполнения» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 11 сентября 2012 года .
  45. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft и языка программирования Java от Sun Microsystems: такое легкое ощущение дежавю: 4. switch Statment» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 7 сентября 2012 года .
  46. ^ «Заявление о попытках с ресурсами (Учебники по Java> Основные классы> Исключения)» . Docs.oracle.com. 28 февраля 2012 . Проверено 24 февраля 2015 года .
  47. ^ Расширение создано для языка программирования Java
  48. ^ «Анонимные типы (Руководство по программированию на C #)» . Msdn.microsoft.com . Проверено 18 августа 2013 года .
  49. ^ «Спецификации Java SE» . Java.sun.com . Проверено 24 февраля 2015 года .
  50. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: перегрузка оператора» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 6 сентября 2012 года . Примечание. В отличие от C ++, C # не допускает перегрузки следующих операторов; new, (), |, &&, = или любые варианты составных присваиваний, таких как + =, - = и т. д. Однако составные операторы присваивания будут вызывать перегруженные операторы, например, + = вызовет перегруженный +.
  51. ^ "Новости Java от августа 1998 г." . Cafeaulait.org . Проверено 24 февраля 2015 года .
  52. ^ Sunwold, Corey (25 февраля 2010). "C # Эквивалент Java" final " " . Кори Санволд. Архивировано 29 ноября 2012 года . Проверено 13 сентября 2016 года . Существует более одного использования последнего ключевого слова, для которого в C # нет эквивалента. Когда вы передаете параметр методу в Java и не хотите, чтобы значение этого параметра изменялось в рамках этого метода, вы можете установить его как окончательный, например:
  53. ^ "C # - Предварительный просмотр языка AC # 6.0" . Msdn.microsoft.com . Проверено 24 февраля 2015 года .
  54. ^ Б Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: D. Теперь о чем-то совершенно другом: 15. Явная реализация интерфейса» . Не бойтесь Обасанджо. Архивировано 22 сентября 2012 года . Проверено 11 сентября 2012 года .
  55. ^ "в модификаторе параметра (Справочник по C #)" . Microsoft. 5 марта 2018. Архивировано 26 января 2019 года . Проверено 26 января 2019 .
  56. ^ Гослинг, Джеймс. «Спецификация языка Java®» . Раздел 8.4.1. Формальные параметры . Проверено 5 октября 2014 года .CS1 maint: location (link)
  57. ^ Hanselman, Скотт (4 апреля 2008). «Как работают методы расширения и почему не требовалась новая среда CLR?» . Проверено 29 марта 2014 года . Методы расширения - это действительно хороший синтаксический сахар. На самом деле они не добавляются в класс, как мы видим, но компилятор создает ощущение, что они
  58. ^ «Методы расширения (Руководство по программированию на C #)» . Microsoft . 2013 . Проверено 29 марта 2014 года . Методы расширения определяются как статические методы, но вызываются с использованием синтаксиса метода экземпляра.
  59. ^ «Спецификация языка C # версии 4.0» . Microsoft. п. 281 . Проверено 10 мая 2012 года . Если никакая часть объявления частичного типа не содержит декларации реализации для данного частичного метода, любой вызывающий его оператор выражения просто удаляется из объявления комбинированного типа. Таким образом, выражение вызова, включая любые составляющие выражения, не действует во время выполнения. Сам частичный метод также удаляется и не будет членом объявления комбинированного типа. Если для данного частичного метода существует реализующее объявление, вызовы частичных методов сохраняются. Частичный метод приводит к объявлению метода, аналогичному объявлению реализующего частичного метода, за исключением следующего: […]
  60. ^ "в модификаторе параметра (Справочник по C #)" . Microsoft. 5 марта 2018. Архивировано 26 января 2019 года . Проверено 26 января 2019 . Ключевое слово in вызывает передачу аргументов по ссылке. Это похоже на ключевые слова ref или out, за исключением того, что аргументы in не могут быть изменены вызываемым методом.
  61. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft и языка программирования Java от Sun Microsystems: D. Теперь кое-что совершенно другое: 12. Переход по ссылке» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 10 сентября 2012 года .В Java аргументы метода передаются по значению, что означает, что метод работает с копиями переданных ему элементов, а не с фактическими элементами. В C #, как и в C ++ и в некотором смысле C, можно указать, что аргументы метода фактически являются ссылками на элементы, передаваемые в метод, а не копии. Эта функция особенно полезна, когда нужно создать метод, возвращающий более одного объекта. В Java попытка вернуть несколько значений из метода не поддерживается и приводит к таким аномалиям, как: метод, который меняет местами два числа, которые были отличительной чертой курсов по информатике для новичков в течение многих лет, невозможно реализовать в Java, не прибегая к трюкам кодирования.
  62. ^ «Проблема с проверенными исключениями» . Artima.com . Проверено 24 февраля 2015 года .
  63. ^ «Форумы MSDN - язык Visual C #» . Msdn2.microsoft.com. Архивировано из оригинала 20 марта 2007 года . Проверено 24 февраля 2015 года .
  64. ^ Экель, Брюс. "Нужны ли Java проверенные исключения?" . Архивировано из оригинала 5 апреля 2002 года . Проверено 6 декабря 2012 года .
  65. ^ «Отказ и исключения» . Artima.com. 22 сентября 2003 . Проверено 18 августа 2013 года .
  66. ^ «Проверенные исключения» . Шон Абрам . Проверено 18 августа 2013 года .
  67. ^ «Спецификации Java SE» . Java.sun.com . Проверено 24 февраля 2015 года .
  68. ^ Анжелика Лангер. «Часто задаваемые вопросы по Java Generics - Часто задаваемые вопросы - Обучение / Консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 24 февраля 2015 года .
  69. Анжелика Лангер (16 апреля 2013 г.). «Часто задаваемые вопросы по Java Generics - Под капотом компилятора - Обучение / Консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 18 августа 2013 года .
  70. Анжелика Лангер (16 апреля 2013 г.). «Часто задаваемые вопросы по Java Generics - Под капотом компилятора - Обучение / Консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 18 августа 2013 года .
  71. Анжелика Лангер (16 апреля 2013 г.). «Часто задаваемые вопросы по Java Generics - Под капотом компилятора - Обучение / Консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 18 августа 2013 года .
  72. Анжелика Лангер (13 февраля 2014 г.). «Часто задаваемые вопросы по Java Generics - Параметры типа - Обучение / Консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 24 февраля 2015 года .
  73. ^ «Обобщения в C #, Java и C» . Artima.com . Проверено 24 февраля 2015 года .
  74. ^ "trove4j / Trove" . Проверено 30 июня 2017 года .
  75. ^ Нил Gafter (23 сентября 2004). «Блог Нила Гафтера: Загадки сквозь стирание: раздел ответов» . Gafter.blogspot.com . Проверено 18 августа 2013 года .
  76. ^ «Лямбда-выражения (Учебники по Java> Изучение языка Java> Классы и объекты)» . Docs.oracle.com. 28 февраля 2012 . Проверено 24 февраля 2015 года .
  77. ^ «Урок: Агрегатные операции (Учебники по Java> Коллекции)» . Docs.oracle.com. 28 февраля 2012 . Проверено 24 февраля 2015 года .
  78. ^ Грант Richins (11 мая 2009). «Улучшения хвостового вызова в .NET Framework 4» . Блоги MSDN .
  79. ^ Рихтер, Джеффри (апрель 2001 г.). «Знакомство с делегатами» . Журнал MSDN . Проверено 23 декабрю +2008 .
  80. Кэмпбелл, Дастин (9 февраля 2007 г.). "Что в закрытии?" . Сделал это с .NET . Архивировано из оригинального 15 августа 2014 года . Проверено 23 Декабрю 2 008 .
  81. ^ Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: аннотации метаданных» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 6 сентября 2012 года . Однако ключевое различие между атрибутами C # и аннотациями Java заключается в том, что в Java можно создавать мета-аннотации (т. Е. Аннотации к аннотациям), но нельзя делать то же самое в C #. Разработчики могут создавать свои собственные пользовательские аннотации, создавая тип аннотации, похожий на интерфейс, за исключением того, что для его определения используется ключевое слово @interface.
  82. ^ «Элемент» . Msdn.microsoft.com . Проверено 18 августа 2013 года .
  83. ^ «C # Assembly - Custom Reference Path - Visual C # Kicks» . Vcskicks.com . Проверено 18 августа 2013 года .
  84. ^ «Как сделать условную компиляцию с помощью Java» . weblogs.java.net. Архивировано из оригинала на 5 января 2013 года . Проверено 11 августа 2015 года .
  85. ^ Платформа Fork-join, включенная в Java версии 7. «ForkJoinPool (Java Platform SE 7)» . Оракул . Проверено 17 июля 2015 года .
  86. ^ «Библиотека параллельных задач (TPL)» . Msdn.microsoft.com. 18 февраля 2015 . Проверено 24 февраля 2015 года .
  87. ^ «Java для научных вычислений: перспективы и проблемы» (PDF) . Pds.ewi.tudelft.nl. Архивировано из оригинального (PDF) 22 сентября 2007 года . Проверено 24 февраля 2015 года .
  88. ^ «Спецификация языка C # версии 5.0» . Microsoft. 4.1.6 Типы с плавающей запятой . Проверено 28 октября 2013 года . Операции с плавающей точкой могут выполняться с более высокой точностью, чем тип результата операции. Например, некоторые аппаратные архитектуры поддерживают "расширенный" или "длинный двойной" тип с плавающей запятой с большим диапазоном и точностью, чем тип double, и неявно выполняют все операции с плавающей запятой, используя этот тип с более высокой точностью. Только при чрезмерных затратах на производительность такие аппаратные архитектуры могут быть выполнены для выполнения операций с плавающей запятой с меньшими затратами.точности, и вместо того, чтобы требовать реализации для потери производительности и точности, C # позволяет использовать тип с более высокой точностью для всех операций с плавающей запятой. Помимо получения более точных результатов, это редко дает какие-либо измеримые эффекты. Однако в выражениях вида x * y / z, где умножение дает результат, выходящий за пределы двойного диапазона, но последующее деление возвращает временный результат обратно в двойной диапазон, тот факт, что выражение оценивается в более высоком Формат диапазона может привести к получению конечного результата вместо бесконечности.
  89. ^ "десятичное против 110" . Проверено 24 февраля 2015 года .[ мертвая ссылка ]
  90. ^ «Спецификация языка C # версии 5.0» . Microsoft. 4.1.7 Десятичный тип.
  91. ^ "Комплекс" . Проверено 24 февраля 2015 года .[ мертвая ссылка ]
  92. ^ Б Dare Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: C. Незначительное ощущение дежавю: 15. Межъязыковая совместимость» . Не бойтесь Обасанджо. Архивировано из оригинального 19 сентября 2012 года . Проверено 10 сентября 2012 года . Существует несколько способов межъязыкового взаимодействия в Java. Прежде всего, это Java Native Interface (JNI)… Java также имеет возможность взаимодействовать с распределенными объектами, которые используют архитектуру брокера общих запросов объектов (CORBA) через Java IDL. … C # и среда выполнения .NET были созданы с целью обеспечения бесшовной межъязыковой совместимости.
  93. ^ «Типы JNI и структуры данных» . Docs.oracle.com . Проверено 9 апреля 2020 .
  94. ^ {{цитировать в Интернете | url = https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#performance-and-interop | title = Указатели на функции в C # 9 | publisher = docs.microsoft.com | access-date = 27 февраля 2021 г.}
  95. ^ "Создание объединений C / C ++ в C #" . docs.microsoft.com . Проверено 27 февраля 2021 года .

Внешние ссылки [ править ]

  • Переход на C # и .NET Framework в MSDN
  • C # и Java: сравнение языков программирования в MSDN
  • Java против C # - код для сравнения кода
  • Итоги работы на девяти языках
  • Microsoft Developer Network (MSDN): язык программирования C # для разработчиков Java
  • Стандартная спецификация языка C # ECMA-334
  • Спецификация языка Java (Sun)
  • Состояние C #: по-прежнему ли он жизнеспособен?