ПЛАШКА "РЕШЕН" НА ТЕМЕ ПОЯВИЛАСЬ СЛУЧАЙНО. Просто палец дернулся, )))) Ответа по сути пока нет.
И давайте проапдейтим сам вопрос (в конце поста).
Опытные товарищи, поясните плиз в какую сторону смотреть. Не понимаю.
public static void main(String[] args) {
Integer integer = 0;
Integer integer1 = new Integer(1);
System.out.println(integer.toString());
System.out.println(integer1.longValue());
0
1
// Методы класса доступны.
Integer integer2 = "222"; // А тут фигушки. Ошибка incompatible types, второй конструктор класса недоступен.
// Ну ОК. Закомментируем предыдущую строку и создадим объект:
Integer integer3 = new Integer("333"); // Нет ошибок. Заявленный конструктор класса отработал
System.out.println (integer instanceof Integer); // так, на всякий случай
true
// Так все же, что происходит при Integer integer = значение ???
}
Собственно вопрос звучит так:
В классе Integer есть два конструктора. Один для int, другой для String. Но почему один доступен без создания экземпляра класса, а для другого таки нужен объект (что и продемонстрировал код выше). Почему не в смысле для чего, а в смысле как. Как это работает?
NightCrow
27 уровень
Integer и другие классы. Создавать объект, или нет.
Решен
Комментарии (15)
- популярные
- новые
- старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Денис Enterprise Java Developer
20 сентября 2024, 09:27
Присвоение примитива классу обёртке возможно из-за существования autoboxing, С его помощью ты можешь присвоить примитив его классу обёртке. Строка, во первых не является примитивом, во вторых, она точно не обязана быть числовым типом например. Как ее в таком случае автобоксить?
Вызов статических методов через инстанс класса возможен, но считается плохой практикой, потому как статика принадлежит классу, а не его инстансу. Как минимум код становится сильно более читаем если отделять мух от котлет и не смешивать контексты.
+2
NightCrowSystem Engineer в Аплана
20 сентября 2024, 09:57
Денис, про аутобоксинг тут прочли все. Ваш ответ, это как если бы на вопрос "А как Коперфильд смог пройти через стену" вы ответили "Он использовал хитрую систему зеркал и механизмов". Насколько ваш ответ точен, ровно настолько же он бессмысленен в данном контексте. ))))
Частично то я разобрался. Это было в моем же ответе выше. Но вот как произошло присвоение внутренней переменной int класса Integer значения переданного в выражении я так и не понял. , ибо переменная приватная, а конструктора без создания объекта по видимому нет.
0
Денис Enterprise Java Developer
20 сентября 2024, 10:04
Ну если уж ты нашёл слово аутобоксинг, то наверное мог найти и вот это
Или ты хотел посмотреть как это выглядит в байткоде?
Что же касается конструктора, то тут никакой магии нет. В нём вызывается статический метод класса, раз он вызывается изнутри класса то и ссылаться на имя класса не нужно. Статические методы существуют без экземпляра класса, потому вполне могут быть вызваны в конструкторе. Куда важнее другое, когда ты заходишь в конструктор у тебя уже и экземпляр имеется, в противном случае куда по твоему ссылается this? :)
Я надеюсь ты понимаешь что
Это и есть конструктор.
Ну и само собой, любые приватные поля и методы класса более чем доступны изнутри этого самого класса.
+2
NightCrowSystem Engineer в Аплана
20 сентября 2024, 11:04
Денис, я вас не понимаю, от слова совсем. Текст конструктора, который вы привели, я уже писал в комментарии к посту. Поэтому фраза "надеюсь ты понимаешь что это и есть конструктор" звучит в высшей степени неуместно.
Услышьте вопрос, если конечно интересно. Есть два конструктора. Один для int, другой для string. Оба абсолютно идентичны с точки зрения модификаторов. Но для одного нужно создавать объект, для другого нет. Мне не интересны абстрактные мысли почему это хорошо. Мне интересно почему это работает так.
P.S. По ссылке, которую вы дали, этого ответа разумеется нет. Я спрашивал не про то, что и во что может завернуться.
-2
Денис Enterprise Java Developer
20 сентября 2024, 11:51
По моему ты не вполне понимаешь о чем пытаешься рассуждать.
Запись Integet num = 1; не вызывает никаких волшебных конструкторов, она валидна потому что есть явление автобоксинга, в байткоде ты мог увидеть, что компилятор подсовывает туда Integer.valueOf().
Какие типы поддерживают и как именно этот боксинг-анбоксинг написано в спецификации языка (ссылка выше).
Создание Integer через конструктор с аргументом в виде строки не имеет никакого отношения к механизму автобоксинга, это обычное создание через конструктор (к слову deprecated и помеченный на удаление). Оно работает как и любое другое создание через конструктор.
Это два разных метода создания объекта.
+3
NightCrowSystem Engineer в Аплана
20 сентября 2024, 12:32
Ну я программирование изучаю всего месяц и это нормально "не вполне понимать". Нормально как раз пытаться разобраться. ))) Естественно байткод я не понял совсем, до последнего комментария.
Вы говорите, что 1: invokestatic #7 это как раз тот самый автобоксинг, когда подсовывается Integer.valueOf(). ОК, но ведь в классе есть и valueOf (String s). Или я зря пытаюсь искать ответы в тексте класса и за это отвечает компилятор, который смотрит, примитив справа, или нет. И если примитив, то valuOf, а если не примитив, то, как говорится, идите лесом, халявы нет, создавайте объект. Итого автобоксинг, это вообще не про объект, но только про конкретный статический метод для конвертации примитивов.
0
hidden #3303140
20 сентября 2024, 13:14
> но ведь в классе есть и valueOf (String s)
А в чём здесь по-твоему заключается "но"?
У тебя есть конструктор, который создаёт упакованный в оболочку Integer объект
Дальше у тебя есть метод valueOf, который по сути своей является фабричным методом, и если опустить возможное обращение к кэшу, этот самый конструктор вызывает:
И есть встроенный в джава-машину механизм автоупаковки, который говорит, что если ты литерал попытаешься поместить в переменную-обёртку Integer, то он, этот самый механизм, вызовет метод valueOf, который по цепочке вызовет конструктор объекта. То есть в конечном итоге не будет никакой разницы между тем, чтобы написать
Integer thousand = 1000;
Integer anotherThousand = new Integer(1000);
Только обрати внимание на то, какая аннотация написана перед конструктором Integer(int) в актуальной версии jdk:
0
hidden #3303140
20 сентября 2024, 13:22
В аннотации неспроста говорится, что вместо конструктора с числом int стоит использовать именно статический метод valueOf. Всё дело в том, что этот метод оптимизирован по сравнению с конструктором, благодаря использованию кэша. Если объяснить кэш простыми словами, то для каждого числа x из диапазона [-128; 127] заранее при старте любой программы уже создали по объекту new Integer(x), и поэтому при попытке создания числа из этого диапазона при помощи valueOf (а как мы теперь знаем, значит и при помощи автобоксинга с использованием числовых литералов) вместо создания нового объекта при помощи оператора new будет возвращена ссылка на уже имеющийся объект, которые заранее сохранили в массив
0
hidden #3303140
20 сентября 2024, 13:34
Что касается конструктора со строковым литералом Integer(String s) и метода valueOf(String s),
то ситуация абсолютно зеркальная, что и с парой метод-конструктор с целочисленным аргументом, описанной выше. Разница заключается лишь в том, что цепочка удлиняется на ещё одну операцию. При помощи парсинга (синтаксического анализа строки) аргумент String s сначала преобразуется в соответствующее ему число int, и потом будет вызван описанный выше конструктор или метод valueOf соответственно. За преобразование String -> int отвечает статический метод parseInt
Такая методика, когда есть несколько методом с одинаковым именем и разными типами аргументов, называется перегрузкой. Перегружать можно методы и конструкторы. Суть как правило заключается в том, что сама логика операции содержится только в одном из этих методов, в данном случае valueOf(int), а второй метод valueOf(String) отвечает просто за преобразование String->int и затем обращается к методу valueOf(int).
0
NightCrowSystem Engineer в Аплана
20 сентября 2024, 13:41
Смотреть в байткод оказалось интересно. Нашел эту фичу в IDEA. Новая игрушка. )))
0
NightCrowSystem Engineer в Аплана
20 сентября 2024, 15:45
"этот самый механизм, вызовет метод valueOf, который по цепочке вызовет конструктор объекта. То есть в конечном итоге не будет никакой разницы между тем, чтобы написать
Integer thousand = 1000;
Integer anotherThousand = new Integer(1000);."
Наверное все же разница есть. На лекциях тут звучало, что при обращении к статическим методам экземпляр класса не нужен.
0
hidden #3303140
21 сентября 2024, 06:20
Ты прочитал всё, что написано вокруг этого текста? Про какой экземпляр класса ты говоришь? В этом абзаце написано, что в конечном итоге и при первой и при второй инструкции экземпляр класса будет создан. Причём тут статический метод?
0
NightCrowSystem Engineer в Аплана
20 сентября 2024, 07:59
Кажется начинаю частично понимать. Поправьте, если не прав. Методы вроде toString являются статическими.
public static String toString(int i) { // фрагмент из текста класса String
Статические методы доступны без создания экземпляра класса. Таким образом, если мы объявили переменную типа Integer, то при использовании конструкции переменная.метод компилятор просто знает, где взять описание этого метода. Объект (экземпляр класса) при этом не создается.
А вот конструктор относится только к экземпляру класса (объекту).
Конструктор, когда есть объект в свою очередь вызывает метод parseInt:
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
public static int parseInt(String s, int radix) throws NumberFormatException {
//Преобразование в int
}
0
KIRAРазработчик в prosv.ruExpert
20 сентября 2024, 11:42
Integer integer2 = "222"; // А тут фигушки. Ошибка incompatible types, второй конструктор класса недоступен.
А тут не вызывается конструктор класса Integer
запись "222" создает вам объект типа String (двойные кавычки всегда воспринимаются как тип String)
И вы пытаетесь объект типа String присвоить переменной с типом Integer
Integer integer2 = "222" - (проверяется пул строк и если там есть строка, возвращается ссылка на нее, если нету, тогда создается новый объект класса String);
Строковые литералы
+3
hidden #3303140
20 сентября 2024, 12:53
Ещё небольшой комментарий.
Сначала про метод toString
> Методы вроде toString являются статическими.
> public static String toString(int i) { // фрагмент из текста класса String
Есть разные методы toString(). Тот, который есть в каждом классе, потому что любой класс наследуется от класса Object, статическим методом не является:
Именно благодаря этому методу, ты можешь вызвать метод toString() у объекта любого класса
Метод, о котором ты говоришь, во-первых содежится таки-не в классе String, а в классе Integer, и это совсем другой метод с таким же именем. Он действительно статический, содержит два параметра и служит для преобразования имеющегося десятичного числа в строку, содержащую представление этого числа в любой (допустимой) системе счисления:
И, как видишь, никакого отношения к созданию объектов Integer это отношения не имеет вообще.
Но, чтобы закончить, про статические методы, их можно (но ни при каких условиях не нужно!) вызывать у экземпляров класса вместо статического вызова:
Как видишь, вызов произойдёт, хотя твоя среда разработки возмутится, что это какая-то глупость, и будет права. Одно число способно распарсить строку для создания другого числа. Но поскольку этот вызов от значения исходного объекта никак не зависит, стоит вместо этого писать Integer.parseInt.
+1