2

I've a basic knowledge of abstract class. Its that it cannot be instantiated itself but with class who is implemented it or the anonymous classes. I hope its right..!

But I've came across a below code.

SAXParserFactory factory = SAXParserFactory.newInstance(); 

And here's a newInstance sourc code:

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 && 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: 

If you see the code, there is a possibility of returning Reference type of SAXParserFactory is at line number 104 and 118.

At line 104, Its creating dynamic class. I want to know how newly created class can be casted into abstract class type SAXParserFactory ? I'm confused Here..!

And after Instantiating SAXParserFactory, below code runs

SAXParser saxParser = factory.newSAXParser();

So once SAXParserFactory is Instantiated, newSAXParser() method of abstract class SAXParserFactory class should be implemented before using it, But From where its being called ? Because the class who implements SAXParserFactory class is a class which is created at run time!

Carlos Cavero
  • 3,011
  • 5
  • 21
  • 41
Trisha
  • 51
  • 1
  • 7
  • This is a complex mixture of reflection and class loading, do you have experience with either of them? – luk2302 Mar 12 '19 at 15:40
  • any instance can be cast to one of its superclasses or to any of the interfaces it implements (e.g. you can cast any instance of `Integer` to `Number` or `Object`) The class represented by `t` must be a subclass of `SAXParserFactory` – user85421 Mar 12 '19 at 15:40
  • *Line 104:* `t` is the Class object for a class that implements (subclasses) `SAXParserFactory`, so the actual class is not abstract and it can be cast without issue. – Andreas Mar 12 '19 at 15:40

1 Answers1

4
97: className = getFactoryClassName(loader, count++);

This line returns the full name of a class which extends SAXParserFactory.
An example might be

oracle.xml.jaxp.JXSAXParserFactory

Then

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

Asks the Classloader for the JXSAXParserFactory Class object (Class<JXSAXParserFactory>).

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

Class#newInstance is invoked, which in this case means the no-args constructor of JXSAXParserFactory is called.

Being the JXSAXParserFactory extends SAXParserFactory, it can be upcasted. This is the right term.

Extending means inheriting the father signature. Obviously by upcasting, you loose the additional exposed members of the sub-class.


SAXParserFactory#newSAXParser will always be limited at returning a SAXParser, but the underlying implementation (basically, the logic) will be different.

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

LppEdd
  • 20,274
  • 11
  • 84
  • 139
  • is that really up-casting: from `Object` to `SAXParseFactory`? I believe that is a down-cast, (up-casting is always allowed; down-casting involves type checking, which definitively is the case here - you'll get an cast exception if `t` is not a class extending `SAXParseFactory`) {the JLS uses these terms at all, it uses Narrowing/Widening Reference Conversion} – user85421 Mar 12 '19 at 16:00
  • @CarlosHeuberger being this is old code, yes, it's down-casting. Newer version of this, I suppose, would use a generic Class. However my statement was referring in general (JXSAXParserFactory extends SAXParserFactory), not really to that line of code – LppEdd Mar 12 '19 at 16:03
  • @LppEdd "This line returns the full name of a class which extends SAXParserFactory", How do we know SAXParserFactory is implemented by the class Class's object ? – Trisha Mar 12 '19 at 18:15
  • @Trisha mmh I'm not following you. What do you mean? Try with some other words. – LppEdd Mar 12 '19 at 18:19
  • @LppEdd, In above code `className` returns the name (`oracle.xml.jaxp.JXSAXParserFactory`) of new Class's instance. And that class is going to be the class which will be implementing `SAXParserFactory` abstact class. But where this implementation is being done ? Which part of code it says that now `SAXParserFactory` is implemented by `oracle.xml.jaxp.JXSAXParserFactory` ? – Trisha Mar 12 '19 at 18:24
  • @Trisha nowhere here. That JXSAXParserFactory resides in a different JAR package, and is found because it is inside the application classpath. Other than that you know it via its JavaDoc https://docs.oracle.com/cd/B14099_19/web.1012/b12024/oracle/xml/jaxp/JXSAXParserFactory.html – LppEdd Mar 12 '19 at 18:26
  • @Trisha That class is already implemented. Its bytecode definition is already inside the application. – LppEdd Mar 12 '19 at 18:27
  • @LppEdd, Okay..! Makes sense....but then what about 'SAXParser', Its also a abstract class. And `SAXParserFactory.newInstance(); ` is actually a `oracle.xml.jaxp.JXSAXParserFactory` class. Then How and who is implementing 'SAXParser' class now ? – Trisha Mar 12 '19 at 18:50
  • @Trisha SAXParser acts just as a "signature" in this case, the real implementation is provided by someone else. It's the same concept as with JXSAXParserFactory – LppEdd Mar 12 '19 at 18:51
  • @Trisha https://docs.oracle.com/cd/B28359_01/appdev.111/b28391/oracle/xml/jaxp/JXSAXParser.html – LppEdd Mar 12 '19 at 18:53