При написании кода столкнулся с вопросом: а что же все таки быстрее? Набросал тест:
import java.util.*;
public class PolymorphTest {
public static void main(String[] args) {
if (args.length == 0) {
exit();
}
int count;
try {
count = Integer.parseInt(args[0]);
} catch (Exception e) {
count = 0;
exit();
}
List<Valued> list = Geneartor.generate(count);
List<A> listA = Geneartor.fetchA(list);
List<B> listB = Geneartor.fetchB(list);
List<C> listC = Geneartor.fetchC(list);
int sum = 0;
long millisStart = System.currentTimeMillis();
for (Valued o : list) {
sum += InstanseChecker.value(o);
}
long millisEnd = System.currentTimeMillis();
long millis = millisEnd - millisStart;
System.out.println("Seconds = " + ((millis) / 1000) + ", millis = " + millis);
millisStart = System.currentTimeMillis();
for (A o : listA) {
sum += Polymorph.value(o);
}
for (B o : listB) {
sum += Polymorph.value(o);
}
for (C o : listC) {
sum += Polymorph.value(o);
}
millisEnd = System.currentTimeMillis();
millis = millisEnd - millisStart;
System.out.println("Seconds = " + ((millis) / 1000) + ", millis = " + millis);
}
private static void exit() {
System.out.println("Need to enter Integer arg for elements count");
System.exit(0);
}
}
class Geneartor {
public static List<Valued> generate(int count) {
List<Valued> list = new ArrayList<Valued>();
for (int i = 0; i < count; i++) {
int next = new Random().nextInt(3);
switch (next) {
case 0:
list.add(new A());
break;
case 1:
list.add(new B());
break;
case 2:
list.add(new C());
break;
}
}
return list;
}
public static List<A> fetchA(List<Valued> list) {
List<A> listA = new ArrayList<A>();
for (Valued o : list) {
if (o instanceof A) {
listA.add((A) o);
}
}
return listA;
}
public static List<B> fetchB(List<Valued> list) {
List<B> listB = new ArrayList<B>();
for (Valued o : list) {
if (o instanceof B) {
listB.add((B) o);
}
}
return listB;
}
public static List<C> fetchC(List<Valued> list) {
List<C> listC = new ArrayList<C>();
for (Valued o : list) {
if (o instanceof C) {
listC.add((C) o);
}
}
return listC;
}
}
class Polymorph {
static int value(A a) {
return a.level();
}
static int value(B b) {
return b.rate();
}
static int value(C c) {
return c.value();
}
}
class InstanseChecker {
static int value(Valued valued) {
if (valued instanceof A) {
return ((A) valued).level();
} else if (valued instanceof B) {
return ((B) valued).rate();
} else if (valued instanceof C) {
return ((C) valued).value();
}
return 0;
}
}
interface Valued {}
class A implements Valued {
int level = 0;
int level() {
return level;
}
}
class B implements Valued {
int rate = 0;
int rate() {
return rate;
}
}
class C implements Valued {
int value = 0;
int value() {
return value;
}
}
Кому лень смотреть код: В двух словах: Есть три типа, A, B, C. У каждого есть метод, который возвращает значение. (В силу обстоятельств я не могу назвать эти методы у себя в коде одинаково и там они вообще будут интерфейсными типами). Но мне нужен один интерфейс для получения значения каждого из этих типов. Тест описывает три таких объекта. Создаётся список экземпляров, совершенно произвольно, он же бьётся на три списка - конкретных объектов. Есть набор полиморфных методов, с одинаковыми названиями и возвращаемым типом, но разными аргументами - типами этих объектов, и один метод, который принимает общий тип и проверяет с помощью instanceof тип конкретный, и вызывает у объектов соответствующий метод.
Результаты меня немного удивили.
Я почему то ожидал, что вызов полиморфных методов будет выполняться приблизительно с той же скоростью, что и вызов instanceof. Однако я получил результат, и буду использовать именно полиморфные методы.
Вопрос же в следующем - где можно почитать, почему так происходит и поизучать кишки этого действа?
Связывание при перегрузке (overloading) метода происходит на этапе компиляции. Для примера, что выведет следующий код?
public void m1(Object a) {
System.out.println("Object");
}
public void m1(Integer a) {
System.out.println("Integer");
}
@Test
public void test() {
Integer i = 3;
Object o = i;
m1(i);
m1(o);
}
Не смотря на то, что фактический тип будет одинаковый, вывод будет следующим:
Integer
Object
То есть никакой дополнительной работы в рантайме не выполянется. В вашем первом случае еще и дополнительно работает instanceof
.
Можете еще почитать про паттерн "Visitor" (посетитель) и узнаете еще про один способ опередления типа, хотя штука громоздкая, применять нужно аккуратно.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
при передачи по ws больших объёмов на выскакивает такое
При отправке сообщения с xml контетном в наследуемом от AbstractPhaseInterceptor классе возникает ошибка SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file