#java #наследование #интерфейс
Например, есть интерфейс "Квартира". Нужно пройтись по всем типам квартир, которые наследуют интерфейс "Квартира", (одно-, двух-, трех- и т.д.) и, скажем, добавить их в ArrayList. Можно ли такое сделать? Если да, то как?
Ответы
Ответ 1
Это реализуемо. Это даже может быть полезно, когда вы пишите какой-нибудь расширяемый фреймворк и заранее не знаете, с какими объектами придется работать, а заставлять пользователя регистрировать классы вручную (как это происходит, например, в JDBC) почему-то неприемлимо. В общем случае вам нужно: Выполнить сканирование CLASSPATH Проверить все найденные классы через рефлексию на наследование интерфейса/класса. Вызвать через рефлексию конструктор. Сразу стоит понять: либо вы точно знаете (требуете), какой конструктор будет реализован во всех классах, либо используете дефолтный конструктор без параметров (а он создается автоматически, только если нет других явных конструкторов). Пункты 1 и 2 несколько утомительны для реализации вручную. К счастью есть отличная библиотека Reflections, которая позволит сделать это двумя строками кода. Допустим, нас интересуют все реализации интерфейса HttpHandler: Reflections reflections = new Reflections(); Set> classes = reflections.getSubTypesOf(HttpHandler.class); И все! Теперь осталось перебрать все экземпляры Class и вызвать, допустим конструктор без параметров: List handlers = new ArrayList<>(); for (Class clazz : classes) { try { handlers.add(clazz.newInstance()); } catch (InstantiationException | IllegalAccessException e) { System.out.println("Не удалось создать экземпляр: " + clazz.getCanonicalName()); } } Но! Если вы еще не пишете свои фреймворки, то есть вероятность, что вы как-то неправильно, ломая ООП, пытаетесь решить совсем иную задачу. Альтернативные реализации сканера CLASSPATH: https://github.com/lukehutch/fast-classpath-scanner Ответ 2
Следующий метод находит все классы находящийся в указанном jar архиве реализующие определенный интерфейс: Collection> getAllInterfaceImplementations(String pathToJar, Class interfaceType) throws Exception { JarFile jarFile = new JarFile(pathToJar); Enumeration e = jarFile.entries(); URL[] urls = {new URL("jar:file:" + pathToJar + "!/")}; URLClassLoader cl = URLClassLoader.newInstance(urls); Collection > classes = new ArrayList<>(); while (e.hasMoreElements()) { JarEntry je = e.nextElement(); if (je.isDirectory() || !je.getName().endsWith(".class")) continue; String className = je.getName().substring(0, je.getName().length() - ".class".length()); className = className.replace('/', '.'); Class type = cl.loadClass(className); if (interfaceType.isAssignableFrom(type)) classes.add(type); } return classes; } Использовать вот так: String pathToJar = "<путь до JAVA_HOME>/rt.jar"; for (Class type : getAllInterfaceImplementations(pathToJar, Collection.class)) System.out.println(type.getName());
Комментариев нет:
Отправить комментарий