Философия Java3
Шрифт:
}
}
class Belt extends Part {}
class FanBelt extends Belt {
public static class Factory
implements typeinfo.factory.Factory<FanBelt> {
public FanBelt createO { return new FanBeltO; }
}
}
class GeneratorBelt extends Belt { public static class Factory
implements typeinfo.factory.Factory<GeneratorBelt> { public GeneratorBelt createO {
return new GeneratorBeltO:
}
class PowerSteeringBelt extends Belt { public static class Factory
implements typei nfо.factory.Factory<PowerSteeri ngBelt> { public PowerSteeringBelt createO {
return new PowerSteeringBeltO;
}
}
}
public class RegisteredFactories {
public static void main(String[] args) { for(int i = 0; i < 10; i++)
System.out.pri ntin(Part.createRandom);
}
} /* Output: GeneratorBelt CabinAirFiIter GeneratorBelt AirFiIter PowerSteeringBelt CabinAirFiIter Fuel Filter PowerSteeringBelt PowerSteeringBelt Fuel Filter *///:-
He
Хотя для включения всех фабрик в список можно воспользоваться вызовом Collections.addAll, компилятор выдает предупреждение, поэтому я вернулся к вызовам add. Метод createRandom случайным образом выбирает объект фабрики из partFactories и вызывает его метод create для получения нового объекта Part.
instanceof и сравнение Class
При получении информации о типе объекта важно различать действие любой формы оператора instanceof (будь это сам оператор instanceof или метод isInstanceO ~~ они дают одинаковые результаты) и прямого сравнения объектов Class. Вот пример, который показывает, в чем их различия:
//. typeinfo/FamilyVsExactType java // Различия между instanceof и class package typeinfo,
import static net mindview util.Print.*, class Base {}
class Derived extends Base {}
public class FamilyVsExactType { static void test(Object x) {
print ("Тестируем x типа " + x.getClassO); printC'x instanceof Base " + (x instanceof Base)), printC'x instanceof Derived "+ (x instanceof Derived)); print("Base.isInstance(x) "+ Base.class.islnstance(x)); print("Derived islnstance(x) " +
Deri ved.class.i slnstance(x)); printC'x getClassO == Base.class " +
(x.getClassO == Base.class)); printC'x.getClassO == Derived.class " +
(x.getClassO == Deri ved. cl ass)). print("x.getClassO.equals(Base.class)) "+
(x getClassO .equals(Base.class))); printC'x getClassO equals (Deri ved. class)) " + (x.getClassO. equals (Deri ved. class)));
}
public static void main(String[] args) { test(new BaseO); test (new DerivedO),
}
} /* Output:
Тестируем x типа class typeinfo.Base x instanceof Base true x instanceof Derived false Base islnstance(x) true Derived islnstance(x) false x getClassO == Base.class true x getClassO == Derived class false x getClassO equals(Base.class)) true x.getClassO equals(Derived.class)) false Тестируем x типа class typeinfo.Derived x instanceof Base true x instanceof Derived true Base.islnstance(x) true Derived.islnstance(x) true x.getClassO == Base.class false x.getClassO == Derived class true x.getClassO equals(Base.class)) false x.getClassO.equals(Derived.class)) true *///:-
Метод test осуществляет проверку типов полученного объекта, используя для этого обе формы оператора instanceof. Затем он получает ссылку на объект Class и использует операцию сравнения ссылок == и метод equals, чтобы проверить объекты Class на эквивалентность.
Рефлексия: динамическая информация о классе
Если вы не знаете точный тип объекта, RTTI сообщит вам его. Однако в этом случае существуют ограничения: тип должен быть известен еще во время компиляции программы, иначе определить его с помощью RTTI и сделать с этой информацией что-то полезное будет невозможно. Другими словами, компилятор должен располагать информацией обо всех классах, к которым вы затем хотели бы применить динамическое определение типов (RTTI).
Сначала кажется, что это ограничение не столь существенно, но предположим, что у вас появилась ссылка на объект, который не находится в пространстве вашей программы. Более того, класс этого объекта недоступен во время ее компиляции. Например, вы получили последовательность байтов с диска или из сетевого соединения, и вам сказали, что эта последовательность представляет некоторый класс. Но компилятор ничего не знал об этом классе, когда обрабатывал вашу программу, как же его можно использовать?
В традиционных средах программирования такая задача показалась бы далекой от реальности. Однако границы мира программирования все больше расширяются и мы все чаще встречаемся с такими ситуациями. Во-первых, такие возможности требуются для компонентного программирования, которое служит основой для систем быстрой разработки приложений (Rapid Application Development, RAD). Это визуальный подход для создания программ (экран представлен в виде «формы»), где значки, представляющие визуальные компоненты, перетаскиваются на форму. Затем происходит настройка этих компонентов, они устанавливаются в некоторое состояние во время работы программы. Чтобы изменить состояние компонентов, необходимо некоторым образом создавать их экземпляры, просматривать их содержимое, считывать и записывать внутренние значения. Вдобавок компоненты с поддержкой событий графического интерфейса должны как-то рассказать о них, чтобы система быстрой разработки приложений помогла программисту реализовать поддержку этих событий. Механизм рефлексии предоставляет средства для получения информации о доступных методах и их именах. Такое компонентное программирование поддерживается и в Java, с помощью технологии JavaBeans.
Другая важная предпосылка поддержки динамической информации о классе — предоставление возможности создавать и использовать объекты на удаленных платформах. Этот механизм, называемый удаленным вызовом методов (Remote Method Invocation, RMI), позволяет программе на Java распределять свои объекты по нескольким машинам. Необходимость в удаленном вызове методов возникает по разным причинам: например, при выполнении задачи с интенсивными вычислениями можно сбалансировать нагрузку по доступным компьютерам. Иногда код, выполняющий определенные операции, размещается на одной машине, чтобы она стала общим хранилищем этих операций и любые изменения кода на такой машине автоматически распространялись на всех клиентов этого кода. (Интересный поворот — компьютер существует исключительно для того, чтобы упростить внесение изменений в программное обеспечение!) Ко всему прочему распределенное программирование также поддерживает удаленное специализированное оборудование, которое эффективно выполняет некоторые задачи — например, обращение матриц, — которые при решении их на локальной машине могут потребовать слишком много времени и ресурсов.