Jump to content

Сравнение C Sharp и Java

(Перенаправлено из «Сравнение Java и C Sharp» )

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

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

Типы данных Ява С#
Десятичные дроби произвольного размера Тип ссылки; нет операторов [ 1 ] Сторонняя библиотека [ 2 ]
Целые числа произвольного размера Тип ссылки; нет операторов Да [ 3 ]
Массивы Да [ 4 ] Да
Логический тип Да Да
Характер Да [ 5 ] Да
Комплексные числа Сторонняя библиотека [ 6 ] Да
Дата/время Да; ссылочный тип [ 7 ] Да; тип значения
Перечислимые типы Да; ссылочный тип Да; скаляр
Высокоточное десятичное число Нет; но см. «Десятичные дроби произвольного размера» выше. 128-битный (28 цифр) десятичный тип [ 8 ]
IEEE 754 двоичное число 32 с плавающей запятой Да Да
IEEE 754 двоичное число 64 с плавающей запятой Да Да
Поднятые (обнуляемые) типы Нет; но типы оберток Да
Указатели Нет; [ 9 ] только ссылки на методы [ 10 ] Да [ 11 ]
Типы ссылок Да Да
Целые числа со знаком Да; 8 , 16 , 32 , 64 бита Да; 8, 16, 32, 64 бита
Струны Неизменяемый ссылочный тип, Unicode Неизменяемый ссылочный тип, Unicode
Введите аннотации Да Да
Однокорневая (унифицированная) система типов Нет; но типы оберток Да [ 12 ]
Кортежи Нет; доступно ограниченное количество сторонних производителей [ 13 ] Да [ 14 ] [ 15 ]
Беззнаковые целые числа Нет; но поддержка некоторых методов [ 16 ] Да; 8, 16, 32, 64 бита
Типы значений Нет; только примитивные типы Да

Единая система типов

[ редактировать ]

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

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

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

Простые типы C# реализуют несколько интерфейсов и, следовательно, предлагают множество методов непосредственно для экземпляров типов, даже для литералов. Имена типов C# также являются просто типов псевдонимами CLR . С# System.Int64 тип точно такой же, как и длинный тип; единственная разница состоит в том, что первое — это каноническое имя .NET , а второе — его псевдоним C#.

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

Типы данных

[ редактировать ]

Числовые типы

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

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

Беззнаковые целые числа
[ редактировать ]

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

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

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

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

В версиях Java 8 и 9 добавлены некоторые ограниченные встроенные целочисленные операции без знака, но они доступны только как статические методы в примитивных классах-оболочках; они работают со знаковыми примитивными целочисленными типами, рассматривая их так, как если бы они были беззнаковыми. [ 20 ]

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

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

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

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

[ редактировать ]

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

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

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

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

Персонажи

[ редактировать ]

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

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

[ редактировать ]

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

Библиотеки обоих языков определяют классы для работы с датами, временем, часовыми поясами и календарями в разных культурах. Java предоставляет java.util.Date, изменяемый ссылочный тип с точностью до миллисекунды и (начиная с Java 8) java.time пакет (включая такие классы, как ЛокальнаяДата , Местное время и LocalDateTime для значений только даты, только времени и даты и времени), набор неизменяемых ссылочных типов с точностью до наносекунды . [ 24 ] Напротив, C# System.DateTime — это неизменяемый тип значения структуры для информации о дате и времени с точностью до 100 наносекунд; также добавлен API .NET 6 System.DateOnly и System.TimeOnly, аналогичные структуры для операций только с датой или только со временем. [ 25 ] C# дополнительно определяет System.TimeSpan тип для работы с периодами времени; Java 8 предоставляет java.time.Duration класс с той же целью. Оба языка поддерживают арифметику даты и времени в соответствии с различными культурами и часовыми поясами.

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

[ редактировать ]

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

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

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

Перечисления

[ редактировать ]

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

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

Ява С#
Определение В Java типом перечисления является класс , а его значениями являются объекты (экземпляры) этого класса. Единственными допустимыми значениями являются те, которые указаны в перечислении. Тип перечисления может объявлять поля , позволяя каждому отдельному перечисляемому значению ссылаться на дополнительные данные, однозначно связанные с этим конкретным значением. Тип перечисления может также объявлять или переопределять методы или реализовывать интерфейсы . [ 27 ] Перечисления в C# неявно выводятся из Тип перечисления , который снова является производным типа значения. Набор значений перечисления C# определяется базовым типом , который может быть целым числом со знаком или без знака длиной 8, 16, 32 или 64 бита. Определение перечисления определяет имена для выбранных целочисленных значений. [ 27 ] [ 28 ] По умолчанию первому имени присваивается значение 0 (ноль), а следующим именам присваиваются с шагом 1. Любое значение базового примитивного типа является допустимым значением перечислимого типа, хотя для его присвоения может потребоваться явное приведение типов. .
Объединение Набор перечислений Java и коллекции карт предоставляют функциональные возможности для объединения нескольких значений перечисления в объединенное значение. Эти специальные коллекции позволяют оптимизировать компилятор, чтобы минимизировать накладные расходы, возникающие при использовании коллекций в качестве механизма комбинирования. C# поддерживает побитовые перечисления, где фактическое значение может представлять собой комбинацию побитовых или объединенных вместе перечисляемых значений. Методы форматирования и синтаксического анализа, неявно определенные типом, попытаются использовать эти значения.

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

Делегаты, ссылки на методы

[ редактировать ]

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

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

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

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

Поднятые (обнуляемые) типы

[ редактировать ]

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

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

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

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

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

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

Поздний (динамический) тип

[ редактировать ]

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

Существует несколько вариантов использования динамический тип в C#:

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

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

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

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

Указатели

[ редактировать ]

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

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

Типы ссылок

[ редактировать ]

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

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

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

Типы ссылок Ява С#
Сбор мусора Да Да
Слабые ссылки Да Да
Очередь ссылок (взаимодействие со сборкой мусора) Да Да
Мягкие ссылки Да Нет
Фантомные ссылки Да Нет
Поддержка прокси Да; генерация прокси Да; контексты объектов

Массивы и коллекции

[ редактировать ]

Массивы и коллекции — это концепции, используемые в обоих языках.

Массивы и коллекции Ява С#
Абстрактные типы данных Да Да
Одномерные индексные массивы с отсчетом от нуля Да Да
Многомерные массивы, прямоугольные (одиночный массив) Нет Да
Многомерные массивы зубчатые (массивы массивов) Да Да
Массивы с ненулевым индексом Нет Некоторый
Унифицированные массивы и коллекции Нет Да
Карты/словари Да Да
Сортированные словари Да Да [ 34 ]
Наборы Да Да
Сортированные наборы Да Да [ 35 ]
Списки/векторы Да Да
Очереди/стеки Да Да
Приоритетная очередь Да Да [ 36 ]
Сумки/мультисеты Сторонняя библиотека Да
Коллекции, оптимизированные для параллелизма Да Да [ 37 ]

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

Ява С#
Массивы являются неявно прямой специализацией Объект . Они не унифицированы с типами коллекций. Массивы в C# — это неявная специализация System.Array класс, реализующий несколько интерфейсов коллекции .
Массивы и коллекции полностью разделены и не подлежат унификации. Массивы не могут передаваться там, где ожидаются последовательности или коллекции (хотя их можно обернуть с помощью Arrays.asList). Массивы могут передаваться там, где последовательности ( IEnumerable коллекций/списков s) или интерфейсы Ожидаются . Однако операции сбора, которые изменяют количество элементов (вставка/добавление/удаление), будут вызывать исключения, поскольку эти операции не поддерживаются массивами.
The Оператор for принимает либо массивы, либо Итерируемый с. Все коллекции реализуют Итерируемый . Это означает, что в циклах for можно использовать тот же краткий синтаксис. The Оператор foreach выполняет итерацию по последовательности, используя конкретную реализацию GetEnumerator , обычно реализуемый через IEnumerable или IEnumerable<T> интерфейс . [ 38 ] Поскольку массивы всегда неявно реализуют эти интерфейсы , цикл также будет проходить через массивы.
В обоих языках массивы ссылочных типов ковариантны. Это означает, что String[] массив присваивается переменным Object[], как Строка — это специализация (назначаемая) Объект . В обоих языках массивы будут выполнять проверку типа при вставке новых значений, поскольку в противном случае безопасность типов будет нарушена. Это контрастирует с тем, как общие коллекции были реализованы на обоих языках.
Никаких многомерных массивов (прямоугольные массивы), а массивы ссылок на массивы ( зубчатые массивы ). Многомерные массивы (прямоугольные массивы) и массивы ссылок на массивы ( зубчатые массивы ).
Размер массивов не может быть изменен (хотя использование System.arraycopy() метод может позволять многоэтапное изменение размера массива) Размер массивов можно изменить, сохраняя существующие значения, используя команду Array.Resize() метод статического массива (но он может вернуть новый массив).
Реализован в модернизации качестве java.util библиотека, имеющая дополнительные функции, такие как структуры данных, такие как наборы и связанные наборы, и несколько алгоритмов для управления элементами коллекции, например, поиск самого большого элемента на основе некоторых Comparator<T> объект, поиск наименьшего элемента, поиск подсписков в списке, изменение содержимого списка, перемешивание содержимого списка, создание неизменяемых версий коллекции, выполнение сортировки и двоичный поиск. [ 39 ] Платформа коллекций C# состоит из классов из System.Collections и System.Collections.Generic пространства имен с несколькими полезными интерфейсами , абстрактными классами и структурами данных. [ 40 ] NET 3.5 добавлен System.Linq пространство имен, содержащее различные методы расширения для запроса коллекций, такие как Совокупный , Все , Средний , Отчетливый , Присоединиться , Союз и многие другие. Запросы, использующие эти методы, называются языковыми интегрированными запросами (LINQ).

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

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

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

C# предоставляет два разных метода создания типов кортежей (также известных как типы продуктов ). Первый — через System.Tuple классы, которые представляют собой неизменяемые ссылочные типы, предоставляемые API платформы (начиная с .NET Framework 4.0) для создания универсальных типов кортежей. [ 14 ] Этот первый метод с тех пор был эффективно заменен вторым, System.ValueTuple структуры, которые представляют собой изменяемые типы значений, предоставляемые API платформы (начиная с .NET Framework 4.7). [ 15 ]

Хотя эти два метода внешне кажутся похожими, у них есть несколько заметных различий. Типы ValueTuple являются типами значений, поэтому они занимают более компактный объем памяти; также, Типы ValueTuple предоставляют свое содержимое как изменяемые поля, в отличие от неизменяемых свойств типа ValueTuple. Кортежные классы. Наконец, начиная с версии C# 7.0, язык имеет встроенную синтаксическую поддержку для создания, деконструкции и манипулирования кортежами, как Экземпляры ValueTuple ; это также обеспечивает произвольное переименование составляющих полей кортежей (в отличие от Tuple , где поля всегда имеют имена Товар1 , Пункт2 и т. д.).

Java не предоставляет типы кортежей как часть своего языка или стандартного API; существуют многочисленные сторонние библиотеки, которые могут предоставлять типы кортежей, [ 41 ] но все они обязательно похожи на C# System.Tuple занятия. По сравнению с С# Типы ValueTuple и связанный с ними синтаксис более громоздки в использовании (требуют явного использования конструкторов или статических фабричных методов для их создания, требуют доступа к отдельным членам для их деконструкции и имеют фиксированные имена для их элементов).

Выражения и операторы

[ редактировать ]
Выражения и операторы Ява С#
Арифметические операторы Да Да
Логические операторы Да Да
Побитовые логические операторы Да Да
Условный Да Да
Конкатенация строк Да Да
Строковая интерполяция Да; Начиная с Java 21 ( подробности ) Да [ 42 ]
Дословные (здесь-) строки Да [ 43 ] Да [ 44 ]
В ролях Да Да
Бокс Да; скрытый Да; скрытый
Распаковка Да; скрытый Да; явный
Поднятые операторы Нет; Видеть java.util.Необязательно Да
Контроль переполнения Нет Да
Строгая оценка с плавающей запятой Да; подписка/выход Да; подписка [ 45 ]

Упаковка и распаковка

[ редактировать ]

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

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

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

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

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

Заявления

[ редактировать ]
Заявления Ява С#
Петли Да Да
Условные предложения Да Да
Управление потоком Да Да
Назначение Да Да
Контроль исключений Да Да
Объявление переменной Да Да
Вывод типа переменной Да [ 47 ] Да
Детерминированная утилизация (ARM-блоки) Да Да

Синтаксис

[ редактировать ]

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

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

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

[ редактировать ]

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

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

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

ключевое слово функция, пример использования
проверено , непроверенный В С#, Проверенные во время выполнения блоки операторов или выражения могут включать проверку арифметического переполнения . [ 48 ]
получать , набор C# реализует свойства как часть синтаксиса языка с необязательными соответствующими им свойствами. получить и установите средства доступа в качестве альтернативы методам доступа , используемым в Java, которые не являются особенностью языка, а шаблоном кодирования, основанным на соглашениях об именах методов.
перейти к C# поддерживает goto ключевое слово. Иногда это может быть полезно, например, для реализации конечных автоматов или для сгенерированного кода использование более структурированного метода потока управления , но обычно рекомендуется (см. критику оператора goto ). Java не поддерживает оператор перехода (но goto — зарезервированное слово). Однако Java поддерживает помеченные перерыв и операторы continue , которые в определенных ситуациях могут использоваться, когда goto В противном случае можно было бы использовать оператор .
switch (color)
{
    case Color.Blue:
        Console.WriteLine("Color is blue");
        break;
    case Color.DarkBlue:
        Console.WriteLine("Color is dark");
        goto case Color.Blue;
    // ...
}
замок В C# Ключевое слово блокировки — это сокращение для синхронизации доступа к блоку кода между потоками (с использованием Монитор ), завернутый в пытаться ... наконец заблокируйте.
вне , ссылка В C# имеется поддержка выходных и ссылочных параметров . Они позволяют возвращать несколько выходных значений из метода или передавать значения по ссылке.
строгий фп Java использует strictfp чтобы гарантировать, что результаты операций с плавающей запятой остаются одинаковыми на разных платформах.
выключатель В C# оператор switch также работает со строками и длинными значениями. Провал допускается для пустых операторов и возможен через «перейти к регистру» для операторов, содержащих код. Оператор переключения Java работает со строками (начиная с Java 7 ), но не с длинный примитивный тип и не выполняется для всех операторов (за исключением тех, у которых есть ' перерыв '). [ 49 ]
синхронизированный На Яве Ключевое слово синхронизировано — это сокращение для синхронизации доступа к блоку кода между потоками (с использованием Монитор ), завернутый в пытаться ... наконец заблокируйте.
бросает Java требует, чтобы каждый метод объявлял проверенные исключения или суперклассы проверенных исключений, которые он может генерировать. Любой метод также может при желании объявить выдаваемое им непроверяемое исключение. В C# нет такого синтаксиса.
public int readItem() throws java.io.IOException {
    // ...
}
с использованием В С#, использование вызывает Метод Dispose (реализуемый через IDisposable интерфейс ) объекта, объявленного для выполнения после запуска блока кода или при возникновении исключения внутри блока кода.
// Create a small file "test.txt", write a string,
// ... and close it (even if an exception occurs)
using (var file = new StreamWriter("test.txt"))
{
    file.Write("test");
}

В Java SE 7 добавлена ​​аналогичная конструкция. [ 50 ] называется try-with-resources:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

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

[ редактировать ]

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

Ориентация объекта Ява С#
Классы обязательный обязательный
Интерфейсы Да Да
Абстрактные классы Да Да
Уровни доступа участников общедоступный, пакетный, защищенный, частный публичный, внутренний, защищенный, частный, защищенный внутренний
уровня класса Внутренние классы Да Да
Внутренние классы уровня экземпляра Да Нет
уровня оператора (локальные) Анонимные классы Да Да; но без методов
Частичные занятия Нет; Сторонняя библиотека [ 51 ] Да
Неявные (выводимые) анонимные классы Нет; Не требуется Да [ 52 ]
Устаревание /устаревание Да Да
Перегрузка версий Некоторый Да
Перечисления могут реализовывать интерфейсы Да Нет
Характеристики Нет Да
События Предоставляется стандартными библиотеками Встроенная языковая функция
Перегрузка оператора Нет Да
Индексаторы Нет Да
Неявные преобразования Нет; но см. автобокс Да
Явные преобразования Да Да

Частичный класс

[ редактировать ]

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

Внутренние и локальные классы

[ редактировать ]

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

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

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

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

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

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

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

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

[ редактировать ]

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

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

Индексатор

[ редактировать ]

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

myList[4] = 5;
string name = xmlNode.Attributes["name"];
orders = customerMap[theCustomer];

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

Поля и инициализация

[ редактировать ]
Поля и инициализация Ява С#
Поля Да Да
Константы Да Да; но нет поддержки постоянных передаваемых параметров [ 56 ]
(классов) Статические конструкторы Да Да
Конструкторы экземпляров Да Да
Финализаторы/деструкторы Да Да
Инициализаторы экземпляров Да Нет; можно моделировать с помощью конструктора экземпляра
объекта Инициализация Вверх дном
(поля и конструкторы)
Сверху вниз (поля); снизу вверх (конструкторы)
Инициализаторы объектов Да Да
Инициализаторы коллекций Статические методы с переменными аргументами Да
Инициализаторы массивов Да Да

Инициализация объекта

[ редактировать ]

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

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

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

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

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

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

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

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

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

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

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

Утилизация ресурсов

[ редактировать ]

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

Методы и свойства Ява С#
Статический импорт Да Да [ 57 ]
Виртуальные методы Виртуальный по умолчанию Невиртуальный по умолчанию
Абстрактный Да Да
Уплотнение Да Да
Явная реализация интерфейса Методы по умолчанию Да [ 58 ]
Значения (входные) параметры Да Да
Эталонные (входные/выходные) параметры Нет Да
Выходные (выходные) параметры Нет Да
Постоянные (неизменяемые) параметры Да; окончательные параметры Да [ 59 ]
Вариадические методы Да Да
Необязательные аргументы Нет; [ 60 ] Вместо этого перегрузка метода или varargs Да
Именованные аргументы Да; с аннотациями Да
Методы генератора Нет; но см. Stream Api Да
Методы расширения/по умолчанию Да Да
Условные методы Нет Да
Частичные методы Нет Да

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

[ редактировать ]

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

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

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

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

Частичные методы

[ редактировать ]

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

Виртуальные методы

[ редактировать ]

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

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

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

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

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

Постоянные/неизменяемые параметры

[ редактировать ]

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

Ява С#
public int addOne(final int x) {
    x++; // ERROR: a final variable cannot be reassigned
    return x;
}

public List addOne(final List<Integer> list) {
    list.add(1); // OK: it is still possible to modify a
                 // final (reference type) variable
    return list;
}
public int AddOne(in int x) 
{
    x++; // ERROR: a readonly parameter cannot be reassigned
    return x;
}

public List<int> AddOne(in List<int> list) 
{
    list.Add(1); // OK: it is still possible to modify a
                 // readonly (reference type) parameter
    return list;
}

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

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

Методы генератора

[ редактировать ]

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

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

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

Явная реализация интерфейса

[ редактировать ]

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

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

Эталонные (входные/выходные) параметры

[ редактировать ]

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

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

Ява С#
class PassByRefTest {

    static class Ref<T> {
        T val;
        Ref(T val) { this.val = val; }
    }
    
    static void changeMe(Ref<String> s) {
        s.val = "Changed";
    }

    static void swap(Ref<Integer> x, Ref<Integer> y) {
        int temp = x.val;

        x.val = y.val;
        y.val = temp;
    }

    public static void main(String[] args) {
        var a = new Ref(5);
        var b = new Ref(10);
        var s = new Ref("still unchanged");
        
        swap(a, b);
        changeMe(s);

        System.out.println( "a = " + a.val + ", " +
                            "b = " + b.val + ", " +
                            "s = " + s.val );
    }
}
class PassByRefTest 
{
    public static void ChangeMe(out string s) 
    {
        s = "Changed";
    }

    public static void Swap(ref int x, ref int y) 
    {
        int temp = x;

        x = y;
        y = temp;
    }

    public static void Main(string[] args) 
    {
        int a = 5;
        int b = 10;
        string s = "still unchanged";

        Swap(ref a, ref b);
        ChangeMe(out s);

        System.Console.WriteLine("a = " + a + ", " +
                                 "b = " + b + ", " +
                                 "s = " + s);
    }
}
a = 10, b = 5, s = Changed a = 10, b = 5, s = Changed

Исключения

[ редактировать ]
Исключения Ява С#
Проверенные исключения Да Нет
Попробуй-поймай-наконец Да Да
Фильтры исключений Нет Да [ 66 ]

Проверенные исключения

[ редактировать ]

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

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

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

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

Попробуй-поймай-наконец

[ редактировать ]

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

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

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

class Foo {
    Exception up = new Exception();
    int foo() throws Exception {
        throw up;
    }
}

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

class Foo
{
    Exception e = new Exception();

    int foo()
    {
        try
        {
            throw e;
        }
        catch (Exception e)
        {
            throw;
        }
    }
}

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

Наконец блоки

[ редактировать ]

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

int foo() {
    try {
        return 0;
    } finally {
        return 1;
    }
}

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

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

Дженерики

[ редактировать ]

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

Дженерики Ява С#
Выполнение Тип стирания реификация
Реализация во время выполнения Нет Да
Тип отклонения Использование сайта Сайт-декларация (только на интерфейсах)
Ограничение ссылочного типа Да; скрытый Да
Ограничение значения/примитивного типа Нет Да
Ограничение конструктора Нет Да
(только для конструктора без параметров)
Ограничение подтипа Да Да
Ограничение супертипа Да Нет
Совместимость миграции Да Нет

Стирание типов и реифицированные дженерики

[ редактировать ]

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

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

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

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

Ява С#
Проверки типов и приведения типов вводятся в клиентский код (код, ссылающийся на дженерики). По сравнению с неуниверсальным кодом с ручным приведением эти приведения будут одинаковыми. [ 74 ] но по сравнению с кодом, проверенным во время компиляции, который не требует приведения и проверок во время выполнения, эти операции представляют собой накладные расходы на производительность. Обобщенные шаблоны C#/.NET гарантируют безопасность типов и проверяются во время компиляции, поэтому дополнительные проверки/приведения не нужны во время выполнения. Следовательно, универсальный код будет работать быстрее, чем неуниверсальный код (или код со стиранием типа), который требует приведения типов при обработке неуниверсальных объектов или объектов со стиранием типа.
Невозможно использовать примитивные типы в качестве параметров типа; вместо этого разработчик должен использовать тип оболочки, соответствующий примитивному типу. Это влечет за собой дополнительные издержки производительности, поскольку требуются преобразования упаковки и распаковки, а также нагрузка на память и сборку мусора, поскольку оболочки будут распределяться в куче, а не в стеке. Примитивные типы и типы значений разрешены в качестве параметров типа в универсальных реализациях. Во время выполнения код будет синтезирован и скомпилирован для каждой уникальной комбинации параметров типа при первом использовании. Обобщенные шаблоны, реализованные с использованием примитивного типа/типа значения, не требуют преобразований упаковки/распаковки.
Общие исключения не допускаются. [ 75 ] и параметр типа нельзя использовать в предложении catch [ 76 ] Можно как определять общие исключения, так и использовать их в предложениях catch.
Статические члены являются общими для всех общих реализаций. [ 77 ] (при стирании типа все реализации сводятся в один класс) Статические члены являются отдельными для каждой общей реализации. Общая реализация — это уникальный класс.
Параметры типа нельзя использовать в объявлениях статических полей/методов или в определениях статических внутренних классов. Нет ограничений на использование параметров типа.
Невозможно создать массив, в котором тип компонента является общей реализацией (конкретный параметризованный тип).
Pair<String, String>[] tenPairs = new Pair[10]; //OK
Общая реализация является гражданином 1-го класса и может использоваться как любой другой класс; также компонент массива
object tenPairs = new Pair<int, string>[10]; // OK
Невозможно создать массив, в котором тип компонента является параметром типа, но можно создать Object array и выполните приведение типов к новому массиву для достижения того же эффекта.
public class Lookup<K, V> {
    public V[] getEmptyValues(K key) {
        return (V[]) new Object[0]; // OK
    }
}

Если параметр универсального типа находится под ограничениями наследования, вместо этого можно использовать тип ограничения. Object

public class Lookup<K, V extends Comparable<V>> {
    public V[] getEmptyValues(K key) {
        return (V[]) new Comparable[0];
    }
}
Параметры типа представляют собой фактические дискретные классы и могут использоваться как любой другой тип в рамках общего определения.
public class Lookup<K, V>
{
    public V[] GetEmptyValues(K key)
    {
        return new V[0]; // OK
    }
}
Не существует литерала класса для конкретной реализации универсального типа. Общая реализация — это реальный класс.
Instanceof не допускается с параметрами типа или конкретными универсальными реализациями. The есть и поскольку операторы для параметров типа работают так же, как и для любого другого типа.
Невозможно создать новые экземпляры, используя параметр типа в качестве типа. С помощью ограничения конструктора универсальные методы или методы универсальных классов могут создавать экземпляры классов, которые имеют конструкторы по умолчанию.
Информация о типе стирается во время компиляции. Для обнаружения исходного типа необходимо использовать специальные расширения отражения. Информация о типах универсальных типов C# полностью сохраняется во время выполнения и обеспечивает полную поддержку отражения и создание экземпляров универсальных типов.
Рефлексию нельзя использовать для построения новых общих реализаций. Во время компиляции дополнительный код (приведение типов) вводится в клиентский код дженериков. Это исключает создание новых реализаций позже. Отражение можно использовать для создания новых реализаций для новых комбинаций параметров типа.

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

Совместимость миграции

[ редактировать ]

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

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

Ковариантность и контравариантность

[ редактировать ]

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

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

[ редактировать ]
Функциональное программирование Ява С#
Ссылки на методы Да [ 10 ] Да
Замыкания Все лямбды не открывают новый уровень области видимости. Все ссылочные переменные должны быть фактически окончательными. Да
Лямбда-выражения Да [ 81 ] Да
Деревья выражений Нет Да
Общий язык запросов/API Да; API Java Stream (Монада) [ 82 ] Да
Оптимизация компилятора хвостовой рекурсии Нет [ 83 ] Только на х64 [ 84 ]

Замыкания

[ редактировать ]

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

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

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

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

Лямбды и деревья выражений

[ редактировать ]

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

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

Метаданные

[ редактировать ]
Метаданные Ява С#
Аннотации/атрибуты метаданных На основе интерфейса; могут быть созданы пользовательские аннотации [ 87 ] На основе классов
Позиционные аргументы Нет; если только один аргумент Да
Именованные аргументы Да Да
Значения по умолчанию По определению Через инициализацию
Вложенные типы Да Да
Специализация Нет Да
Условные метаданные Нет Да

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

[ редактировать ]
Предварительная обработка , компиляция и упаковка Ява С#
Пространства имен Пакеты Пространства имен
Содержимое файла Ограниченный Бесплатно
Упаковка Упаковка общедоступная/внутренняя видимость членов пространства имен, которые система сборки преобразует в модули и сборки на уровне CLR.
Путь поиска классов/сборок Путь к классу И время компиляции, и время выполнения [ 88 ] [ 89 ]
Условная компиляция Нет; но см. Apache Ant [ 90 ] Да
Пользовательские ошибки/предупреждения Да; Процессор аннотаций Да
Явные регионы Нет Да

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

[ редактировать ]

В 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() может быть импортированным методом расширения, работающим с типом фу ).

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

Условная компиляция

[ редактировать ]

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

Многопоточность и асинхронные функции

[ редактировать ]

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

Многопоточность и синхронизация Ява С#
Темы Да Да
Пул потоков Да Да
Параллелизм на основе задач Да [ 91 ] Да [ 92 ]
Семафоры Да Да
Мониторы Да Да
Локальные переменные потока Да Да; ThreadStaticAttribute и ThreadLocal<T> сорт

Параллелизм на основе задач для C#

[ редактировать ]

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

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

public static class SomeAsyncCode
{
    public static Task<XDocument> GetContentAsync()
    {
        HttpClient httpClient = new HttpClient();
        return httpClient.GetStringAsync("www.contoso.com").ContinueWith((task) => {
            string responseBodyAsText = task.Result;
            return XDocument.Parse(responseBodyAsText);
        });
    }
}

var t = SomeAsyncCode.GetContentAsync().ContinueWith((task) => {
    var xmlDocument = task.Result;
});

t.Start();

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

public static class SomeAsyncCode
{
    public static async Task<XDocument> GetContentAsync()
    {
        HttpClient httpClient = new HttpClient();
        string responseBodyAsText = await httpClient.GetStringAsync("www.contoso.com");
        return XDocument.Parse(responseBodyAsText);
    }
}

var xmlDocument = await SomeAsyncCode.GetContentAsync();

// The Task will be started on call with await.

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

Параллелизм на основе задач для Java

[ редактировать ]

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

var myThread = new Thread(() -> {
    var threadName = Thread.currentThread().getName();
    System.out.println("Hello " + threadName);
});

myThread.start();

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

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

ExecutorService executor = Executors.newSingleThreadExecutor();

executor.submit(() -> {
    var threadName = Thread.currentThread().getName();
    System.out.println("Hello " + threadName);
});

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

ExecutorService executor = Executors.newSingleThreadExecutor();

Future<String> contentAsync = executor.submit(() -> {           
    HttpRequest httpReq = HttpRequest.newBuilder()
        .uri(new URI("www.graalvm.org"))
        .build();
            
    return HttpClient.newHttpClient()
        .send(httpReq, BodyHandlers.ofString())
        .body();
});
   
var webPageResult = contentAsync.get();

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

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

public static class SomeAsyncCode {

    static ExecutorService executor = Executors.newSingleThreadExecutor();

    public static Future<String> getContentAsync(){
        return executor.submit(() -> {           
            HttpRequest httpReq = HttpRequest.newBuilder()
                .uri(new URI("www.graalvm.org"))
                .build();
            return HttpClient.newHttpClient()
                .send(httpReq, BodyHandlers.ofString())
                .body();
        });
    }
}

var webPageResult = SomeAsyncCode.getContentAsync().get();

Дополнительные возможности

[ редактировать ]

Числовые приложения

[ редактировать ]

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

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

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

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

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

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

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

Языковой интегрированный запрос (LINQ)

[ редактировать ]

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

LINQ включает в себя следующие функции:

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

Встроенная совместимость

[ редактировать ]
Встроенная совместимость Ява С#
Межъязыковая совместимость Да (с GraalVM , Nashorn , CORBA , JNI или JNA ) [ 98 ] Да; C# был разработан для этого [ 98 ]
Внешние/родные методы Да Да
сортировка Требуется внешний код клея Да; контролируемые метаданные
Указатели и арифметика Нет; но см. sun.misc.Unsafe Да
Родные типы Да [ 99 ] Да
Буферы фиксированного размера Нет Да
Явное распределение стека Нет Да
Адрес-из Нет Да
Закрепление объекта (фиксация переменной по адресу) Нет Да
Указатели функций Нет Да [ 100 ]
Союзы Нет Да [ 101 ]

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

Кроме того, библиотеки сторонних производителей обеспечивают соединение Java- компонентной объектной модели (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 , что затем позволяет использовать переменные-указатели . При использовании этой функции программист должен пометить код с помощью значка небезопасное ключевое слово. JNI, P/Invoke и «небезопасный» код — одинаково опасные функции, обнажающие возможные дыры в безопасности и нестабильность приложения. Преимущество небезопасного управляемого кода перед P/Invoke или JNI заключается в том, что он позволяет программисту продолжать работать в знакомой среде C# для выполнения некоторых задач, которые в противном случае потребовали бы вызова неуправляемого кода. Сборка (программа или библиотека), использующая небезопасный код, должна быть скомпилирована со специальным ключом и будет помечена как таковая. Это позволяет средам выполнения принимать особые меры предосторожности перед выполнением потенциально опасного кода.

Среды выполнения

[ редактировать ]

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

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

Ввод/вывод

[ редактировать ]

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

Ява С#
import java.nio.file.*;

class FileIOTest {

    public static void main(String[] args) throws Exception {
        var lines = Files.readAllLines(Paths.get("input.txt"));
        Files.write(Paths.get("output.txt"), lines);
    }
}
using System.IO;

class FileIOTest
{
    public static void Main(string[] args)
    {
        var lines = File.ReadLines("input.txt");
        File.WriteAllLines("output.txt", lines);
    }
}
Примечания к реализации Java:
  • Files.readAllLines метод возвращает список строк с содержимым текстового файла. В Files также есть метод readAllBytes возвращает массив Струны .
  • Files.write Метод записывает массив байтов или в выходной файл, указанный объектом Path.
  • Files.write Метод также заботится о буферизации и закрытии выходного потока.
Примечания к реализации C#:
  • The Метод ReadLines возвращает перечислимый объект, который при перечислении будет читать файл по одной строке за раз.
  • The Метод WriteAllLines принимает перечисляемое, извлекает по одной строке и записывает ее до тех пор, пока перечисление не завершится.
  • Базовый модуль чтения автоматически выделит буфер, поэтому нет необходимости явно вводить буферизованный поток.
  • WriteAllLines автоматически закрывает выходной поток, в том числе в случае аварийного завершения.

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

[ редактировать ]

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

Ява С#
var bigNumber =
    new BigInteger("123456789012345678901234567890");

var answer = bigNumber.multiply(BigInteger.valueOf(42));
var square = bigNumber.sqrt();
var sum = bigNumber.add(bigNumber);
var bigNumber =
    BigInteger.Parse("123456789012345678901234567890");

var answer = bigNumber * 42;
var square = bigNumber * bigNumber;
var sum = bigNumber + bigNumber;

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

[ редактировать ]
Ява С#
// a target class
class Target {
    public boolean targetMethod(String arg) {
        // do something
        return true;
    }
}

// usage
void doSomething() {
    // construct a target with the target method
    var target = new Target();

    // capture the method reference
    Function<String, Boolean> ivk = target::targetMethod;

    // invokes the referenced method
    var result = ivk.apply("argumentstring");
}
    // a target class
    class Target
    {
        public bool TargetMethod(string arg)
        {
            // do something
            return true;
        }
    }

    // usage
    void DoSomething()
    {
        // construct a target with the target method
        var target = new Target();

        // capture the delegate for later invocation
        Func<string, bool> dlg = target.TargetMethod;

        // invoke the delegate
        bool result = dlg("argumentstring");
    }

Тип подъемный

[ редактировать ]
Ява С#

Java не имеет этой функции, хотя аналогичный эффект возможен при использовании Дополнительный класс

var a = Optional.of(42);
var b = Optional.<Integer>empty();

var c = a.flatMap(aa -> b.map(bb -> aa * bb));
int? a = 42;
int? b = null;

// c will receive the null value
// because*is lifted and one of the operands are null
int? c = a * b;

Взаимодействие с динамическими языками

[ редактировать ]

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

Ява С#

Использование GraalVM

[ редактировать ]
Context polyglot = Context.newBuilder().allowAllAccess(true).build();

//Ruby
Value rubyArray = polyglot.eval("ruby", "[1,2,42,4]");
int rubyResult = rubyArray.getArrayElement(2).asInt();

//Python
Value pythonArray = polyglot.eval("python", "[1,2,42,4]");
int pythonResult = pythonArray.getArrayElement(2).asInt();

//JavaScript
Value jsArray = polyglot.eval("js", "[1,2,42,4]");
int jsResult = jsArray.getArrayElement(2).asInt();

//R
Value rArray = polyglot.eval("R", "c(1,2,42,4)");
int rResult = rArray.getArrayElement(2).asInt();

//LLVM (in this case C, but could be C++, Go, Basic, etc...)
Source source = Source.newBuilder("llvm", new File("C_Program.bc")).build();
Value cpart = polyglot.eval(source);
cpart.getMember("main").execute();

Традиционный способ

[ редактировать ]
// Initialize the engine
var invocable = new ScriptEngineManager().getEngineByName("jruby");
var rubyFile = new FileReader("Deepthought.rb");
engine.eval(fr);
// create a new instance of "Deepthought" calculator
var calcClass = engine.eval("Deepthought");
var calc = invocable.invokeMethod(calcClass, "new");

// set calculator input values
invocable.invokeMethod(calc, "a=", 6);
invocable.invokeMethod(calc, "b=", 7);

// calculate the result
var answer = invocable.invokeMethod(calc, "Calculate");
// Initialize the engine

var runtime = ScriptRuntime.CreateFromConfiguration();
dynamic globals = runtime.Globals;

runtime.ExecuteFile("Deepthought.rb");
// create a new instance of "Deepthought" calculator
var calc = globals.Deepthought.@new();

// set calculator input values
calc.a = 6;
calc.b = 7;

// calculate the result
var answer = calc.Calculate();

Примечания к реализации Java:

  • Имена средств доступа Ruby генерируются из имени атрибута с помощью = суффикс. При назначении значений разработчики Java должны использовать имя метода доступа Ruby.
  • Динамические объекты иностранного языка не являются первоклассными объектами, поскольку ими необходимо манипулировать через API.

Примечания к реализации C#:

  • Объекты, возвращаемые свойствами или методами динамические объекты сами по себе динамический тип. Когда вывод типа ( ключевое слово var ), переменные Calc и Answer выводятся динамически/с поздней привязкой.
  • Динамические объекты с поздними границами являются первоклассными гражданами, которыми можно манипулировать с помощью синтаксиса C#, даже если они созданы на внешнем языке.
  • новый — зарезервированное слово. @ Префикс позволяет использовать ключевые слова в качестве идентификаторов.

Последовательность Фибоначчи

[ редактировать ]

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

Ява С#
// The Fibonacci sequence
Stream.generate(new Supplier<Integer>() {
    int a = 0;
    int b = 1;

    public Integer get() {
        int temp = a;
        a = b;
        b = a + temp;
        return temp;
    }
}).limit(10).forEach(System.out::println);
// The Fibonacci sequence
public IEnumerable<int> Fibonacci() 
{
    int a = 0;
    int b = 1;

    while (true) 
    {
        yield return a;
        (a, b) = (b, a + b);
    }
}
// print the 10 first Fibonacci numbers
foreach (var it in Fibonacci().Take(10)) 
{
    Console.WriteLine(it);
}
Примечания к версии Java:
  • Интерфейс Java 8 Stream представляет собой последовательность элементов, поддерживающих последовательные и параллельные агрегатные операции.
  • Метод генерации возвращает бесконечный последовательный неупорядоченный поток, в котором каждый элемент генерируется предоставленным Поставщиком.
  • Метод limit возвращает поток, состоящий из элементов этого потока, усеченных до длины не более maxSize.
  • Метод forEach выполняет действие для каждого элемента этого потока, это действие может быть лямбда-выражением или ссылкой на метод.

Использование foreach

[ редактировать ]

Тот же пример выше, но с использованием метода, возвращающего Iterable, для обеспечения большего сходства с примером C#. Все, что реализует итерируемый интерфейс, может быть повторено в foreach.

Iterable<Integer> fibonacci(int limit) {
    return Stream.generate(new Supplier<Integer>() {
        int a = 0;
        int b = 1;
        
        public Integer get() {
            int temp = a;
            a = b;
            b = a + temp;
            return temp;
        }
    }).limit(limit)::iterator;
}
// print the 10 first Fibonacci numbers
for(int it: fibonacci(10)) {
    System.out.println(it);
}

Самый распространенный способ реализовать приведенный выше пример — использовать потоки, а не Iterables. Его можно вернуть из такого метода, как в примере C#, но в этом нет необходимости, и его можно использовать напрямую, просто собрав Stream.

Ниже приведен пример использования потоков и сбора вызовов потоков. toList в блоке foreach.

var fibonacci = Stream.generate(new Supplier<Integer>() {
    int a = 0;
    int b = 1;
            
    public Integer get() {
        int temp = a;
        a = b;
        b = a + temp;
        return temp;
    }
});
// print the 10 first Fibonacci numbers
for(int it: fibonacci.limit(10).toList()) {
    System.out.println(it);
}

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

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

Функциональный стиль

[ редактировать ]

Приведенный выше алгоритм можно записать еще более последовательно, используя Stream.iterate. Метод итерации получает начальный параметр и функцию, которая определяет, что делать для каждой итерации. В этом случае начальным числом может быть класс записи с двумя начальными значениями алгоритма и соответствующим преобразованием на каждой итерации. Короче говоря, метод итерации делает ненужной реализацию Поставщика.

record Pair(int a, int b) {};

Stream
  .iterate(new Pair(0, 1), p -> new Pair(p.b, p.a + p.b))
  .limit(10)
  .map(p -> p.a)
  .forEach(System.out::println);
Примечания для версии C#:
  • Метод определен как возвращающий экземпляры интерфейса. IEnumerable<int>, что позволяет клиентскому коду повторно запрашивать следующий номер последовательности.
  • The yield Ключевое слово преобразует метод в метод-генератор.
  • The yield return Оператор возвращает следующий номер последовательности и создает продолжение, чтобы последующие вызовы IEnumerable интерфейс MoveNext метод продолжит выполнение со следующего оператора со всеми локальными переменными.
  • Присвоение кортежа позволяет избежать необходимости создавать и использовать временную переменную при обновлении значений переменных. а и б .

См. также

[ редактировать ]
  1. ^ «BigDecimal (платформа Java 2 SE 5.0)» . Docs.oracle.com . Проверено 24 февраля 2015 г.
  2. ^ «Мпир.НЕТ» . Проверено 17 июля 2015 г.
  3. ^ Перейти обратно: а б «Структура BigInteger (System.Numerics)» . Learn.microsoft.com . Проверено 14 апреля 2023 г.
  4. ^ «Коллекция (платформа Java 2 SE 5.0)» . Docs.oracle.com . Проверено 20 мая 2015 г.
  5. ^ «Строка (платформа Java 2 SE 5.0)» . Docs.oracle.com . Проверено 20 мая 2015 г.
  6. ^ «Математика – Руководство пользователя Commons Math – Комплексные числа» . Проверено 17 июля 2015 г.
  7. ^ «Дата (платформа Java 2 SE 5.0)» . Docs.oracle.com . Проверено 20 мая 2015 г.
  8. ^ «десятичный (Справочник по C#)» . Майкрософт . Проверено 30 ноября 2015 г.
  9. ^ Перейти обратно: а б с «Языковая среда Java» . Oracle.com . Проверено 18 августа 2013 г.
  10. ^ Перейти обратно: а б «Ссылки на методы (Учебные пособия по Java > Изучение языка Java > Классы и объекты)» . Документы.oracle.com. 28 февраля 2012 года . Проверено 24 февраля 2015 г.
  11. ^ Доступно только в небезопасном режиме или через IntPtr. управляемый тип
  12. ^ Система типов по умолчанию унифицирована, если только компилятор не переключен в небезопасный режим , где необработанные указатели доступны в качестве типа данных. Указатели не являются производными от объекта и не имеют неявных преобразований в/из типа данных объекта.
  13. ^ «org.apache.commons.lang3.tuple (API Apache Commons Lang 3.4-SNAPSHOT)» . Commons.apache.org. 15 января 2014 года . Проверено 24 февраля 2015 г.
  14. ^ Перейти обратно: а б «Класс кортежа (система)» . Learn.microsoft.com . Корпорация Майкрософт . Проверено 20 апреля 2023 г.
  15. ^ Перейти обратно: а б «Типы кортежей (ссылка на C#)» . Learn.microsoft.com . Корпорация Майкрософт . Проверено 20 апреля 2023 г.
  16. ^ «API беззнаковых целочисленных арифметических операций теперь в JDK 8 (блог Oracle Джозефа Д. Дарси)» . Блоги.oracle.com. Архивировано из оригинала 25 февраля 2017 года . Проверено 24 февраля 2015 г.
  17. ^ «Небезопасный код, типы указателей и указатели на функции» . Learn.microsoft.com. 29 мая 2022 г. Проверено 14 апреля 2023 г.
  18. ^ Джошуа Блох; Нил Гафтер (2005). Головоломки Java: ловушки, ловушки и угловые случаи (5-е печатное изд.). Река Аппер-Сэддл, Нью-Джерси [ua]: Аддисон-Уэсли. п. 36. ISBN  978-0-321-33678-1 . Урок для разработчиков языка заключается в том, что знаковое расширение байтовых значений является распространенным источником ошибок и путаницы. Маскирование, необходимое для подавления расширения знаков, загромождает программы, делая их менее читабельными. Следовательно, тип байта должен быть беззнаковым. {{cite book}}: CS1 maint: несколько имен: список авторов ( ссылка )
  19. ^ «Джеймс Гослинг на Яве, май 2001 года» . Артима.com. 10 мая 2001 года . Проверено 24 февраля 2015 г.
  20. ^ «Целое число (платформа Java SE 8)» . Docs.oracle.com . Проверено 20 апреля 2023 г.
  21. ^ «десятичный» . Справочник по С# . Майкрософт. 19 августа 2012 г.
  22. ^ Перейти обратно: а б Сестофт, Джон Джаггер, Найджел Перри, Питер (2007). «11.1.7 Десятичный тип». С? аннотированный стандарт . Амстердам: Издательство Elsevier/Morgan Kaufmann. ISBN  978-0-12-372511-0 . {{cite book}}: CS1 maint: несколько имен: список авторов ( ссылка )
  23. ^ Мок, Хенг Нги (2003). «9.5. Десятичный тип». С Java на C? : руководство разработчика . Харлоу, Англия: Аддисон-Уэсли. ISBN  978-0-321-13622-0 .
  24. ^ «Пакет java.time (Java Platform SE 8)» . docs.oracle.com . Проверено 20 апреля 2023 г.
  25. ^ «Как использовать структуры DateOnly и TimeOnly» . Learn.microsoft.com. 12 января 2023 г. Проверено 20 апреля 2023 г.
  26. ^ «Энум» . Интернет: .NET Perls . Проверено 14 ноября 2016 г. Производительность. Перечисления выполняются быстро. Они почти никогда не вызывают проблем с производительностью. Это просто синтаксический сахар для типа типа int, который также работает быстро. […] Тип. Перечисление имеет базовый тип. Каждый раз, когда мы используем перечисление, мы используем базовый тип. Перечисление имеет синтаксический сахар сверху.
  27. ^ Перейти обратно: а б Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems» . Дэйр Обасанджо. Архивировано из оригинала 17 декабря 2001 года . Проверено 6 сентября 2012 г. В Java перечисляемые типы представляют собой полноценный класс, что означает, что они типобезопасны и могут быть расширены путем добавления методов, полей или даже реализации интерфейсов. В то время как в C# перечислимый тип представляет собой просто синтаксический сахар вокруг целочисленного типа (обычно int), что означает, что они не могут быть расширены и не являются типобезопасными.
  28. ^ Проф. Др. Грунц, Доминик (8 апреля 2005 г.). «Java 5: Укрощение тигра: синтаксический сахар» (на немецком языке). Университет прикладных наук Аргау, Северо-Западная Швейцария. Архивировано из оригинала 8 июля 2012 года . Проверено 10 сентября 2012 г. Перечисления — тайные победители Java 1.5. После многочисленных заверений Sun в том, что перечисления не нужны в Java и их можно легко воссоздать, теперь они были введены. Самый простой способ перечислить времена года заключается в следующем... Ключевое слово enum представляет особый тип класса, который определяет перечисление. ... В отличие от других языков программирования, таких как C/C++ и C#, им нельзя присваивать целые числа с помощью знака равенства.
  29. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: C. Очень легкое ощущение дежавю: 4. Оператор Switch» . Дэйр Обасанджо. Архивировано из оригинала 19 сентября 2012 года . Проверено 10 сентября 2012 г.
  30. ^ "перейти (C#)" . Msdn.microsoft.com . Проверено 18 августа 2013 г.
  31. ^ Перейти обратно: а б «Технологическая сеть Oracle для разработчиков Java | Технологическая сеть Oracle | Oracle» . Java.sun.com. Архивировано из оригинала 27 июня 2012 года . Проверено 24 февраля 2015 г.
  32. ^ Как использовать JavaFX в вашем приложении Swing. Архивировано 4 марта 2009 г. на Wayback Machine.
  33. ^ «Небезопасный код и указатели (Руководство по программированию на C#)» . Майкрософт . Проверено 11 марта 2013 г.
  34. ^ «Класс SortedDictionary<TKey,TValue> (System.Collections.Generic)» . Learn.microsoft.com . Проверено 20 апреля 2023 г.
  35. ^ «Класс SortedSet<T> (System.Collections.Generic)» . Learn.microsoft.com . Проверено 20 апреля 2023 г.
  36. ^ «Класс PriorityQueue<TElement,TPriority> (System.Collections.Generic)» . Learn.microsoft.com . Проверено 20 апреля 2023 г.
  37. ^ «System.Collections.Concurrent Namespace» . Learn.microsoft.com . Проверено 20 апреля 2023 г.
  38. ^ "foreach, in (ссылка на C#)" . Майкрософт. 2018. Архивировано из оригинала 12 января 2019 года . Проверено 26 января 2019 г. Оператор foreach выполняет оператор или блок операторов для каждого элемента экземпляра типа, который реализует System.Collections.IEnumerable или Интерфейс System.Collections.Generic.IEnumerable<T> .
  39. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C # от Microsoft с языком программирования Java от Sun Microsystems: C. Очень легкое ощущение дежавю: 6. Коллекции» . Дэйр Обасанджо. Архивировано из оригинала 19 сентября 2012 года . Проверено 10 сентября 2012 г. Платформа коллекций Java не только имеет методы, позволяющие получать доступ к небезопасным коллекциям потокобезопасным способом, но также содержит потокобезопасные версии большинства структур данных. Платформа коллекций Java имеет ряд алгоритмов для управления элементами в структурах данных, включая алгоритмы, которые могут выполнять следующие действия: найти самый большой элемент на основе некоторого компаратора, найти самый маленький элемент, найти подсписки в списке, перевернуть содержимое списка, перетасовать содержимое списка, создать неизменяемые версии коллекции, выполнить сортировку и двоичный поиск.
  40. ^ Дэйр Обасанджо (март 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 и Сортированный список . Все четыре конкретные реализации структур данных позволяют получить синхронизированные оболочки для коллекции, обеспечивающие доступ к ней потокобезопасным способом. Пространство имен System.Collections.Generic содержит общие реализации ключевых структур данных в пространстве имен System.Collections, включая общие Список<T> , Стек<T> , Очередь<T> , Словарь<K,T> и Классы SortedDictionary<K,T> .
  41. ^ "javatuples" . Проверено 20 апреля 2023 г.
  42. ^ «Интерполяция строк с использованием $» . Learn.microsoft.com. 8 апреля 2023 г. Проверено 20 апреля 2023 г.
  43. ^ «JEP 378: Текстовые блоки» . Проверено 5 августа 2020 г.
  44. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: D. Теперь о чем-то совершенно другом: 13. Дословные строки» . Дэйр Обасанджо. Архивировано из оригинала 19 сентября 2012 года . Проверено 11 сентября 2012 г.
  45. ^ Эрик Флигал (2004). «Оптимизация Microsoft Visual C++ с плавающей запятой» . MSDN . Проверено 1 января 2016 г.
  46. ^ Перейти обратно: а б «Программа Java Community Process (SM) – JSR: запросы спецификаций Java – подробно JSR № 14» . Jcp.org . Проверено 24 февраля 2015 г.
  47. ^ «JEP 286: Вывод типа локальной переменной» . Проверено 25 апреля 2018 г.
  48. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: D. Теперь о чем-то совершенно другом: 14. Обнаружение переполнения» . Архивировано из оригинала 22 сентября 2012 года . Проверено 11 сентября 2012 г.
  49. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: очень легкое ощущение дежавю: 4. Switch Statement [ sic . Архивировано из оригинала 22 сентября 2012 года . Проверено 7 сентября 2012 г.
  50. ^ «Операция try-with-resources (Учебные руководства по Java > Основные классы > Исключения)» . Документы.oracle.com. 28 февраля 2012 года . Проверено 24 февраля 2015 г.
  51. ^ Расширение, созданное для языка программирования Java.
  52. ^ «Анонимные типы (основы C#)» . Learn.microsoft.com . Проверено 14 апреля 2013 г.
  53. ^ «Спецификации Java SE» . Java.sun.com . Проверено 24 февраля 2015 г.
  54. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: перегрузка операторов» . Дэйр Обасанджо. Архивировано из оригинала 19 сентября 2012 года . Проверено 6 сентября 2012 г. Примечание. В отличие от C++, C# не допускает перегрузку следующих операторов; new, ( ), ||, &&, = или любые варианты составных присваиваний, например +=, -= и т. д. Однако составные операторы присваивания будут вызывать перегруженные операторы, например, += вызовет перегрузку + .
  55. ^ «Новости Java за август 1998 г.» . Cafeaulait.org . Проверено 24 февраля 2015 г.
  56. ^ Санволд, Кори (25 февраля 2010 г.). «C# Эквивалент «финальной версии» Java » . Кори Санволд. Архивировано из оригинала 29 ноября 2012 года . Проверено 13 сентября 2016 г. Ключевое слово Final используется более чем в одном случае, для которого в C# нет эквивалента. Когда вы передаете параметр методу в Java и не хотите, чтобы значение этого параметра менялось в пределах области действия этого метода, вы можете установить его как окончательный следующим образом:
  57. ^ «Предварительный просмотр языка C# – AC# 6.0» . Learn.microsoft.com. июль 2015 года . Проверено 14 апреля 2023 г.
  58. ^ Перейти обратно: а б Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: D. Теперь о чем-то совершенно другом: 15. Явная реализация интерфейса» . Дэйр Обасанджо. Архивировано из оригинала 22 сентября 2012 года . Проверено 11 сентября 2012 г.
  59. ^ "в модификаторе параметра (Справочник по C#)" . Майкрософт. 5 марта 2018 г. Архивировано из оригинала 26 января 2019 г. . Проверено 26 января 2019 г.
  60. ^ Гослинг, Джеймс. «Спецификация языка Java®» . Раздел 8.4.1. Формальные параметры . Проверено 5 октября 2014 г. {{cite web}}: CS1 maint: местоположение ( ссылка )
  61. ^ Генсельман, Скотт (4 апреля 2008 г.). «Как работают методы расширения и почему не потребовалась новая CLR?» . Проверено 29 марта 2014 г. Методы расширения — действительно хороший синтаксический сахар. Как мы видим, на самом деле они не добавляются в класс, но компилятор создает ощущение, что они добавлены.
  62. ^ «Методы расширения (Руководство по программированию на C#)» . Майкрософт . 2013 . Проверено 29 марта 2014 г. Методы расширения определяются как статические методы, но вызываются с использованием синтаксиса метода экземпляра.
  63. ^ «Спецификация языка C# версии 4.0» . Майкрософт. п. 281 . Проверено 10 мая 2012 г. Если ни одна часть объявления частичного типа не содержит объявления реализации для данного частичного метода, любой оператор-выражение, вызывающий его, просто удаляется из объявления комбинированного типа. Таким образом, выражение вызова, включая любые составляющие выражения, не оказывает никакого эффекта во время выполнения. Сам частичный метод также удаляется и не будет членом объявления комбинированного типа. Если для данного частичного метода существует объявление реализации, вызовы частичных методов сохраняются. Частичный метод порождает объявление метода, аналогичное реализующему объявлению частичного метода, за исключением следующего: […]
  64. ^ "в модификаторе параметра (Справочник по C#)" . Майкрософт. 5 марта 2018 г. Архивировано из оригинала 26 января 2019 г. . Проверено 26 января 2019 г. Ключевое слово in позволяет передавать аргументы по ссылке. Это похоже на ключевые слова ref или out, за исключением того, что аргументы in не могут быть изменены вызываемым методом.
  65. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: D. Теперь о чем-то совершенно другом: 12. Передача по ссылке» . Дэйр Обасанджо. Архивировано из оригинала 19 сентября 2012 года . Проверено 10 сентября 2012 г. В Java аргументы метода передаются по значению, что означает, что метод работает с копиями переданных ему элементов, а не с реальными элементами. В C#, как и в C++ и в некотором смысле C, можно указать, что аргументы метода на самом деле являются ссылками на элементы, передаваемые в метод, а не копиями. Эта функция особенно полезна, когда нужно создать метод, возвращающий более одного объекта. В Java попытка вернуть несколько значений из метода не поддерживается и приводит к таким аномалиям, как: метод, который меняет местами два числа, что было отличительной чертой курсов информатики для первокурсников в течение многих лет, невозможно реализовать в Java, не прибегая к уловкам кодирования.
  66. ^ «Исключительная фильтрация исключений» . Плюралсайт® . Проверено 24 июня 2022 г.
  67. ^ «Проблема с проверенными исключениями» . Artima.com . Проверено 24 февраля 2015 г.
  68. ^ «Форумы Msdn — язык Visual C#» . Msdn2.microsoft.com. Архивировано из оригинала 20 марта 2007 года . Проверено 24 февраля 2015 г.
  69. ^ Экель, Брюс. «Нужны ли в Java проверенные исключения?» . Архивировано из оригинала 5 апреля 2002 года . Проверено 6 декабря 2012 г.
  70. ^ «Неудачи и исключения» . Артима.com. 22 сентября 2003 года . Проверено 18 августа 2013 г.
  71. ^ «Проверенные исключения» . Шон Абрам . Проверено 18 августа 2013 г.
  72. ^ «Спецификации Java SE» . Java.sun.com . Проверено 24 февраля 2015 г.
  73. ^ Анжелика Лангер. «Часто задаваемые вопросы по Java Generics – Часто задаваемые вопросы – Обучение/консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 24 февраля 2015 г.
  74. ^ Анжелика Лангер (16 апреля 2013 г.). «Часто задаваемые вопросы по Java Generics – Под капотом компилятора – Обучение/консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 18 августа 2013 г.
  75. ^ Анжелика Лангер (16 апреля 2013 г.). «Часто задаваемые вопросы по Java Generics – Под капотом компилятора – Обучение/консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 18 августа 2013 г.
  76. ^ Анжелика Лангер (16 апреля 2013 г.). «Часто задаваемые вопросы по Java Generics – Под капотом компилятора – Обучение/консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 18 августа 2013 г.
  77. ^ Анжелика Лангер (13 февраля 2014 г.). «Часто задаваемые вопросы по Java Generics – Параметры типа – Обучение/консультации Анжелики Лангер» . AngelikaLanger.com . Проверено 24 февраля 2015 г.
  78. ^ «Обобщенные шаблоны в C#, Java и C» . Artima.com . Проверено 24 февраля 2015 г.
  79. ^ «trove4j / Трова» . Проверено 30 июня 2017 г.
  80. ^ Нил Гафтер (23 сентября 2004 г.). «Блог Нила Гафтера: Загадки через стирание: раздел ответов» . Gafter.blogspot.com . Проверено 18 августа 2013 г.
  81. ^ «Лямбда-выражения (Учебные пособия по Java > Изучение языка Java > Классы и объекты)» . Документы.oracle.com. 28 февраля 2012 года . Проверено 24 февраля 2015 г.
  82. ^ «Урок: Агрегированные операции (Учебные пособия по Java > Коллекции)» . Документы.oracle.com. 28 февраля 2012 года . Проверено 24 февраля 2015 г.
  83. ^ Бруно, Эрик (7 ноября 2022 г.). «Кудрявые скобки №6: оптимизация рекурсии и хвостовых вызовов» . Архивировано из оригинала 17 июля 2024 года . Проверено 17 июля 2024 г.
  84. ^ Грант Ричинс (11 мая 2009 г.). «Усовершенствования хвостового вызова в .NET Framework 4» . Блоги MSDN .
  85. ^ Рихтер, Джеффри (апрель 2001 г.). «Введение в делегатов» . Журнал MSDN . Проверено 23 декабря 2008 г.
  86. ^ Кэмпбелл, Дастин (9 февраля 2007 г.). «Что в закрытии?» . Сделал это с .NET . Архивировано из оригинала 15 августа 2014 года . Проверено 23 декабря 2008 г.
  87. ^ Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: аннотации метаданных» . Дэйр Обасанджо. Архивировано из оригинала 19 сентября 2012 года . Проверено 6 сентября 2012 г. Однако ключевое различие между атрибутами C# и аннотациями Java заключается в том, что можно создавать метааннотации (т. е. аннотации к аннотациям) в Java, но нельзя делать то же самое в C#. Разработчики могут создавать свои собственные аннотации, создавая тип аннотации, аналогичный интерфейсу, за исключением того, что для его определения используется ключевое слово @interface.
  88. ^ «Элемент» . Msdn.microsoft.com . Проверено 18 августа 2013 г.
  89. ^ «Сборка C# — пользовательский путь ссылки — возможности Visual C#» . Vcskicks.com . Проверено 18 августа 2013 г.
  90. ^ «Как выполнить условную компиляцию в Java» . weblogs.java.net. Архивировано из оригинала 5 января 2013 года . Проверено 11 августа 2015 г.
  91. ^ Платформа fork-join включена в Java версии 7. «ForkJoinPool (платформа Java SE 7)» . Оракул . Проверено 17 июля 2015 г.
  92. ^ «Библиотека параллельных задач (TPL)» . Msdn.microsoft.com. 18 февраля 2015 года . Проверено 24 февраля 2015 г.
  93. ^ «Java для научных вычислений: перспективы и проблемы» (PDF) . Pds.ewi.tudelft.nl. Архивировано из оригинала (PDF) 22 сентября 2007 года . Проверено 24 февраля 2015 г.
  94. ^ «Спецификация языка C# версии 5.0» . Майкрософт. 4.1.6 Типы с плавающей запятой . Проверено 28 октября 2013 г. Операции с плавающей запятой могут выполняться с более высокой точностью, чем тип результата операции. Например, некоторые аппаратные архитектуры поддерживают тип с плавающей запятой «extended» или «long double» с большим диапазоном и точностью, чем тип double, и неявно выполняют все операции с плавающей запятой, используя этот тип с более высокой точностью. Только при чрезмерных затратах на производительность такие аппаратные архитектуры могут выполнять операции с плавающей запятой с меньшей точностью, и вместо того, чтобы требовать от реализации потери как в производительности, так и в точности, C# позволяет использовать тип более высокой точности для всех операций с плавающей запятой. . Помимо получения более точных результатов, это редко имеет какой-либо измеримый эффект. Однако в выражениях вида x*y/z, где умножение дает результат, выходящий за пределы двойного диапазона, но последующее деление возвращает временный результат обратно в двойной диапазон, тот факт, что выражение оценивается в более высоком диапазоне Формат диапазона может привести к получению конечного результата вместо бесконечности.
  95. ^ «десятичное число против 110» . Проверено 24 февраля 2015 г. [ мертвая ссылка ]
  96. ^ «Спецификация языка C# версии 5.0» . Майкрософт. 4.1.7 Десятичный тип.
  97. ^ "Сложный" . Проверено 24 февраля 2015 г. [ мертвая ссылка ]
  98. ^ Перейти обратно: а б Дэйр Обасанджо (2007). «Сравнение языка программирования C# от Microsoft с языком программирования Java от Sun Microsystems: C. Очень легкое ощущение дежавю: 15. Межъязыковая совместимость» . Дэйр Обасанджо. Архивировано из оригинала 19 сентября 2012 года . Проверено 10 сентября 2012 г. В Java существует несколько способов межъязыковой совместимости. Прежде всего, существует собственный интерфейс Java (JNI)… Java также имеет возможность взаимодействовать с распределенными объектами, которые используют архитектуру брокера запросов общих объектов (CORBA) через Java IDL. … C# и среда выполнения .NET были созданы с целью обеспечения беспрепятственного межъязыкового взаимодействия.
  99. ^ «Типы JNI и структуры данных» . Docs.oracle.com . Проверено 9 апреля 2020 г.
  100. ^ «Указатели на функции в C# 9» . docs.microsoft.com . Проверено 27 февраля 2021 г.
  101. ^ «Создание объединений C/C++ в C#» . docs.microsoft.com . Проверено 27 февраля 2021 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 56aa50473b723e82fdb5a5b4469b008e__1723226880
URL1:https://arc.ask3.ru/arc/aa/56/8e/56aa50473b723e82fdb5a5b4469b008e.html
Заголовок, (Title) документа по адресу, URL1:
Comparison of C Sharp and Java - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)