Автоупаковка и автораспаковка


Содержание

Почему мы используем autoboxing и unboxing в Java?

Autoboxing — это автоматическое преобразование, которое компилятор Java делает между примитивными типами и их соответствующей оберткой объекта классы. Например, преобразование int в Integer, двойное к Двойной и т.д. Если преобразование идет другим путем, это называется unboxing.

Итак, зачем нам это нужно и почему мы используем autoboxing и unboxing в Java?

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

Примитивы против классов

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

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

Это свойство переменных класса делает ссылки на них взаимозаменяемыми (в некоторой степени). Это позволяет нам делать то, что мы называем заменой: в широком смысле использовать экземпляр определенного типа в качестве экземпляра другого связанного типа (например, используйте String как Object ).

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

Дженерики и стирание типов

Общие типы — это типы с одним или несколькими параметрами типа (точное число называется общей арностью). Например, определение типового типа List имеет параметр типа T , который может быть Object (создающий конкретный тип List ), String ( List ), Integer ( List ) и т.д.

Общие типы намного сложнее, чем не общие. Когда они были введены в Java (после его первоначального выпуска), чтобы избежать радикальных изменений в JVM и, возможно, нарушить совместимость со старыми двоичными файлами, создатели Java решили внедрить родовые типы наименее инвазивным способом:/strong > все конкретные типы List на самом деле скомпилированы в (двоичный эквивалент) List (для других типов граница может быть чем-то отличным от Object , но вы получаете эту точку). Общая информация о параметрах arty и type теряется в этом процессе, поэтому мы называем это type erasure.

Поместите два вместе

Теперь проблема заключается в сочетании вышеуказанных реалий: если List становится List во всех случаях, тогда T всегда должен быть типом, который может быть непосредственно назначен Object . Ничего другого нельзя разрешить. Поскольку, как мы уже говорили ранее, int , float и double не взаимозаменяемы с Object , не может быть List , List или List (если только значительно более сложный реализация дженериков существовала в JVM).

Но Java предлагает такие типы, как Integer , float и double , которые переносят эти примитивы в экземпляры классов, делая их эффективно заменяемыми как Object , таким образом позволяет родовые типы косвенно работать с примитивами (потому что вы можете иметь List , List , List и т.д.).

Процесс создания Integer из int , a float из a float и т.д. называется boxing. Реверс называется распаковкой. Поскольку наличие полевых примитивов каждый раз, когда вы хотите использовать их как Object , неудобно, есть случаи, когда язык делает это автоматически — который называется autoboxing.

java — Что в приоритете: автоупаковка или автораспаковка?

Вопрос: что делает компилятор со строкой (*) ? Не понимаю, то ли распаковывает t , то ли упаковывает s .
Мудрый человек, пишет что здесь идёт «autoboxing», но с ним мне не связаться и я не знаю почему он так пишет.
Могу предположить только, что раз в сравнении у нас нашёлся Object some_obj , коим является Integer t , то идёт сравнение по ссылкам, и int s автоупаковывается.
Из результатов программы: t==s — правда. Не знаю почему так. Вроде потому, что есть какой-то метод, который для Integer , String и подобных им приводит объект к некоторому виду, заменяя ссылку на такой же по натуре объект, чтобы == работало. К примеру две «разных» строки, например: «Hello» и «Hello» после вызова этого метода в сравнении == дают true .

Итого: очень хочу увидеть какое-то документальное объяснение происходящего, что к чему приводится, и почему результат строки (*) есть false , что в принципе значит: t и s равны. Но в каком понимании они равны? Ссылок, чисел. Байт-код мне не помог, там не понять как проходит это сравнение.

    5 2
  • 30 янв 2020 2020-01-30 20:58:26
  • Direct

2 ответа

Легко проверяется экспериментально.


Через исключение при unboxingе nullа: https://ideone.com/ltbefI

В обоих случаях выводится:

  • 30 янв 2020 2020-01-30 21:47:28
  • Qwertiy

Происходит распаковывание t (то есть преобразование из Integer в int ) с последующим обычным сравнением примитивов (то есть значений типа int ).

Чтобы понять почему так происходит обратимся к спецификации Java.

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).

Если операнды оператора сравнения оба имеют числовой тип, или один из операндов является числовым типом, а второй может быть преобразован в числовой тип, то операнды подвергаются binary numeric promotion.

В случае сравнения int и Integer операнд типа int является примитивным типом, а операнд типа Integer может быть преобразован в числовой тип. В принципе не важно, как переводится binary numeric promotion, важно лишь что при этом выполняются действия описанные в соответствующем разделе JLS 5.6.2:

If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).

Если один из операндов является ссылочным типом, то происходит распаковывание.

В нашем случае распаковывается Integer и получается int . Далее обычным способом сравниваются два примитива (значения типа int ).

Автоупаковка и автораспаковка

Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!

Автоупаковка и автораспаковка
Изучение новых функциональных возможностей, включенных в последнюю версию Java 2 5.0, начнем с так долго ожидаемых всеми программистами на языке Java автоупаковки (autoboxing) и автораспаковки (auto-unboxing). Выбор этот сделан по трем причинам. Во-первых, автоупаковка/автораспаковка сильно упрощает и рационализирует исходный код, в котором требуется объектное представление базовых типов языка Java, таких как int или char. Поскольку такие ситуации часто встречаются в текстах программ на Java, выигрыш от применения средств автоупаковки/распаковки получат практически все, программирующие на этом языке. Во-вторых, автоупаковка/автораспаковка во многом способствует простоте и удобству применения другого нового средства — настройки типов (generics). Следовательно, понимание автоупаковки и автораспаковки понадобится для последующего изучения этого механизма. В-третьих, автоупаковка/распаковка плавно изменяет наши представления о взаимосвязи объектов и данных базовых типов. Эти изменения гораздо глубже, чем может показаться на первый взгляд из-за концептуальной простоты двух описываемых здесь новых функциональных возможностей. Их влияние ощущается во всем языке Java.
Автоупаковка и автораспаковка напрямую связаны с оболочками типов (type wrapper) языка Java и со способом вставки значений в экземпляры таких оболочек и извлечения значений из них. По этой причине мы начнем с краткого обзора оболочек типов и процесса упаковки и распаковки значений для них.
Обзор оболочек типов и упаковки значений
Как вам известно, в языке Java используются базовые типы (также называемые простыми), такие как int или double, для хранения элементарных данных типов, поддерживаемых языком. Для хранения таких данных из-за более высокой производительности применяются базовые типы, а не объекты. В этом случае использование объектов добавляет неприемлемые издержки даже к простейшей вычислительной операции. Таким образом, базовые типы не являются частью иерархии объектов и не наследуют класс Object.
Несмотря на выигрыш в производительности, предлагаемый базовыми типами, возникают ситуации, требующие обязательного объектного представления. Например, Вы не можете передать в метод переменную базового типа как параметр по ссылке. Кроме того, много стандартных cтруктур данных, реализованных в языке Java, оперирует объектами, и, следовательно, Вы не можете использовать эти структуры для хранения данных базовых типов. Для подобных (и других) случаев Java предоставляет оболочки типов, представляющие собой классы, которые инкапсулируют данные простого типа в объект. Далее перечислены классы оболочки типов.
Boolean Byte Character Double
Float Long Integer Short
Значение базового типа инкапсулируется в оболочку в момент конструирования объекта. Упакованное таким образом значение можно получить обратно с помощью вызова одного из методов, определенных в оболочке. Например, все оболочки числовых типов предлагают следующие методы:
byte byteValue() double doubleValue() float floatValue()
int intValue() long longValue() short shortValue()
Каждый метод возвращает значение заданного базового типа. Например, объект типа Long может вернуть значение одного из встроенных числовых типов, включая short, double или long.
Процесс инкапсуляции значения в объект называется упаковкой (boxing). До появления Java 2 версии 5.0 вся упаковка выполнялась программистом вручную, с помощью создания экземпляра оболочки с нужным значением. В приведенной далее строке кода значение 100 упаковывается вручную в объект типа Integer:
Integer iOb = new Integer(l00);
В приведенном примере новый объект типа Integer со значением 100 создается явно и ссылка на него присваивается переменной iOb.
Процесс извлечения значения из оболочки типа называется распаковкой (unboxing). И снова, до появления Java 2 версии 5.0 вся распаковка выполнялась вручную с помощью вызова метода оболочки для получения значения из объекта.
В следующей строке кода значение из объекта iOb вручную распаковывается в переменную типа int:
int i = iOb.intValue();
В данном случае метод intValue() возвращает значение типа int из объекта iOb. Как объяснялось ранее, есть и другие методы, позволяющие извлечь из объекта значение другого числового типа, такого как byte, short, long, double или float. Например, для получения значения типа long из объекта iOb Вам следует вызвать метод iOb.longValue(). Таким образом, можно распаковать значение в переменную простого типа, отличающегося от типа оболочки.
Начиная с первоначальной версии языка Java, для упаковки и распаковки вручную выполнялась одна и та же базовая процедура, приведенная в предыдущих примерах. Хотя такой способ упаковки и распаковки работает, он утомителен и подвержен ошибкам, так как требует от программиста вручную создавать подходящий объект для упаковки значения и при необходимости его распаковки явно задавать переменную соответствующего базового типа. К счастью Java 2, v5.0 коренным образом модернизирует эти важнейшие процедуры, вводя средства автоупаковки/распаковки.
Основы автоупаковки/распаковки
Автоупаковка (autoboxing) — это процесс автоматической инкапсуляции данных простого типа, такого как int или double, в эквивалентную ему оболочку типа, как только понадобится объект этого типа. При этом нет необходимости в явном создании объекта нужного типа. Автораспаковка (auto-unboxing) — это процесс автоматического извлечения из упакованного объекта значения, когда оно потребуется. Вызовы методов, таких как intValue() и doubleValue(), становятся ненужными.
Добавление средств автоупаковки/автораспаковки значительно упрощает кодирование ряда алгоритмов, исключая утомительные упаковку и распаковку, выполняемые вручную. Кроме того, эти новые средства программирования позволяют избежать ошибок за счет устранения возможности распаковки вручную неверного типа из оболочки. Автоупаковка также облегчает использование настраиваемых типов (generics) и запоминание данных базовых типов в коллекциях.
Благодаря автоупаковке исчезает необходимость в создании вручную объекта для инкапсуляции значения простого типа. Вам нужно только присвоить это значение указателю на объект типа-оболочки. Язык Java автоматически создаст для вас этот объект. В следующей строке приведен пример современного способа конструирования объекта типа Integer, хранящего значение 100:
Integer iOb = 100; // автоматически упаковывает значение типа int
Обратите внимание на то, что никакого объекта не создается явно, с помощью операции new. Язык Java выполнит это автоматически.
Для автораспаковки объекта просто присвойте ссылку на него переменной соответствующего базового типа. Например, для распаковки объекта iOb можно использовать следующую строку кода:
int i = iOb; // автораспаковка
Все детали выполнит для вас язык Java.
В листинге 2.1 приведена короткая программа, вобравшая в себя все приведенные ранее фрагменты и демонстрирующая основы механизма автоупаковки/распаковки,
Листинг 2.1. Демонстрация применения автоупаковки/распаковки

// Demonstrate autoboxing/unboxing.
class AutoBox <

public static void main(String args[]) <
Integer iOb = 100; ; // автоупаковка значения типа int
int i = iOb; // автораспаковка
System.out.println(i + » » + iOb); // отображает на экране: 100 100

// Autoboxing/unboxing takes place with
// method parameters and return values.

class AutoBox2 <
// Принимает параметр типа Integer и возвращает
// значение типа int;

static int m(Integer v) <
return v ; // auto-unbox to int
>

public static void main(String args[]) <
// Передает значение int в метод m() и присваивает возвращаемое
// значение объекту типа Integer. Здесь аргумент 100
// автоупаковывается в объект типа Integer. Возвращаемое значение
// также автоупаковывается в тип Integer.

Integer iOb = m(100);

Программа листинга 2.2 отображает следующий ожидаемый результат:
100
В приведенной программе метод задает параметр типа Integer и возвращает результат типа int. В теле main() методу m() передается значение 100. Поскольку ожидает объект типа Integer, передаваемое значение автоматически упаковывается. Далее метод то возвращает эквивалент своего аргумента, но простого типа int. Это приводит к автоматической распаковке в переменную v. Далее в методе main() объекту iOb присваивается это значение типа int, что вызывает его автоупаковку. Главное преимущество заключается в том, что все преобразования выполняются автоматически.
Автоупаковка/распаковка в выражениях
Вообще, автоупаковка/распаковка происходит всегда, когда требуется преобразование в объект или из объекта. Это применимо и к выражениям. В них числовой объект автоматически распаковывается. Результат выражения повторно упаковывается, если это необходимо. Рассмотрим программу, приведенную в листинге 2.3.
Листинг 2.3. Автоупаковка/распаковка внутри выражений


class AutoBox3 <
public static void main(String args[]) <

Integer iOb, iOb2;
int i;

iOb = 100;
System.out.println(«Original value of iOb: » + iOb);

// Далее автоматически распаковывается объект iOb,
// выполняется операция инкремента, затем результат
// повторно упаковывается в объект iOb.

++iOb;
System.out.println(«After ++iOb: » + iOb);

// Здесь iOb распаковывается, выражение
// вычисляется и результат повторно упаковывается
// и присваивается iOb2.

iOb2 = iOb + (iOb / 3);
System.out.println(«iOb2 after expression: » + iOb2);
// To же самое выражение вычисляется, но результат
// повторно не упаковывается.

i = iOb + (iOb / 3);
System.out.println(«i after expression: » + i);

Далее приведен вывод программы, отображающий результаты ее работы.
Original value of iOb: 100
After ++iOb: 101
iOb2 after expression: 134
i after expression: 134
Обратите особое внимание на следующую строку программы из листинга 2.3:
++iOb;
Она вызывает увеличение на единицу значения, упакованного в объекте iOb. Это действие выполняется следующим образом: объект iOb распаковывается, значение увеличивается, и результат повторно упаковывается.
Автораспаковка позволяет смешивать в выражении числовые объекты разных типов. После того как значения распакованы, к ним применимы стандартные преобразования типов и переходы от одного к другому. Например, приведенная в листинге 2.4 программа вполне корректна.
Листинг 2.4. Обработка числовых объектов разных типов в одном выражении

class AutoBox4 <
public static void main(String args[]) <

Integer iOb = 100;
Double dOb = 98.6;

dOb = dOb + iOb;
System.out.println(«dOb after expression: » + dOb);
>
>

Integer iOb = 2 ;
switch (iOb) <
case 1: System.out.println(«one»);
break;
case 2: System.out.println(«two») ;
break;
default: System.out.println(«error») ;

Когда вычисляется выражение в операторе switch, распаковывается объект iOb и извлекается значение типа int.
Приведенные примеры программ показывают, что наличие автоупаковки/распаковки делает использование числовых объектов в выражении легким и интуитивно понятным. В прошлом в этот код пришлось бы вставлять вызовы методов, подобных intValue().
Автоупаковка/распаковка логических и символьных значений
Кроме оболочек для числовых типов язык Java также предоставляет оболочки для данных типов boolean и char. Они называются Boolean и Character соответственно. К ним также применимы автоупаковка/распаковка. Рассмотрим программу, приведенную в листинге 2.5.

Листинг 2.5. Автоупаковка/распаковка типов Boolean и Character

class AutoBox5 <
public static void main(String args[]) <
// Автоупаковка/распаковка логических переменных.
Boolean b = true;

// Далее объект b автоматически распаковывается, когда используется
// в условном выражении оператора, такого как if.
if(b) System.out.println(«b is true»);
// Автоупаковка/распаковка символьных переменных.

Character ch = ‘x’; // box a char
char ch2 = ch; // unbox a char

System.out.println(«ch2 is » + ch2);
>
>

Далее приведен вывод программы из листинга 2.5, отображающий результаты ее работы:
b is true
ch2 is x
Наиболее важной в программе из листинга 2.5 является автораспаковка объекта b внутри условного выражения в операторе if. Как вы должны помнить, условное выражение, управляющее выполнением оператора if, следует вычислять как значение типа boolean. Благодаря наличию автораспаковки логическое значение, содержащееся в объекте b, автоматически распаковывается при вычислении условного выражения. Таким образом, с появлением Java 2 v5.0 стало возможным использование объекта типа Boolean для управления оператором if.
Более того, теперь объект типа Boolean можно применять для управления любыми операторами цикла языка Java. Когда объект типа Boolean используется как условное выражение в циклах while, for, do/while, он автоматически распаковывается в эквивалент простого типа boolean. Например, приведенный далее фрагмент теперь абсолютно корректен.
Boolean b;
//
while (b) < //

Помощь автоупаковки/распаковки в предупреждении ошибок
Кроме удобства, которое предоставляет механизм автоупаковки/распаковки, он может помочь в предупреждении ошибок. Рассмотрим программу, приведенную в листинге 2.6.
Листинг 2.6. Ошибка, возникшая при распаковке вручную

class UnboxingError <
public static void main(String args[]) <

Integer iOb = 1000;
// автоматически упаковывает значение 1000
int i = iOb.byteValue();// вручную распаковывается как тип byte .
System.out.println(i);// не отображает значение 1000
>
>

Программа из листинга 2.6 отображает число -24 вместо ожидаемого значения 1000! Причина заключается в том, что значение, хранящееся в объекте iOb, распаковывается вручную с помощью вызова метода byteValue() который приводит к усечению этого значения, равного 1000. В результате переменной i присваивается число -24, так называемый «мусор». Автораспаковка препятствует возникновению ошибок этого типа, потому что она преобразует значение, хранящееся в iOb, в величину базового типа, сопоставимого с типом int.
Вообще говоря, поскольку автоупаковка всегда создает правильный объект, а автораспаковка всегда извлекает надлежащее значение, не возникает ситуаций для формирования неверного типа объекта или значения. В редких случаях, когда Вам нужен тип, отличающийся от созданного автоматическим процессом, Вы и сейчас можете упаковывать и распаковывать значения вручную так, как делали это раньше. Конечно, при этом теряются преимущества автоупаковки/распаковки. Как правило, во вновь разрабатываемом коде должны применяться эти механизмы, так как они соответствуют современному стилю программирования на языке Java.
Предостережения
Теперь, когда в язык Java включены средства автоупаковки/распаковки, может появиться желание использовать только числовые объекты типа Integer или Double, полностью отказавшись от данных простых типов. Например, благодаря наличию автоупаковки/распаковки теперь можно написать код, подобный приведенному далее.
//Пример плохого использования автоупаковки/распаковки Double a,b,c;

а = 10.0;
b = 4.0;
с = Math.sqrt(a*a + b*b);
System.out.println(«Hypotenuse is » + c);



В приведенном примере объекты типа Double содержат значения, которые используются для вычисления гипотенузы прямоугольного треугольника. Хотя этот код технически корректен и будет выполняться правильно, он служит образцом очень плохого применения автоупаковки/распаковки. Гораздо эффективнее использовать данные простого типа double для подобных вычислений, т. к. каждая автоупаковка и автораспаковка вносят дополнительные затраты, которых лишены вычисления с применением базовых типов данных.
Вообще говоря, следует ограничить использование оболочек типов только теми случаями, для которых требуется объектное представление данных простых типов. Автоупаковка/автораспаковка включены в язык таким образом, чтобы не ограничивать применение простых типов данных.
Опубликовал Kest Январь 13 2009 00:39:27 · 0 Комментариев · 8021 Прочтений ·

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •

Комментарии
Нет комментариев.
Добавить комментарий
Рейтинги

Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь .

Блог только про Java

Учимся программировать на Java с нуля

Объектные оболочки и автоупаковка Java

Иногда приходится преобразовывать переменные простых типов вроде int в объекты. Все простые типы имеют аналоги в виде классов. Например, существует класс Integer, соответствующий типу int. Такие классы принято называть объектными оболочками(object wrapper). Они имеют очевидные имена: Integer, Long, Float, Double, Short, Byte, Character, Vo > Предположим, мы хотим, чтобы в списочном массиве хранились целые числа. К сожалению, с помощью параметра в угловых скобках невозможно задать простой тип, например, выражение ArrayList недопустимо. Здесь приходит на помощь класс-оболочку. Можно объявить списочный массив, предназначенный для хранения объектов Integer:

При использовании объекта ArrayList производительность становится меньше, чем при работе с массивом int[]. Причина очевидна: каждое значение инкапсулировано внутри объекта, и для его записи или извлечения необходимо предпринимать дополнительные действия. Таким образом, использование классов-оболочек оправдано в небольших наборах данных, когда удобство работы программиста важнее эффективности работы программы.

С появлением Java SE 5.0 стало проще добавлять элементы в массив и извлекать их. Рассмотрим следующую строку кода:

Она автоматически преобразуется в выражение:

Подобное автоматическое преобразование называется автоупаковкой(autoboxing).

В противоположном случае, если вы присвоите объект Integer переменной int, целочисленное значение будет автоматически извлечено из объекта, т.е. распаковано(unboxed). Другими словами, компилятор преобразует строку кода:

Java / Автоупаковка примитивов в Java

Автор: shual ← к списку ← →

Автоупаковка это механизм неявной инициализации объектов классов-оберток (Byte, Short, Character, Integer, Long, Float, Double) значениями соответствующих им исходных примитивных типов (соотв. byte, short, char, int, long, float, double), без явного использования конструктора класса.
Автоупаковка происходит при прямом присвоении примитива — классу-обертке (с помощью оператора»=»), либо при передаче примитива в параметры метода (типа «класса-обертки»). Автоупаковке в «классы-обертки» могут быть подвергнуты как переменные примитивных типов, так и константы времени компиляции(литералы и final-примитивы). При этом литералы должны быть синтаксически корректными для инициализации переменной исходного примитивного типа.

Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива — типу «класса-обертки».
Например, попытка автоупаковать переменную типа byte в Short, без предварительного явного приведения byte->short вызовет ошибку компиляции.

Автоупаковка констант примитивных типов допускает более широкие границы соответствия. В этом случае компилятор способен предварительно осуществлять неявное расширение/сужение типа примитивов. Преобразование происходит в два этапа:
1) неявное расширение(сужение) исходного типа примитива до типа примитива соответствующего классу-обертке (для преобразования int->Byte, сначала компилятор неявно сужает int в byte)
2) автоупаковку примитива в соотвествующий «класс-обертку» (компилятор автоупаковывает byte->Byte). однако в этом случае существуют два дополнительных ограничения:
a) присвоение примитива — «обертке» может производится только оператором «=» (нельзя передать такой примитив в параметры метода , без явного приведения типов)
b) тип левого операнда не должен быть старше чем Character, тип правого не дожен старше чем int, (допустимо расширение/сужение byte short, byte char, short char
и только сужение byte 27 Голосовать

Java для начинающих. Часть 1 из 4

Данные статьи помогут легко и быстро разобраться в концепциях и программировании на Java.

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

JVM, JRE и JDK

Вот так и происходит вся магия: логика (т.е. код) прописывается в java файле, который затем преобразуется в файл класса. Машина его читает и выполняет.

А теперь подробнее:


  • JVM — виртуальная машина Java, выполняющая байт-код Java.
  • JVM можно загружать на разном железе. Байт-коды — это машинный язык JVM. Поэтому Java является самым портируемым языком. JVM — это некий объект, который и обеспечивает портируемость. Для разных операционных систем (Mac, Windows, Linux и т.д.) придуманы свои реализации JVM.
  • JRE — среда выполнения Java, достаточная для запуска программы.
  • JRE = JVM + файлы библиотеки/пакеты классов (Util, Lang, Math etc).
  • JDK — пакет средств разработки на Java. Нужен для написания, компиляции и выполнения программы.
  • JDK = JRE + инструменты, необходимые для разработки Java-программы.

Выделение памяти

Коротко о том, как происходит выделение памяти со стороны кода в фоновом режиме:

  • Каждый раз при создании объекта в Java он сохраняется в heap памяти.
  • Примитивы и локальные переменные хранятся в stack памяти, переменные-члены — в heap.
  • При многопоточности каждый поток имеет собственный stack, но находится в общей куче (heap). О многопоточности поговорим во второй части.
  • При вызове какого-либо метода все методы и переменные помещаются в stack. По завершении вызова указатель стека (stack) уменьшается.
  • 32-разрядная операционка тратит не более 4GB RAM на Java-приложения. В 64-разрядной затраты памяти на те же элементы увеличиваются вдвое.
  • Примитивный тип int тратит в 4 раза меньше памяти, чем Integer.

Таблица ниже перечисляет различные типы данных и их диапазоны хранимых значений:

ООП — Инкапсуляция, наследование, полиморфизм и абстракция

Объектно-ориентированное программирование (ООП) — это концепция программирования, основанная на 4 базовых принципах.

1. Инкапсуляция

Инкапсуляция — это объединение данных и функциональных средств в единый компонент. Функциональные средства — это «методы», а данные — это «переменные». Все они объединяются в «класс». Это некая схема или набор инструкций.

Класс — это некий прообраз или прототип, который определяет переменные и методы. Пример:

Класс: Машина Переменные-члены или объекты: цвет, тип, модель и т.д. Методы: остановка, ускорение, предельная скорость.

Объект — это экземпляр класса. В примере выше моя машина будет экземпляром общего класса Машина.

Переменные: локальные, статические и переменные экземпляра. Локальные переменные объявляются в теле метода. Переменные экземпляра объявляются вне метода и являются специфичными для конкретного объекта. Статические переменные инициализируются только один раз при запуске программы. Статические переменные инициализируются первыми, но об этом чуть позже.

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

Пакет— это набор связанных классов. Используется для организации классов в структуру папок, а также для быстрого нахождения и повторного использования этих классов.

2. Абстракция

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

3. Наследование

Наследование — это процедура, при которой один класс приобретает свойства другого. Например, потомок наследует признаки своего родителя.

4. Полиморфизм

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

  • Перегрузка — это несколько методов одного класса с одним именем, но разной сигнатурой.
  • Переопределение — два метода (один в родительском классе, другой — в дочернем) с одним именем и сигнатурой.
  • Метод подкласса переопределяет метод суперкласса.
  • При переопределении подклассов модификатор доступа должен быть больше родительского класса. Например, если использовать public abc() в родительском классе и private abc() в подклассе — это вызовет исключение.


Загрузка статического и динамического класса

  • Добавление класса для запуска в JVM называется загрузкой класса.
  • Классы загружаются статично с помощью нового оператора.
  • Первый класс загружается через метод static main(). Затем подгружаются остальные классы.
  • В серверных проектах отсутствует main(), поскольку сервер сам отвечает за всю инфраструктуру. Первый класс для загрузки отмечается в config файле. Довольно часто фреймворк реализует метод main() и предоставляет API. Пример: Контейнерный класс вызывает метод init() в сервлетах.
  • main нужен для запуска Java-программы из командной строки в JVM.
  • Если при загрузке статического класса не находится ссылка на класс, то выбрасывается No />

Абстрактный класс и интерфейс

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

Java Packages

Ниже даны примеры библиотек из пакетов Java которые помогут при написании правильного кода. О них мы еще поговорим.

Конструкторы


  • Их единственная цель — создавать экземпляры класса. Они вызываются в процессе создания объекта класса.
  • Если конструктор с аргументами определен в классе, то нельзя будет работать со стандартным конструктором без аргументов (no-argument constructor) — придется их прописать.
  • Java не поддерживает конструктор копирования.
  • Имя конструктора и класса совпадает.
  • Если конструктор вызывается из другого конструктора с синтаксисом this, то речь идет именно об этом объекте.
  • В Java есть стандартный конструктор.

Приватный конструктор:

  • Защищает класс от явного превращения в экземпляр.
  • Построение объекта возможно только внутри конструктора.
  • Используется в шаблоне «Одиночка» (Singleton).

Вопрос: Можно ли синхронизировать конструкторы в Java?

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

Вопрос: Наследуются ли конструкторы? Может ли подкласс вызывать конструктор родительского класса?

Конструкторы не наследуются. При переопределении конструктора суперклассов нарушается инкапсуляция языка. Конструктор родительского класса вызывается ключевым словом super.

Static

  • Модификатор Static используется для создания чего-то в единственном экземпляре. Например, когда мы хотим создать переменную или объект, доступные для всех объектов класса.
  • Static необходим для передачи информации по всем объектам.
  • Static подходит для переменных, методов и блоков.
  • или переменные принадлежат классу, а не объекту.
  • Статичный метод или переменная инициализируются один раз перед переменной экземпляра.
  • Статичный метод или переменная могут вызываться напрямую из имени класса. Пример: .
  • Статичный метод имеет доступ только к статичным данным.
  • Статичный метод не может ссылаться на this или super.
  • Статичный метод может вызывать только другие статичные методы.

  • main () — это статичный метод. Он должен быть доступен приложению до создания экземпляров.
  • Конструктор не бывает статичным, потому как компилятор считает его методом. Кроме того, конструктор нужен для инициализации нового объекта, а static выполняет совершенно противоположную функцию.
  • Статичная переменная загружается первой. После нее идет статичный блок. И очередность здесь важна. Статичные методы загружаются в конце.

Статичный родитель → Статичный потомок → Экземпляр родитель → Конструктор родитель → Экземпляр потомок → Конструктор потомок.

  • При переопределении статичного метода компилятор не выдает ошибок. Но правильнее это называть не переопределением, а скрытием, т.к. пропадают все плюсы полиморфизма.

Final, Finalize и Finally

  • Ключевое слово final указывает на неизменность значения чего-либо.
  • Класс final не расширяется.
  • Метод final не переопределяется.
  • Переменные final равнозначны константам.
  • Блок finally вызывается для всех блоков try-catch и используется для очистки системных ресурсов, будь то подключения, выражения и т.д. Мы еще поговорим о них подробнее.
  • Метод finalize() помогает высвобождать память. Он вызывается перед тем, как сборщик мусора помещает объект на удаление.

Класс Object

В каждом классе есть суперкласс Object. В нем присутствуют следующие не конечные методы:

Конечные методы суперкласса:

Equals и hashСode

  • Методы equals() и hashСode() переопределяются для сравнения двух объектов.
  • Метод equal() выполняет сравнение, а метод hashCode возвращает хеш-код.


Clone

  • Метод сlone нужен для копирования объекта.
  • В методе clone присутствует защищенный модификатор доступа.
  • Для вызова метода clone объекту требуется реализация интерфейса Cloneable. В противном случае выбрасывается исключение CloneNotSupportedException.
  • Интерфейс Cloneable является маркерным, то есть методы не определяют интерфейс, а говорят классу об особом отношении.
  • Плюс такого интерфейса: можно копировать только объекты, доступные для клонирования.
  • Если какое-то поле объекта ссылается на другой объект, то делаем поверхностную копию. В ней копируется только адрес памяти, т.е. используется один и тот же объект.
  • При глубоком копировании происходит создание объекта и новое динамическое распределение памяти.

Не обращайте внимание на оператора try — к нему мы вернемся позже.

Агрегация и композиция

  • Агрегация выражает отношение is a («являться чем-то»). Пример: дом является зданием.
  • Композиция выражает отношение has a («быть частью чего-то»). Пример: в доме имеется ванная. То есть форма отношения, в котором эта часть не может существовать без остальных элементов.
  • Агрегация — это более слабое отношение. Композиция намного сильнее.
  • Как правило, агрегация достигается расширением класса. Для композиции нужна реализация интерфейса.

Примитивы и оболочки типов

Переменная примитивного типа всегда содержит его значение. В Java существует 8 примитивных типов: byte , short , int , long , char , boolean , float and double .

Класс-оболочка — это класс, объект которого оборачивает или содержит примитивные типы данных. При создании объекта в классе-оболочкепоявляется поле для хранения примитивных типов данных, а также других поддерживающих и операционных методов. Если использовать не сами примитивы, а Object-оболочки для примитивных типов данных, то процесс выполняется медленнее. Дополнительные ресурсы тратятся на создание экземпляра объекта, вызовы методов и т.д. За каждым из этих примитивных типов закреплен свой класс: Byte, Short, Integer, Long, String, Boolean, Float и Double.

Автоупаковка и распаковка

  • Компилятор Java 1.5 автоматически преобразует примитивы к оболочкам типов, то есть выполняет автоупаковку. Обратное действие называется распаковкой.
  • Для этого в компиляторе используется valueOf() и intValue().

Кастинг

  • Это присвоение значение другому примитиву.

byte → short → int → long → float → double

Автоупаковка и автораспаковка

В языке Java существует два типа переменных: примитивные, например int и boolean, а также ссылочные типы вроде Integer и Boolean (классы-обертки). Для каждого примитивного типа существует, соответствующий ему ссылочный тип.

Классы-обертки являются неизменяемыми: это означает, что после создания объекта его состояние (значение поля value) не может быть изменено; и задекларированы, как final
(от этих классов невозможно наследоваться).

Java автоматически производит преобразования между примитивными типами и их обертками:

В зависимости от реализации виртуальной машины, эти значения могут изменяться. Например, в виртуальной машине Oracle значения типа boolean сопоставляются со значениями 0 и 1 типа int (это связано с тем, что в VM нет инструкций для работы с булевыми значениями) и, как результат, занимают в памяти 32 бита.

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

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

Накладные расходы зависят от реализации конкретной JVM. Здесь мы приведем результаты для 64-х битной виртуальной машины со следующими параметрами:

H Примитивные типы в Java в черновиках Tutorial

.collapse»>Содержание

Примитивные типы

Примитивные типы немного нарушают объектную ориентированность языка Java, так так представляют одиночные (простые) значения. Эта особенность объясняется желанием обеспечить максимальную эффективность. Создавать объект простой переменной с помощью new недостаточно эффективно, так как new перемещает объект в кучу. Вместо этого создается «автоматическая» переменная, которая не является ссылкой на объект. Переменная хранит единственное значение и располагается в стеке. Стек — это область хранения данных, расположена в RAM. Процессор имеет прямой доступ до этой области через указатель на стек, поэтому стек — очень быстрый и эффективный способ хранения данных. По скорости стек уступает только регистрам (логично, так как регистры расположены внутри процессора).
Все размеры примитивных типов строго фиксированы и не зависят от машинной архитектуры. Это одна с причин улучшенной переносимости Java-программ.
В Java определено восемь примитивных типов, которые можно разбить на четыре группы:

Целые числа Числа с плавающей точкой Символы Логические значения
byte, short, int, long float, double char boolean

Целые числа

Для целых чисел определены четыре примитивных типа: byte, short, int, long. Все эти типы представляют целочисленные значения со знаком: положительные или отрицательные. В Java нет положительных целочисленных значений без знака (unsigned). Как было сказано раньше, все размеры примитивных типов фиксированы:

Тип Длина в байтах Длина в битах Диапазон
byte 1 8 [-128, 127] или [-2 7 , 2 7 -1]
short 2 16 [-32768, 32767] или [-2 15 , 2 15 -1]
int 4 32 [-2147483648, 2147483647] или [-2 31 , 2 31 -1]
long 8 64 [-9223372036854775808, 9223372036854775807] или [-2 63 , 2 63 -1]

Наименьшим целочисленным типом является byte. Переменные этого типа очень удобны для работы с потоками ввода-вывода и при манипулировании двоичными данными. Далее идет тип short, который применяется реже всех остальных типов. Наиболее часто употребляемым типом является int. Его постоянно используют в циклах, для индексации массивов. Может показаться, что использование типов byte и short в местах, где не требуется широкий диапазон значений, будет более эффективным чем использование int. Но это не так, потому что при вычислении выражений значения типа byte или short будут преобразованы в int (мы еще вернемся к этому вопросу). Когда длины типа int недостаточно для хранения значения, нужно использовать long. Его диапазон значений достаточно велик, что делает long удобным при работе с большими целыми числами.

Числа с плавающей точкой

Числа с плавающей точкой (или действительные числа) представлены типами float и double. Используются для хранения значений с точностью до определенного знака после десятичной точки.

Тип Длина в байтах Длина в битах Диапазон
float 4 32 [1.4e -45 , 3.4028235e 38 ]
double 8 64 [4.9e -324 , 1.7976931348623157 308 ]

Тип float определяет числовое значение с плавающей точкой одинарной точности. Этот тип используется, когда нужно числовое значение с дробной частью, но без особой точности. Тип double используется для хранений значений с плавающей точкой двойной точности. Обработка значений двойной точности выполняется быстрее, чем обработка значений одинарной точности. Поэтому большинство математических функций класса java.lang.Math возвращают значения типа double. Эффективнее всего использовать double, когда требуется сохранить точность многократно повторяющихся вычислений или манипулировать большими числами.

Символы

В спецификации примитивный тип char принадлежит к целочисленным типам (или integral types), но поскольку он играет немного другую роль, можно выделить для него собственную категорию. Его роль — представлять символы Unicode. Для хранения символов требуется 16 бит. Странно, ведь для представления символов основных языков (например, английского, французского, испанского) достаточно 8 бит. Но такая цена интернационализации. Unicode использует полный набор международных символов на всех известных языках мира.

Тип Длина в байтах Длина в битах Диапазон
char 2 16 [‘\u0000’, ‘\uffff’] или [0, 65535]

Логические азначения

Примитивный тип boolean предназначен для хранения логических значений. Данный тип может принимать одно из двух возможных значений: true (истина) или false (ложь). Значения boolean возвращаются со всех логических операций (например, операции сравнения). Является обязательным при построении циклов, операторов (например, for, if).

Литералы

Значения примитивных типов данных в большинстве случаев инициализируются с помощью литералов. Рассмотрим их.

Целочисленные литералы

Наиболее часто используемые литералы. Любое целочисленное значение является числовым литералом (например, -10, 10 — десятичные значения). Можно использовать восьмеричные, шестнадцатеричные и двоичные литералы:

Все целочисленные литералы представляют значения int. Если значение литерала лежит в диапазоне byte, short или char, то его можно присвоить переменной этого типа без приведения типов. Для создания литерала типа long, необходимо явно указать компилятору, дополнив литерал буквой ‘l‘ или ‘L‘:

Литералы с плавающей точкой

Существует две формы записи литеров с плавающей точкой: стандартная и экспоненциальная:

Всех литералам с плавающей точкой по-умолчанию присваивается тип double. Поэтому чтобы создать литерал типа float, нужно после литерала указать букву ‘f‘ или ‘F‘. К литералам также можно добавлять букву ‘d‘ или ‘D‘, сообщая, что это литерал типа double, но зачем?

Можно использовать шестнадцатеричные литералы с плавающей точкой, например:

Для удобности чтения длинных литералов в 7 версии языка была добавлена возможность использовать символ ‘_’ внутри литерала:

Символьные литералы

Символьные литералы заключаются в одинарные кавычки. Все отображаемые символы можно задавать таким способом. Если символ нельзя ввести непосредственно, используют управляющее последовательности начинающиеся с символа ‘\‘. Хотя все эти последовательности можно заменить соответствующим Unicode кодом. Также символьный литерал можно создать используя восьмеричную (‘\xxx’) и шестнадцатеричную форму (‘\uxxxx’).

Существуют также строковые литералы. Информацию о них можно получить тут.

Логические литералы

С логическими операторами все просто. Существует только два логических литерала:

Логические литералы можно присваивать только переменным типа boolean. Также важно понимать, что false не равен , а true не равен 1. Преобразовать переменную типа boolean в другие примитивные типы не выйдет.

Операции

Над целочисленными типами

Над Floating-Point типами

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

Над логическим типом

Преобразование

Существует три типа преобразований:

  • расширяющее преобразование (widening)
  • суживающее преобразование (narrowing)
  • widening + narrowing (преобразование byte к char, сначала byte преобразовываем в int, а потом int — в char)

Расширяющее преобразование

Если оба типа совместимы и длина целевого типа больше длины исходного типа выполняется расширяющее преобразование (например byte преобразуется в int). Следующая таблица демонстрирует все возможные расширяющее преобразования. Курсовом помечены типы, преобразования в которые, возможно, приведут к потери данных.

byte short, int, long, float, double
short int, long, float, double
char int, long, float, double
int long, float, double
long float, double
float double (если использовать strictfp потери данных не будет)

Суживающее преобразование

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

short byte, char
char byte, short
int byte, short, char
long int, byte, short, char
float long, int, byte, short, char
double float, long, int, byte, short, char

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

Продвижение

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

Правила продвижения хорошо демонстрирует следующая диаграмма:

Классы-обертки

Для представления примитивных типов как объектов было сделаны классы-обертки (wrapper classes). Какие преимущества дают нам классы-обертки?

  • возможность использования объектов классов-оберток в качестве параметров к методам или как generic-параметры
  • возможность использования констант, которые отвечают за границы соответствующего типа данных (MIN_VALUE и MAX_VALUE)
  • возможность использования методов для преобразования в другие примитивные типы, конвертации между системами счисления

Wrapper-классов восемь, по одному на каждый примитивный тип:

Примитивный тип Класс-обертка
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double Double

Почти все классы (кроме Boolean и Character) унаследованы от абстрактного класса Number и являются сравнимыми (реализуют интерфейс Comparable). Иерархия, примерно, такая:

Автоупаковка и распаковка

В версии JDK 5 были введены два важных средства:

  • Автоупаковка (autoboxing) — процесс автоматического инкапсулирования примитивного типа в соответствующий класс-обертку. Отпадает необходимость явно создавать объект.
  • Распаковка (unboxing) — процесс автоматического извлечения примитивного типа с соответствующего класса-обертки. Отпадает необходимость явного вызова метода для получения примитивного типа.

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

Некоторые полезные методы

Спасибо за внимание. Все дополнения, уточнения и критика приветствуются.

Проблема с автоупаковкой (autoboxing) в Java

я хочу, чтобы конвертировать примитив, чтобы строка, и я попробовал:

в Этом выдает ошибка:

Теперь, я понимаю, что примитивы не ссылочные типы (ie, а не Объект) и поэтому не могут быть методы. Однако, Java 5, введена автоматическая упаковка и Распаковка (a la C#. которая мне никогда не нравилась в C#, но это к делу). Так с autoboxing, я предполагаю, что выше, чтобы преобразовать myInt Целое число, а затем вызов toString ().

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

Основные синтаксические и семантические единицы языка Java. Примитивныe типы данных и основные операторы языка: Методические указания к лабораторной работе , страница 9

atan2(double y, double x)

copySign(double magnitude, double sign)

copySign(float magnitude, float sign)

hypot(double x, double y)

IEEEremainder(double f1, double f2)

max(double a, double b)

max(float a, float b)

max(long a, long b)

min(double a, double b)

min(float a, float b)

min(long a, long b)

nextAfter(double start, double direction)

nextAfter(float start, double direction)

pow(double a, double b)

scalb(double d, int scaleFactor)

scalb(float f, int scaleFactor)

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

К классам-оболочкам относятся: Boolean, Character, Byte, Short, Integer, Long, Float, Double, Void.

Автоупаковка и автораспаковка

Допускается присваивать переменным примитивного типа значения соответствующих классов-оболочек и наоборот — в этом случае вызов метода преобразования будет автоматически добавлен компилятором:

Является предком всех классов исключений, сигнализирующих о нестандартных ситуациях, которые должны быть специальным образом обработаны. Исключения, которые может вызывать какой-либо метод, должны объявляться в предложении throws этого метода (кроме исключений, порожденных от класса RuntimeException).

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

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

  • АлтГТУ 419
  • АлтГУ 113
  • АмПГУ 296
  • АГТУ 266
  • БИТТУ 794
  • БГТУ «Военмех» 1191
  • БГМУ 172
  • БГТУ 602
  • БГУ 153
  • БГУИР 391
  • БелГУТ 4908
  • БГЭУ 962
  • БНТУ 1070
  • БТЭУ ПК 689
  • БрГУ 179
  • ВНТУ 119
  • ВГУЭС 426
  • ВлГУ 645
  • ВМедА 611
  • ВолгГТУ 235
  • ВНУ им. Даля 166
  • ВЗФЭИ 245
  • ВятГСХА 101
  • ВятГГУ 139
  • ВятГУ 559
  • ГГДСК 171
  • ГомГМК 501
  • ГГМУ 1967
  • ГГТУ им. Сухого 4467
  • ГГУ им. Скорины 1590
  • ГМА им. Макарова 300
  • ДГПУ 159
  • ДальГАУ 279
  • ДВГГУ 134
  • ДВГМУ 409
  • ДВГТУ 936
  • ДВГУПС 305
  • ДВФУ 949
  • ДонГТУ 497
  • ДИТМ МНТУ 109
  • ИвГМА 488
  • ИГХТУ 130
  • ИжГТУ 143
  • КемГППК 171
  • КемГУ 507
  • КГМТУ 269
  • КировАТ 147
  • КГКСЭП 407
  • КГТА им. Дегтярева 174
  • КнАГТУ 2909
  • КрасГАУ 370
  • КрасГМУ 630
  • КГПУ им. Астафьева 133
  • КГТУ (СФУ) 567
  • КГТЭИ (СФУ) 112
  • КПК №2 177
  • КубГТУ 139
  • КубГУ 107
  • КузГПА 182
  • КузГТУ 789
  • МГТУ им. Носова 367
  • МГЭУ им. Сахарова 232
  • МГЭК 249
  • МГПУ 165
  • МАИ 144
  • МАДИ 151
  • МГИУ 1179
  • МГОУ 121
  • МГСУ 330
  • МГУ 273
  • МГУКИ 101
  • МГУПИ 225
  • МГУПС (МИИТ) 636
  • МГУТУ 122
  • МТУСИ 179
  • ХАИ 656
  • ТПУ 454
  • НИУ МЭИ 641
  • НМСУ «Горный» 1701
  • ХПИ 1534
  • НТУУ «КПИ» 212
  • НУК им. Макарова 542
  • НВ 777
  • НГАВТ 362
  • НГАУ 411
  • НГАСУ 817
  • НГМУ 665
  • НГПУ 214
  • НГТУ 4610
  • НГУ 1992
  • НГУЭУ 499
  • НИИ 201
  • ОмГТУ 301
  • ОмГУПС 230
  • СПбПК №4 115
  • ПГУПС 2489
  • ПГПУ им. Короленко 296
  • ПНТУ им. Кондратюка 119
  • РАНХиГС 186
  • РОАТ МИИТ 608
  • РТА 243
  • РГГМУ 118
  • РГПУ им. Герцена 124
  • РГППУ 142
  • РГСУ 162
  • «МАТИ» — РГТУ 121
  • РГУНиГ 260
  • РЭУ им. Плеханова 122
  • РГАТУ им. Соловьёва 219
  • РязГМУ 125
  • РГРТУ 666
  • СамГТУ 130
  • СПбГАСУ 318
  • ИНЖЭКОН 328
  • СПбГИПСР 136
  • СПбГЛТУ им. Кирова 227
  • СПбГМТУ 143
  • СПбГПМУ 147
  • СПбГПУ 1598
  • СПбГТИ (ТУ) 292
  • СПбГТУРП 235
  • СПбГУ 582
  • ГУАП 524
  • СПбГУНиПТ 291
  • СПбГУПТД 438
  • СПбГУСЭ 226
  • СПбГУТ 193
  • СПГУТД 151
  • СПбГУЭФ 145
  • СПбГЭТУ «ЛЭТИ» 380
  • ПИМаш 247
  • НИУ ИТМО 531
  • СГТУ им. Гагарина 114
  • СахГУ 278
  • СЗТУ 484
  • СибАГС 249
  • СибГАУ 462
  • СибГИУ 1655
  • СибГТУ 946
  • СГУПС 1513
  • СибГУТИ 2083
  • СибУПК 377
  • СФУ 2423
  • СНАУ 567
  • СумГУ 768
  • ТРТУ 149
  • ТОГУ 551
  • ТГЭУ 325
  • ТГУ (Томск) 276
  • ТГПУ 181
  • ТулГУ 553
  • УкрГАЖТ 234
  • УлГТУ 536
  • УИПКПРО 123
  • УрГПУ 195
  • УГТУ-УПИ 758
  • УГНТУ 570
  • УГТУ 134
  • ХГАЭП 138
  • ХГАФК 110
  • ХНАГХ 407
  • ХНУВД 512
  • ХНУ им. Каразина 305
  • ХНУРЭ 324
  • ХНЭУ 495
  • ЦПУ 157
  • ЧитГУ 220
  • ЮУрГУ 306

Полный список ВУЗов

Чтобы распечатать файл, скачайте его (в формате Word).

Илон Маск рекомендует:  Что такое код recode_string
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL