Указание на абстрактный класс

#java #abstract-class

#java #абстрактный класс

Вопрос:

У меня есть базовые знания об абстрактном классе. Это то, что он не может быть создан сам по себе, но с классом, который его реализовал, или анонимными классами. Я надеюсь, что это правильно ..!

Но я наткнулся на приведенный ниже код.

 SAXParserFactory factory = SAXParserFactory.newInstance(); 
  

И вот newInstance исходный код:

 public static SAXParserFactory newInstance()
  86:     throws FactoryConfigurationError
  87:   {
  88:     ClassLoader loader = Thread.currentThread().getContextClassLoader();
  89:     if (loader == null)
  90:       {
  91:         loader = SAXParserFactory.class.getClassLoader();
  92:       }
  93:     String className = null;
  94:     int count = 0;
  95:     do
  96:       {
  97:         className = getFactoryClassName(loader, count  );
  98:         if (className != null)
  99:           {
 100:             try
 101:               {
 102:                 Class t = (loader != null) ? loader.loadClass(className) :
 103:                   Class.forName(className);
 104:                 return (SAXParserFactory) t.newInstance();
 105:               }
 106:             catch (ClassNotFoundException e)
 107:               {
 108:                 className = null;
 109:               }
 110:             catch (Exception e)
 111:               {
 112:                 throw new FactoryConfigurationError(e,
 113:                      "error instantiating class "   className);
 114:               }
 115:           }
 116:       }
 117:     while (className == null amp;amp; count < 3);
 118:     return new gnu.xml.stream.SAXParserFactory();
 119:   }
 120: 
 121:   private static String getFactoryClassName(ClassLoader loader, int attempt)
 122:   {
 123:     final String propertyName = "javax.xml.parsers.SAXParserFactory";
 124:     switch (attempt)
 125:       {
 126:         case 0:
 127:           return System.getProperty(propertyName);
 128:         case 1:
 129:           try
 130:             {
 131:               File file = new File(System.getProperty("java.home"));
 132:               file = new File(file, "lib");
 133:               file = new File(file, "jaxp.properties");
 134:               InputStream in = new FileInputStream(file);
 135:               Properties props = new Properties();
 136:               props.load(in);
 137:               in.close();
 138:               return props.getProperty(propertyName);
 139:             }
 140:           catch (IOException e)
 141:             {
 142:               return null;
 143:             }
 144:         case 2:
 145:           try
 146:             {
 147:               String serviceKey = "/META-INF/services/"   propertyName;
 148:               InputStream in = (loader != null) ?
 149:                  loader.getResourceAsStream(serviceKey) :
 150:                 SAXParserFactory.class.getResourceAsStream(serviceKey);
 151:               if (in != null)
 152:                 {
 153:                   BufferedReader r =
 154:                      new BufferedReader(new InputStreamReader(in));
 155:                   String ret = r.readLine();
 156:                   r.close();
 157:                   return ret;
 158:                 }
 159:             }
 160:           catch (IOException e)
 161:             {
 162:             }
 163:           return null;
 164:         default:
 165:           return null;
 166:       }
 167:   }
 168: 
  

Если вы видите код, существует возможность возврата ссылочного типа SAXParserFactory is в строках с номерами 104 и 118.

В строке 104 создается динамический класс. Я хочу знать, как вновь созданный класс может быть приведен к типу абстрактного класса SAXParserFactory ? Я здесь в замешательстве ..!

И после создания экземпляра SAXParserFactory выполняется приведенный ниже код

 SAXParser saxParser = factory.newSAXParser();
  

Итак, после SAXParserFactory создания экземпляра метод newSAXParser() абстрактного класса SAXParserFactory class должен быть реализован перед его использованием, но откуда он вызывается? Потому что класс, который реализует SAXParserFactory class, — это класс, который создается во время выполнения!

Комментарии:

1. Это сложная смесь отражения и загрузки класса, есть ли у вас опыт работы с любым из них?

2. любой экземпляр может быть приведен к одному из его суперклассов или к любому из реализуемых им интерфейсов (например, вы можете привести любой экземпляр Integer к Number или Object ) Класс, представленный t , должен быть подклассом SAXParserFactory

3.Строка 104: t является объектом класса для класса, который реализует (подклассы) SAXParserFactory , поэтому фактический класс не является абстрактным, и его можно привести без проблем.

Ответ №1:

 97: className = getFactoryClassName(loader, count  );
  

Эта строка возвращает полное имя класса, который расширяется SAXParserFactory .
Примером может быть

 oracle.xml.jaxp.JXSAXParserFactory
  

Затем

 102: Class t = (loader != null) ? loader.loadClass(className)
103:                            : Class.forName(className);
  

Запрашивает у Classloader JXSAXParserFactory Class объект ( Class<JXSAXParserFactory> ).

 104: return (SAXParserFactory) t.newInstance();
  

Class#newInstance вызывается, что в данном случае означает, что вызывается конструктор без аргументов JXSAXParserFactory .

Будучи JXSAXParserFactory extends SAXParserFactory , он может быть повышен. Это правильный термин.

Расширение означает наследование отцовской подписи. Очевидно, что при повышении производительности вы теряете дополнительные доступные члены подкласса.


SAXParserFactory#newSAXParser всегда будет ограничено при возврате SAXParser , но базовая реализация (в основном, логика) будет другой.

https://en.wikipedia.org/wiki/Polymorphism_ (computer_science)

Комментарии:

1. это действительно преобразование вверх: от Object к SAXParseFactory ? Я считаю, что это приведение вниз (приведение вверх всегда разрешено; приведение вниз включает проверку типа, что, безусловно, имеет место здесь — вы получите исключение приведения, если t это не класс, расширяющий SAXParseFactory ) {JLS использует эти термины вообще, он использует преобразование ссылок сужения / расширения}

2. @CarlosHeuberger поскольку это старый код, да, он выполняется с понижением. Более новая версия этого, я полагаю, будет использовать универсальный класс<T> . Однако мое утверждение относилось в целом (JXSAXParserFactory расширяет SAXParserFactory), на самом деле не к этой строке кода

3. @LppEdd «Эта строка возвращает полное имя класса, который расширяет SAXParserFactory», Откуда мы знаем, что SAXParserFactory реализован объектом класса Class ?

4. @Trisha mmh Я тебя не понимаю. Что вы имеете в виду? Попробуйте использовать какие-нибудь другие слова.

5. @LppEdd, В приведенном выше коде className возвращает имя ( oracle.xml.jaxp.JXSAXParserFactory ) экземпляра нового класса. И этот класс будет классом, который будет реализовывать SAXParserFactory класс abstact. Но где выполняется эта реализация? Какая часть кода, по его словам, сейчас SAXParserFactory реализована oracle.xml.jaxp.JXSAXParserFactory ?