Вопрос о полиморфизме Java и кастинге

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

   private void initActivityScreenOrientPortrait()
    {
        // Avoid screen rotations (use the manifests android:screenOrientation setting)
        // Set this to nosensor or potrait

        // Set window fullscreen
        this.activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        DisplayMetrics metrics = new DisplayMetrics();
        this.activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

         // Test if it is VISUAL in portrait mode by simply checking it's size
        boolean bIsVisualPortrait = ( metrics.heightPixels >= metrics.widthPixels ); 

        if( !bIsVisualPortrait )
        { 
            // Swap the orientation to match the VISUAL portrait mode
            if( this.activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT )
             { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }
            else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ); }
        }
        else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); }

    }

Работает как шарм!

8
задан ooboo 4 July 2009 в 16:11
поделиться

8 ответов

Рассмотрим пример из реального мира:

public class Dog extends Animal

Все собаки - животные, но не все животные - собаки. Следовательно ...

public class Cat extends Animal

Заклинание животного к собаке может быть выполнено только в том случае, если рассматриваемое животное действительно является собакой. В противном случае это заставило бы Вселенную вывести свойства, уникальные для собаки (виляние хвостом, лай и т. Д.), На Животное. Этим животным вполне может быть кошка с уникальными для нее свойствами (мурлыканье, строгий режим самоочистки и т. Д.). Если приведение невозможно, тогда во время выполнения генерируется исключение ClassCastException.

Никто не хочет, чтобы собака мурлыкала.


((M) k) .getClass () дает K. Почему это? Он был преобразован в более общий M!

Вы преобразовали k в M, но все классы имеют метод getClass (). Класс k всегда K, независимо от того, указали ли вы его ссылку на M или нет. Если вы примените Dog к Animal и спросите его, что это за животное, оно все равно ответит, что это собака.

Фактически, приведение к суперклассу излишне. Собака уже является животным, и у нее есть все приемы животного, а также свои собственные. Многие инструменты анализа кода, такие как FindBugs, будут уведомлять вас об избыточных приведениях, чтобы вы могли их удалить.


Предположим, у меня есть метод doIt (), реализованный как в M, так и в K. Выполнение

((M) k) .doIt ( );

дает M или K doIt ()?

K doIt () по тем же причинам, что и выше. Приведение работает со ссылкой; он не преобразует объект в другой тип.


Можете ли вы привести пример того, когда приведение (Dog doggy = (Dog) myAnimal) имеет смысл?

Конечно, может. Представьте себе метод, который получает список животных для обработки. Всех собак нужно выгуливать, и всеми кошками нужно играть с помощью игрушки в форме птицы. Для этого мы вызываем метод takeForWalk () , который существует только в Dog, или метод play () , который существует только в Cat.

public void amuseAnimals( List<Animal> animals ) {
    for ( Animal animal : animals ) {
         if ( animal instanceof Dog ) {
             Dog doggy = (Dog)animal;
             doggy.takeForWalk( new WalkingRoute() );
         } else if ( animal instanceof Cat ) {
             Cat puss = (Cat)animal;
             puss.play( new BirdShapedToy() );
         }
     }
}
15
ответ дан 5 December 2019 в 04:58
поделиться

Чтобы добавить к ответу Фредерика, приведение объекта к чему-то не меняет его тип. Кроме того, объект может быть приведен только к тому типу, которым он уже является (компилятор просто не знает в этот момент) Вот почему невозможные преобразования никогда не будут приняты:

Integer i = (Integer) new String();

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

1
ответ дан 5 December 2019 в 04:58
поделиться

Просто потому, что E расширяет C, C не становится E ... E, с другой стороны, является C

Edit: Чтобы развернуть комментарий Марка ниже ... Только потому, что каждая женщина - человек, не все люди - женщины. Все люди разделяют "человеческий интерфейс" ногами, руками, лицами и т. Д. Женщины расширяют его функциональностью, которая возвращает хорошие чувства, когда вы даете алмазы и золото.

Двойное преобразование int => даже не связано, поскольку это не так. приведение класса, но преобразование, указывающее компилятору хранить все, что находится в x, в y (что оказывается двойным).

((M) k) .getClass () дает K.

, потому что k по-прежнему является K, даже если вы примените его к M или объекту (или чему-то еще, что это может быть).

Edit: Я думаю, что путаница здесь в том, что вы считаете, что k "становится" M, когда вы его разыгрываете , это не т. Вы просто относитесь к нему как к M. Если вы спросите кого-то, кто является «владельцем собаки», что это за порода, он не вернет «Это собака», причина просто в том, что метод getBreedName (), вероятно, был переопределен в подклассе LabradorOwner для возврата » Лабрадор ». То же самое и с getClass (), он вернет класс реализации. Это будет не M, а K, который также будет M просто потому, что K расширяет M.

7
ответ дан 5 December 2019 в 04:58
поделиться

Вы не можете приводить объекты в Java.

Вы можете приводить ссылки в Java.

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

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

8
ответ дан 5 December 2019 в 04:58
поделиться

the int/double is unrelated; that is a conversion, not a cast - there is no relationship between int and double.

Re the question; a type's object is fixed at creation. An object that is a C is not (and can never be) an E. However, you can treat an E as a C, since inheritance represents "is a". For example:

E e = new E();
C c = e;

Here we still only have one object - simply that the c variable thinks of it as a C, so won't expose methods specific to E (even though the object is an E).

If we then add:

E secondE = (E) c;

This is a type check; again, we haven't changed the object, but to put c into an E variable requires us to prove to the compiler/runtime that it really is an E. We didn't need this in the first example as it can already prove that any E is also a C.

Likewise, with the getClass() - all the cast does is change how the compiler thinks of the object; you haven't changes the object itself. It is still a K.

You need to separate variables from objects. The cast is talking about the variables; they don't change the object.

4
ответ дан 5 December 2019 в 04:58
поделиться

Что касается первого вопроса, вы не можете преобразовать суперкласс в подкласс, потому что подкласс добавляет элементы, которых у суперкласса нет. Как компилятор должен знать, какие значения вводить при преобразовании? По сути, E - это C, но C не является E.

getClass () получает тип объекта в памяти. Приведение к M просто скрывает тот факт, что это K, и не меняет базовый объект.

0
ответ дан 5 December 2019 в 04:58
поделиться

((M) k) .getClass () дает K. Почему это так? Он был преобразован в более общий M!

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

Как это имеет отношение к этому вопросу? Допустим, есть план McMansion и план McMansionWithHeatedPool . McMansionWithHeatedPool является расширением McMansion с подогреваемым бассейном.

Теперь, если вы видите настоящий McMansionWithHeatedPool , для этого объекта:

  1. Концептуально (то есть, если вы посмотрите на чертежи архитектора), вы увидите, что McMansionWithHeatedPool явно также McMansion . Следовательно, апкаст разрешен. (По той же причине объект McMansion не может быть преобразован в тип McMansionWithHeatedPool : нет бассейна с подогревом!)

  2. (( McMansion ) k). getClass () дает McMansionWithHeatedPool , потому что k по-прежнему является McMansionWithHeatedPool . Приведение типа выполняется для выражения, а не для объекта.

1
ответ дан 5 December 2019 в 04:58
поделиться

«Если компилятор рассматривает его как M, он должен выполнять методы M».
Компилятор обрабатывает ссылку как M. Экземпляр , на который указывает ссылка, имеет тип K, а не M. Вы не можете привести ссылку и предположить, что это означает, что экземпляр внезапно изменить поведение. Компилятор должен убедиться, что метод, который вы вызываете для указанной ссылки, существует. Это не имеет ничего общего с тем, какая реализация вызывается, только то, что реализация действительно существует.

1
ответ дан 5 December 2019 в 04:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: