что такое кастинг в java
Приведение типов объектов в Java
Обзор приведения типов в Java, покрытый простыми и понятными примерами.
1. Обзор
Система типов Java состоит из двух типов: примитивов и ссылок.
Дальнейшее чтение:
Основы дженериков Java
Оператор Java instanceof
2. Примитивный против Ссылка
В обоих случаях мы “превращаем” один тип в другой. Но, упрощенно говоря, примитивная переменная содержит свое значение, и преобразование примитивной переменной означает необратимые изменения ее значения:
Ссылочные переменные различны ; ссылочная переменная ссылается только на объект, но не содержит самого объекта.
И приведение ссылочной переменной не затрагивает объект, на который она ссылается, а только помечает этот объект другим способом, расширяя или сужая возможности работы с ним. Приведение вверх сужает список методов и свойств, доступных этому объекту, а приведение вниз может расширить его.
Ссылка подобна дистанционному управлению объектом. Пульт дистанционного управления имеет больше или меньше кнопок в зависимости от его типа, а сам объект хранится в куче. Когда мы выполняем кастинг, мы меняем тип пульта дистанционного управления, но не меняем сам объект.
3. Апкастинг
Апкастинг тесно связан с наследованием – еще одной основной концепцией в Java. Обычно ссылочные переменные используются для ссылки на более конкретный тип. И каждый раз, когда мы это делаем, происходит скрытое повышение.
Чтобы продемонстрировать восходящее вещание, давайте определим класс Animal :
Теперь давайте расширим Животное :
Теперь мы можем создать объект класса Cat и назначить его ссылочной переменной типа Cat :
И мы также можем назначить его ссылочной переменной типа Animal :
В приведенном выше задании имеет место неявное повышение. Мы могли бы сделать это явно:
Но нет необходимости делать явное приведение дерева наследования. Компилятор знает, что cat является Животным и не отображает никаких ошибок.
Обратите внимание, что ссылка может ссылаться на любой подтип объявленного типа.
Хотя Cat объект остается Cat объектом, вызов meow() вызовет ошибку компилятора:
Но теперь мы опишем, что дает нам это предсказание. Благодаря апкастингу мы можем воспользоваться преимуществами полиморфизма.
3.1. Полиморфизм
Неявная передача происходит, когда мы добавляем объекты определенного типа в список animals :
Также распространена передача на интерфейс.
Мы можем создать Новый интерфейс и сделать Cat реализовать его:
Теперь любой объект Cat также может быть передан в Mew :
Это/| Кошка является Новым , Животным , Объектом и Кошкой . В нашем примере он может быть назначен ссылочным переменным всех четырех типов.
3.2. Переопределение
Если мы добавим некоторые записи в наши классы, мы увидим, что вызываются методы Cat ‘и Dog :
4. Даункастинг
Давайте возьмем пример:
Чтобы вызвать мяу() мы должны опустить животное к Кошке :
Внутренние скобки и тип, который они содержат, иногда называются оператором приведения. Обратите внимание, что внешние скобки также необходимы для компиляции кода.
Давайте перепишем предыдущий пример Animal Feeder с помощью метода meow() :
4.1. Оператор instanceof
Мы часто используем оператор instanceof перед понижением, чтобы проверить, принадлежит ли объект определенному типу:
4.2. Исключение ClassCastException
Чтобы продемонстрировать это, давайте удалим оператор instanceof из приведенного выше кода:
Этот код компилируется без проблем. Но если мы попытаемся запустить его, мы увидим исключение:
ява,ланг.ClassCastException: com.baeldung.casting.Собака не может быть брошена в com.baeldung.casting.Cat
ClassCastException’ s всегда выбрасывается во время выполнения, если тип, к которому мы относимся, не соответствует типу реального объекта.
Обратите внимание, что если мы попытаемся перейти к несвязанному типу, компилятор этого не допустит:
Компилятор говорит: “Не может привести от животного к строке”.
Для компиляции кода оба типа должны находиться в одном дереве наследования.
Давайте подведем итоги:
5. метод cast()
Есть еще один способ приведения объектов с помощью методов Class :
В приведенном выше примере вместо операторов cast и instanceof используются методы cast ( ) и isInstance () соответственно.
Обычно используются методы cast() и isInstance() с универсальными типами.
Давайте создадим AnimalFeederGeneric класс с feed() методом, который “кормит” только один тип животных – кошек или собак, в зависимости от значения параметра типа:
Давайте сделаем T равным Cat и убедимся, что метод возвращает только кошек:
6. Заключение
В этом основополагающем учебнике мы изучили, что такое восходящий и нисходящий переход, как их использовать и как эти концепции могут помочь вам воспользоваться преимуществами полиморфизма.
В чем разница между up-casting и down-casting относительно переменной класса
в чем разница между up-casting и down-casting относительно переменной класса?
например, в следующем классе программы Animal содержит только один метод, но класс Dog содержит два метода, а затем мы приводим переменную Dog к переменной Animal.
Если кастинг сделан, то как мы можем назвать другой метод собаки с переменной животного.
9 ответов
Downcasting было бы что-то вроде этого:
однако, если вы должны были сделать это:
чтобы вызвать метод суперкласса, вы можете сделать super.method() или путем выполнения upcast.
чтобы вызвать метод подкласса, вы должны сделать downcast. Как показано выше, вы обычно рискуете ClassCastException при этом, однако, вы можете использовать instanceof оператор для проверки типа выполнения объект перед выполнением броска, что позволяет предотвратить ClassCastException s:
Down-casting и up-casting было следующим образом:
Upcasting: когда мы хотим привести подкласс к супер классу, мы используем Upcasting (или расширение). Это происходит автоматически, не нужно ничего делать явно.
Downcasting: когда мы хотим привести супер класс к подклассу, мы используем Downcasting (или сужение), а Downcasting непосредственно невозможно в Java, явно мы должны это сделать.
Upcasting и downcasting являются важной частью Java, которая позволяет нам создавать сложные программы с использованием простого синтаксиса и дает нам большие преимущества, такие как полиморфизм или группирование различных объектов. Java разрешает объект типа подкласса рассматриваться как объект любого типа суперкласса. Это называется upcasting. Upcasting выполняется автоматически, в то время как downcasting должен выполняться вручную программистом, и я собираюсь дать все возможное, чтобы объяснить почему это так.
Upcasting и downcasting не похожи на кастинг примитивов от одного к другому, и я считаю, что это вызывает много путаницы, когда программист начинает изучать объекты кастинга.
полиморфизм: все методы в Java являются виртуальными по умолчанию. Это означает, что любой метод может быть переопределен при использовании в наследовании, если этот метод не объявлен как final или static.
вы можете увидеть пример ниже как!—6—> работы согласно типу предмета (собаки,любимчика,собаки полиции).
Предположим, у вас есть три собаки
полицейская собака-полицейская собака расширяет собаку.
полиморфизм : все методы в Java являются виртуальными по умолчанию. Это означает, что любой метод может быть переопределен при использовании в наследовании, если этот метод объявляется как final или static.(Объяснение относится к концепции виртуальных таблиц)
виртуальная таблица / таблица отправки: таблица отправки объекта будет содержать адреса динамически связанных методов объекта. Вызовы метода выполняются путем извлечения адреса метода из таблицы отправки объекта. Таблица отправки одинакова для всех объектов, принадлежащих к одному классу, и поэтому обычно используется совместно их.
Downcasting нужно сделать программистом вручную
при попытке вызвать secretID(); метод on obj3 что это PoliceDog object но ссылаться на Dog который является супер-классом в иерархии, он выдает ошибку, так как obj3 нет доступа к secretId() метод.In чтобы вызвать этот метод, вам нужно вручную понизить obj3 до PoliceDog
, который печатает ID
аналогичным образом вызвать dogName(); метод PetDog класс нужно опустить obj2 до PetDog поскольку obj2 ссылается на Dog и не имеют доступа к dogName(); метод
это причина, по которой вам нужно опустить объекты вручную если вы ссылались на свои объекты на тип супер класса.
Примечание: здесь ссылка означает вы не меняете адрес памяти ваших объектов, когда вы опускаете его, он все еще остается тем же, вы просто группируете их к определенному типу в этом случае Dog
Я знаю, что этот вопрос задан довольно давно, но для новых пользователей этого вопроса. Пожалуйста, прочитайте эту статью, где содержится полное описание по upcasting, downcasting и использованию instanceof оператор
нет необходимости поднимать вручную, это происходит само по себе:
Mammal m = (Mammal)new Cat(); равна Mammal m = new Cat();
но downcasting необходимо всегда делать вручную:
Почему это так, что upcasting является автоматическим, но downcasting должен быть ручным? Видите ли, апкастинг никогда не подводит. Но если у вас есть группа разных животных и вы хотите унизить их всех до кошки, то есть шанс, что некоторые из этих животных на самом деле собаки, и процесс терпит неудачу, бросая ClassCastException. Именно здесь следует ввести полезную функцию под названием «instanceof», который проверяет, является ли объект экземпляр некоторого класса.
для получения дополнительной информации, пожалуйста, прочитайте в этой статье
Лучшая практика Java: кастинг объектов против интерфейсов
Предположим, у нас есть следующие игрушечные интерфейсы:
и у нас есть класс, который реализует оба интерфейса:
на данный момент я вижу разные способы вызова методов на Duck и я не могу решить, какой из них является лучшей практикой. Рассмотрим такой сценарий:
Я вижу Java-код, написанный так все время, иногда в учебниках (например, pg. 300 из «Head First Design Patterns» О’Рейли) так в этом должна быть заслуга, которой мне не хватает.
если бы я написал подобный код, я бы попытался избежать downcasting к типу или интерфейсу, который не гарантируется. например, в этом случае я бы сделал что-то вроде этого:
что позволило бы мне сделать:
это ненужный перебор? какие подводные камни для этого?
Я чувствую, что этот дизайн развязывает SafeSpeakAndFly() функция от своих параметров и держит насекомых в страхе из-за компиляции проверка типа.
почему первый метод используется так широко на практике, а последний нет?
2 ответов
Я вижу Java-код, написанный так все время, иногда в учебниках (например, pg. 300 из «Head First Design Patterns» О’Рейли), поэтому в этом должна быть заслуга, которую мне не хватает.
эта книга была первоначально опубликована еще в 2004 году, и я не думаю, что Java поддерживала дженерики в то время. Поэтому небезопасное литье было тем, что очень часто использовалось тогда. Вероятно, если бы у меня не было поддержки параметрического полиморфизма в Java, я бы сначала проверьте, является ли параметр экземпляром типа, к которому я хотел бы привести его, а затем выполните фактическое приведение:
имея дженерики, однако, позволяет нам сделать это:
здесь компилятор может убедиться, что мы не пропустим что-то, что не реализует Speakable и Flyer и может обнаружить такие нахальные попытки во время компиляции.
почему первый метод используется так широко на практике, а последний нет?
Это может полагаю, вы видели много устаревшего кода. 🙂
вы можете применить аргумент, чтобы быть в то же время Speakable и Flyer создание универсального метода с пересечением типов:
таким образом, вам не нужно кастинг или создание дополнительного интерфейса.
Casting between primitive Java types
Changing a value from one data type to a variable of another type is known as data type conversion.
There are two types of casting,
Primitive Type Casting
There are two basic types of Primitive Type Casting widening and narrowing.
Widening conversions (Implicit casting)
Widening conversions in Java
Narrowing Conversions (Explicit Casting)
Narrowing conversions in Java
Reference Type Casting
Objects of classes also can be cast into objects of other classes when the source and destination classes are related by inheritance and one class is a subclass of the other. The cast can be to its own class type or to one of its subclass or superclass types or interfaces. There are compile-time rules and runtime rules for casting in java. There are two types of Reference Type Casting in Java, they are :
Up-casting is casting to a supertype, while downcasting is casting to a subtype. Supercasting is always allowed, but subcasting involves a type check and can throw a ClassCastException.
Upcasting
Casting a subtype object into a supertype and this is called upcast. In Java, we need not add an explicit cast and you can assign the object directly. Compiler will understand and cast the value to supertype. By doing this, we are lifting an object to a generic level. If we prefer, we can add an explicit cast and no issues.
Downcasting
Casting a supertype to a subtype is called downcast. This is the mostly done cast. By doing this we are telling the compiler that the value stored in the base object is of a super type. Then we are asking the runtime to assign the value. Because of downcast we get access to methods of the subtype on that object. When performing downcasting, that you’re well aware of the type of object you’ll be casting.
Вводит ли Java-кастинг накладные расходы? Зачем?
есть ли накладные расходы, когда мы бросаем объекты одного типа в другой? Или компилятор просто решает все и нет никаких затрат во время выполнения?
Это общие вещи, или бывают разные случаи?
например, предположим, что у нас есть массив Object[], где каждый элемент может иметь различные типы. Но мы всегда точно знаем, что, скажем, элемент 0 является двойным, элемент 1-строкой. (Я знаю, что это неправильный дизайн, но давайте просто предположим, что я должен был сделать этот.)
информация о типе Java все еще хранится во время выполнения? Или все забывается после компиляции, и если мы сделаем (двойные)элементы[0], мы просто будем следовать указателю и интерпретировать эти 8 байт как Двойной, что бы это ни было?
Мне очень непонятно, как сделано в Java. Если у вас есть какие-либо рекомендации по книгам или статье, то спасибо тоже.
5 ответов:
подразумевается литье, когда вы бросаете от типа к более широкому типу, который выполняется автоматически и нет накладных расходов:
явно кастинга, когда вы переходите от более широкого типа к более узкому. В этом случае вы должны явно использовать приведение следующим образом:
в этом втором случае, есть накладные расходы во время выполнения, потому что эти два типа должны быть проверены и в случае, если литья не представляется возможным, виртуальная машина должна бросить ClassCastException.
литье используется для преобразования между типы-между ссылочными типами в в частности, для типа литья операция, в которой мы заинтересованы здесь.
Upcast операции (также называемые расширение преобразований в Java Спецификация языка) преобразует a производный класс ссылка на предка ссылка на класс. Это кастинг деятельность нормально автоматическая, с тех пор это всегда безопасно и может быть реализуется непосредственно компилятором.
потупив операции (также называемые сужающие преобразования в Java Спецификация языка) преобразует ссылка класса предка на подкласс ссылка. Эта операция литья создает накладные расходы на выполнение, так как Java требует, чтобы приведение было проверено по адресу время выполнения, чтобы убедиться, что это действительно так. Если указанный объект не является экземпляр любого целевого типа для приведение или подкласс этого типа, попытка приведения не допускается и должен бросить Ява.ленг.ClassCastException.
сначала необходимо прочитать указатель на тип среды выполнения. Это необходимо для вызова виртуального метода в подобной ситуации в любом случае.
тогда значение read просто нуждается в сравнении с ожидаемым статическим типом приведения. В зависимости от архитектура набора инструкций, другая инструкция должна будет ветвиться (или неисправность) на неправильной ветви. ISA, такие как 32-битный ARM, имеют условную инструкцию и могут иметь возможность пропускать грустный путь через счастливый путь.
интерфейсы сложнее из-за множественного наследования интерфейсов. Как правило, последние два приведения к интерфейсам кэшируются в типе среды выполнения. В самые первые дни (более десяти лет назад) интерфейсы были немного медленными, но это уже не так соответствующий.
надеюсь, вы можете видеть, что такого рода вещи в значительной степени не имеют отношения к производительности. Ваш исходный код более важен. С точки зрения производительности, самым большим ударом в вашем сценарии могут быть промахи кэша от преследования указателей объектов по всему месту (информация о типе, конечно, будет общей).
компилятор не отмечает типы отдельных элементов массива. Он просто проверяет, что тип каждого выражения элемента присваивается элементу массива тип.
информация о типе Java все еще хранится во время выполнения? Или все забывается после компиляции, и если мы сделаем (двойные)элементы[0], мы просто будем следовать указателю и интерпретировать эти 8 байт как Двойной, что бы это ни было?
некоторая информация хранится во время выполнения, но не статические типы отдельных элементов. Вы можете сказать это, глядя на формат файла класса.
теоретически возможно, что JIT-компилятор может использовать «escape-анализ» для устранения ненужных проверок типов в некоторых назначениях. Однако делать это в той степени, в которой вы предлагаете, было бы за пределами реалистичной оптимизации. Отдача от анализа типов отдельных элементов была бы слишком мала.
кроме того, люди не должны писать код приложения, как это в любом случае.
для массивов Java сохраняет информацию о типе во время выполнения. Большую часть времени компилятор будет ловить ошибки типа для вас, но есть случаи, когда вы столкнетесь с ArrayStoreException при попытке сохранить объект в массиве, но тип не совпадает (и компилятор не поймал его). Элемент язык Java спецификации приводит следующий пример:
Point[] pa = cpa действует с ColoredPoint является подклассом точки, но pa[0] = new Point() недопустимо.
это противопоставляется универсальным типам, где нет информации о типе, хранящейся во время выполнения. Компилятор вставляет checkcast инструкции, где это необходимо.
эта разница в типизации для универсальных типов и массивов делает его часто непригодным для смешивания массивов и универсальных типов.
в теории, есть накладные представил. Однако современные СП являются умными. Каждая реализация отличается, но неразумно предполагать, что может существовать реализация, которая JIT оптимизировала проверки кастинга, когда она могла бы гарантировать, что никогда не будет конфликта. Что касается того, какие конкретные СП предлагают это, я не мог вам сказать. Я должен признать, что хотел бы знать специфику JIT-оптимизации сам, но это для инженеров JVM, о которых нужно беспокоиться.
в мораль истории заключается в том, чтобы сначала написать понятный код. Если вы испытываете замедления, профиль и определить вашу проблему. Шансы хорошие, что это не будет связано с кастингом. Никогда не жертвуйте чистым, безопасным кодом в попытке оптимизировать его, пока вы не знаете, что вам нужно.