Сколько обработки и использования памяти занимает кастинг в Java? - PullRequest
8 голосов
/ 19 октября 2010

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

Сколько системных ресурсов это использует:

objectName.functionOne();
((SubClass) objectName).functionOther();

Является ли это лучше, чем:

SuperClass objectA = (SuperClass) getSameInstance();
SubClass objectB = getSameInstance();
objectA.functionOne();
objectB.functionOther();

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

((SubClass) objectName).functionOther();

Однако, стоит ли это того?

Спасибо,Грей

ОБНОВЛЕНИЕ:

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

Я мог бы просто иметь:

SuperClass instanceRef;
SubClass instanceRef2;

instanceRef.etc()
instanceRef.etc2()
instanceRef.etc3()
instanceRef2.specialSubClassOnlyCall();
instanceRef2.specialSubClassOnlyCall2();

или я мог бы иметь:

SuperClass instanceRef;

instanceRef.etc()
instanceRef.etc2()
instanceRef.etc3()
((SpecialSubClass)instanceRef).specialSubClassOnlyCall();
((SpecialSubClass)instanceRef).specialSubClassOnlyCall2();

Однако я нене знаю, какой из них более эффективен.

ОБНОВЛЕНИЕ 2:

Вот пример, чтобы показать вам, о чем я говорю:

class Shape
Triangle extends Shape
Square extends Shape
Circle extends Shape
Cube extends Shape

Пример с двумя указателями: (Недостаток дополнительного указателя.)

Shape pointer1 = (Shape) getSomeRandomShape();
Cube pointer2 = null;

pointer1.getWidth();
pointer1.getHeight();
pointer1.generalShapeProp();
pointer1.generalShapeProp2();
pointer1.generalShapeProp3();

if(sure_its_cube)
{
   pointer2 = (Cube) pointer1;
   pointer2.getZAxis();
   pointer2.getOtherCubeOnlyThing();
   pointer2.getOtherCubeOnlyThing2();
   pointer2.getOtherCubeOnlyThing3();
   pointer2.getOtherCubeOnlyThing4();
}

Или я мог бы сделать это так.(Недостаток - куча приведений.)

Shape pointer1 = (Shape) getSomeRandomShape();

pointer1.getWidth();
pointer1.getHeight();
pointer1.generalShapeProp();
pointer1.generalShapeProp2();
pointer1.generalShapeProp3();

if(sure_its_cube)
{
   ((Cube)pointer1).getZAxis();
   ((Cube)pointer1).getOtherCubeOnlyThing();
   ((Cube)pointer1).getOtherCubeOnlyThing2();
   ((Cube)pointer1).getOtherCubeOnlyThing3();
   ((Cube)pointer1).getOtherCubeOnlyThing4();
}

Так что пять приведений хуже, чем один дополнительный указатель?Что это было шесть бросков или 20?Разве один бросок хуже, чем указатель.

Грей

Ответы [ 6 ]

20 голосов
/ 19 октября 2010

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

11 голосов
/ 19 октября 2010

Из вашего фрагмента кода видно, что getSameInstance() возвращает SubClass. В этом случае самое простое решение -

SubClass objectB = getSameInstance();
objectB.functionOne();
objectB.functionOther();

Никаких поворотов, никаких забот: -)

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

Дополнительное примечание: повторный вызов одного и того же метода может быть проблематичным, если метод тяжелый (в этом случае вы эффективно делаете свой код медленнее, а не быстрее) или имеет побочные эффекты (в этом случае поведение вашей программы может заметно изменится).

И, кстати, в этой строке вашего фрагмента кода

SuperClass objectA = (SuperClass) getSameInstance();

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

Обновление

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

public Shape getSomeRandomShape();

это правильно?

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

Также в последних примерах вам не нужно приводить возвращаемое значение к (Shape), поскольку оно уже Shape. Актеры просто загромождают ваш код. Точно так же, многие приведения во втором примере вашего UPDATE 2 затрудняют чтение кода. Я бы предпочел первую версию с двумя ссылками ( не указатели, кстати - у Java нет указателей).

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

3 голосов
/ 19 октября 2010

Приведение не является «операцией», выполняемой во время выполнения. Это просто необходимо компилятору для обеспечения безопасности статического типа.

Только что посмотрел на код JVM, два подхода в основном эквивалентны, они реализованы как

CHECKCAST Main$B
INVOKEVIRTUAL Main$B.mySubMethod()V

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

2 голосов
/ 19 октября 2010

Читаемость и поддержка кода должны быть вашим приоритетом в чем-то подобном, а не в производительности, если только вы на самом деле не оказались в узком месте (крайне маловероятно).

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

1 голос
/ 19 октября 2010

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

Для чего бы то ни было, вам на самом деле не нужно приводить подкласс к ссылке на суперкласс (второе решение в списке), а только наоборот. При приведении суперкласса к подклассу обычно предпочтительнее проверять его тип с instanceof перед приведением, чем делать предположения.

0 голосов
/ 20 октября 2010

Допустим, у вас есть 64-битный компьютер, и он экономит 8 байт ресурсов.Допустим, вы потратили 10 минут на обдумывание.Было ли это хорошим использованием вашего времени?

1 ГБ добавляет около 100 долларов к стоимости сервера, поэтому 8 байтов стоят примерно 0,0000008

10 минут вашего времени стоят около 1 доллара на минимальной зарплате.

Ресурс многоразовый, вашего времени нет.Что еще более важно, время, когда кто-то читает / поддерживает ваш код, вероятно, будет еще дороже, и поэтому простота / ясность гораздо важнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...