ClassLoader源码


1
/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/* 18 * Copyright (C) 2008 The Android Open Source Project 19 * 20 * Licensed under the Apache License, Version 2.0 (the "License"); 21 * you may not use this file except in compliance with the License. 22 * You may obtain a copy of the License at 23 * 24 * http://www.apache.org/licenses/LICENSE-2.0 25 * 26 * Unless required by applicable law or agreed to in writing, software 27 * distributed under the License is distributed on an "AS IS" BASIS, 28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 29 * See the License for the specific language governing permissions and 30 * limitations under the License. 31 */ 32 33package java.lang; 34 35import dalvik.system.PathClassLoader; 36import java.io.IOException; 37import java.io.InputStream; 38import java.net.URL; 39import java.nio.ByteBuffer; 40import java.security.ProtectionDomain; 41import java.util.Collection; 42import java.util.Collections; 43import java.util.Enumeration; 44import java.util.HashMap; 45import java.util.Map; 46import java.util.Set; 47 48/** 49 * Loads classes and resources from a repository. One or more class loaders are 50 * installed at runtime. These are consulted whenever the runtime system needs a 51 * specific class that is not yet available in-memory. Typically, class loaders 52 * are grouped into a tree where child class loaders delegate all requests to 53 * parent class loaders. Only if the parent class loader cannot satisfy the 54 * request, the child class loader itself tries to handle it. 55 * <p> 56 * {@code ClassLoader} is an abstract class that implements the common 57 * infrastructure required by all class loaders. Android provides several 58 * concrete implementations of the class, with 59 * {@link dalvik.system.PathClassLoader} being the one typically used. Other 60 * applications may implement subclasses of {@code ClassLoader} to provide 61 * special ways for loading classes. 62 * </p> 63 * @see Class 64 */ 65public abstract class ClassLoader { 66 67 /** 68 * The 'System' ClassLoader - the one that is responsible for loading 69 * classes from the classpath. It is not equal to the bootstrap class loader - 70 * that one handles the built-in classes. 71 * 72 * Because of a potential class initialization race between ClassLoader and 73 * java.lang.System, reproducible when using JDWP with "suspend=y", we defer 74 * creation of the system class loader until first use. We use a static 75 * inner class to get synchronization at init time without having to sync on 76 * every access. 77 * 78 * @see #getSystemClassLoader() 79 */ 80 static private class SystemClassLoader { 81 public static ClassLoader loader = ClassLoader.createSystemClassLoader(); 82 } 83 84 /** 85 * The parent ClassLoader. 86 */ 87 private ClassLoader parent; 88 89 /** 90 * The packages known to the class loader. 91 */ 92 private Map<String, Package> packages = new HashMap<String, Package>(); 93 94 /** 95 * To avoid unloading individual classes, {@link java.lang.reflect.Proxy} 96 * only generates one class for each set of interfaces. This maps sets of 97 * interfaces to the proxy class that implements all of them. It is declared 98 * here so that these generated classes can be unloaded with their class 99 * loader. 100 * 101 * @hide 102 */ 103 public final Map<Set<Class<?>>, Class<?>> proxyCache 104 = Collections.synchronizedMap(new HashMap<Set<Class<?>>, Class<?>>()); 105 106 /** 107 * Create the system class loader. Note this is NOT the bootstrap class 108 * loader (which is managed by the VM). We use a null value for the parent 109 * to indicate that the bootstrap loader is our parent. 110 */ 111 private static ClassLoader createSystemClassLoader() { 112 String classPath = System.getProperty("java.class.path", "."); 113 114 // String[] paths = classPath.split(":"); 115 // URL[] urls = new URL[paths.length]; 116 // for (int i = 0; i < paths.length; i++) { 117 // try { 118 // urls[i] = new URL("file://" + paths[i]); 119 // } 120 // catch (Exception ex) { 121 // ex.printStackTrace(); 122 // } 123 // } 124 // 125 // return new java.net.URLClassLoader(urls, null); 126 127 // TODO Make this a java.net.URLClassLoader once we have those? 128 return new PathClassLoader(classPath, BootClassLoader.getInstance()); 129 } 130 131 /** 132 * Returns the system class loader. This is the parent for new 133 * {@code ClassLoader} instances and is typically the class loader used to 134 * start the application. 135 */ 136 public static ClassLoader getSystemClassLoader() { 137 return SystemClassLoader.loader; 138 } 139 140 /** 141 * Finds the URL of the resource with the specified name. The system class 142 * loader's resource lookup algorithm is used to find the resource. 143 * 144 * @return the {@code URL} object for the requested resource or {@code null} 145 * if the resource can not be found. 146 * @param resName 147 * the name of the resource to find. 148 * @see Class#getResource 149 */ 150 public static URL getSystemResource(String resName) { 151 return SystemClassLoader.loader.getResource(resName); 152 } 153 154 /** 155 * Returns an enumeration of URLs for the resource with the specified name. 156 * The system class loader's resource lookup algorithm is used to find the 157 * resource. 158 * 159 * @return an enumeration of {@code URL} objects containing the requested 160 * resources. 161 * @param resName 162 * the name of the resource to find. 163 * @throws IOException 164 * if an I/O error occurs. 165 */ 166 public static Enumeration<URL> getSystemResources(String resName) throws IOException { 167 return SystemClassLoader.loader.getResources(resName); 168 } 169 170 /** 171 * Returns a stream for the resource with the specified name. The system 172 * class loader's resource lookup algorithm is used to find the resource. 173 * Basically, the contents of the java.class.path are searched in order, 174 * looking for a path which matches the specified resource. 175 * 176 * @return a stream for the resource or {@code null}. 177 * @param resName 178 * the name of the resource to find. 179 * @see Class#getResourceAsStream 180 */ 181 public static InputStream getSystemResourceAsStream(String resName) { 182 return SystemClassLoader.loader.getResourceAsStream(resName); 183 } 184 185 /** 186 * Constructs a new instance of this class with the system class loader as 187 * its parent. 188 */ 189 protected ClassLoader() { 190 this(getSystemClassLoader(), false); 191 } 192 193 /** 194 * Constructs a new instance of this class with the specified class loader 195 * as its parent. 196 * 197 * @param parentLoader 198 * The {@code ClassLoader} to use as the new class loader's 199 * parent. 200 */ 201 protected ClassLoader(ClassLoader parentLoader) { 202 this(parentLoader, false); 203 } 204 205 /* 206 * constructor for the BootClassLoader which needs parent to be null. 207 */ 208 ClassLoader(ClassLoader parentLoader, boolean nullAllowed) { 209 if (parentLoader == null && !nullAllowed) { 210 throw new NullPointerException("parentLoader == null && !nullAllowed"); 211 } 212 parent = parentLoader; 213 } 214 215 /** 216 * Constructs a new class from an array of bytes containing a class 217 * definition in class file format. 218 * 219 * @param classRep 220 * the memory image of a class file. 221 * @param offset 222 * the offset into {@code classRep}. 223 * @param length 224 * the length of the class file. 225 * @return the {@code Class} object created from the specified subset of 226 * data in {@code classRep}. 227 * @throws ClassFormatError 228 * if {@code classRep} does not contain a valid class. 229 * @throws IndexOutOfBoundsException 230 * if {@code offset < 0}, {@code length < 0} or if 231 * {@code offset + length} is greater than the length of 232 * {@code classRep}. 233 * @deprecated Use {@link #defineClass(String, byte[], int, int)} 234 */ 235 @Deprecated 236 protected final Class<?> defineClass(byte[] classRep, int offset, int length) 237 throws ClassFormatError { 238 throw new UnsupportedOperationException("can't load this type of class file"); 239 } 240 241 /** 242 * Constructs a new class from an array of bytes containing a class 243 * definition in class file format. 244 * 245 * @param className 246 * the expected name of the new class, may be {@code null} if not 247 * known. 248 * @param classRep 249 * the memory image of a class file. 250 * @param offset 251 * the offset into {@code classRep}. 252 * @param length 253 * the length of the class file. 254 * @return the {@code Class} object created from the specified subset of 255 * data in {@code classRep}. 256 * @throws ClassFormatError 257 * if {@code classRep} does not contain a valid class. 258 * @throws IndexOutOfBoundsException 259 * if {@code offset < 0}, {@code length < 0} or if 260 * {@code offset + length} is greater than the length of 261 * {@code classRep}. 262 */ 263 protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length) 264 throws ClassFormatError { 265 throw new UnsupportedOperationException("can't load this type of class file"); 266 } 267 268 /** 269 * Constructs a new class from an array of bytes containing a class 270 * definition in class file format and assigns the specified protection 271 * domain to the new class. If the provided protection domain is 272 * {@code null} then a default protection domain is assigned to the class. 273 * 274 * @param className 275 * the expected name of the new class, may be {@code null} if not 276 * known. 277 * @param classRep 278 * the memory image of a class file. 279 * @param offset 280 * the offset into {@code classRep}. 281 * @param length 282 * the length of the class file. 283 * @param protectionDomain 284 * the protection domain to assign to the loaded class, may be 285 * {@code null}. 286 * @return the {@code Class} object created from the specified subset of 287 * data in {@code classRep}. 288 * @throws ClassFormatError 289 * if {@code classRep} does not contain a valid class. 290 * @throws IndexOutOfBoundsException 291 * if {@code offset < 0}, {@code length < 0} or if 292 * {@code offset + length} is greater than the length of 293 * {@code classRep}. 294 * @throws NoClassDefFoundError 295 * if {@code className} is not equal to the name of the class 296 * contained in {@code classRep}. 297 */ 298 protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length, 299 ProtectionDomain protectionDomain) throws java.lang.ClassFormatError { 300 throw new UnsupportedOperationException("can't load this type of class file"); 301 } 302 303 /** 304 * Defines a new class with the specified name, byte code from the byte 305 * buffer and the optional protection domain. If the provided protection 306 * domain is {@code null} then a default protection domain is assigned to 307 * the class. 308 * 309 * @param name 310 * the expected name of the new class, may be {@code null} if not 311 * known. 312 * @param b 313 * the byte buffer containing the byte code of the new class. 314 * @param protectionDomain 315 * the protection domain to assign to the loaded class, may be 316 * {@code null}. 317 * @return the {@code Class} object created from the data in {@code b}. 318 * @throws ClassFormatError 319 * if {@code b} does not contain a valid class. 320 * @throws NoClassDefFoundError 321 * if {@code className} is not equal to the name of the class 322 * contained in {@code b}. 323 */ 324 protected final Class<?> defineClass(String name, ByteBuffer b, 325 ProtectionDomain protectionDomain) throws ClassFormatError { 326 327 byte[] temp = new byte[b.remaining()]; 328 b.get(temp); 329 return defineClass(name, temp, 0, temp.length, protectionDomain); 330 } 331 332 /** 333 * Overridden by subclasses, throws a {@code ClassNotFoundException} by 334 * default. This method is called by {@code loadClass} after the parent 335 * {@code ClassLoader} has failed to find a loaded class of the same name. 336 * 337 * @param className 338 * the name of the class to look for. 339 * @return the {@code Class} object that is found. 340 * @throws ClassNotFoundException 341 * if the class cannot be found. 342 */ 343 protected Class<?> findClass(String className) throws ClassNotFoundException { 344 throw new ClassNotFoundException(className); 345 } 346 347 /** 348 * Returns the class with the specified name if it has already been loaded 349 * by the VM or {@code null} if it has not yet been loaded. 350 * 351 * @param className 352 * the name of the class to look for. 353 * @return the {@code Class} object or {@code null} if the requested class 354 * has not been loaded. 355 */ 356 protected final Class<?> findLoadedClass(String className) { 357 ClassLoader loader; 358 if (this == BootClassLoader.getInstance()) 359 loader = null; 360 else 361 loader = this; 362 return VMClassLoader.findLoadedClass(loader, className); 363 } 364 365 /** 366 * Finds the class with the specified name, loading it using the system 367 * class loader if necessary. 368 * 369 * @param className 370 * the name of the class to look for. 371 * @return the {@code Class} object with the requested {@code className}. 372 * @throws ClassNotFoundException 373 * if the class can not be found. 374 */ 375 protected final Class<?> findSystemClass(String className) throws ClassNotFoundException { 376 return Class.forName(className, false, getSystemClassLoader()); 377 } 378 379 /** 380 * Returns this class loader's parent. 381 * 382 * @return this class loader's parent or {@code null}. 383 */ 384 public final ClassLoader getParent() { 385 return parent; 386 } 387 388 /** 389 * Returns the URL of the resource with the specified name. This 390 * implementation first tries to use the parent class loader to find the 391 * resource; if this fails then {@link #findResource(String)} is called to 392 * find the requested resource. 393 * 394 * @param resName 395 * the name of the resource to find. 396 * @return the {@code URL} object for the requested resource or {@code null} 397 * if the resource can not be found 398 * @see Class#getResource 399 */ 400 public URL getResource(String resName) { 401 URL resource = parent.getResource(resName); 402 if (resource == null) { 403 resource = findResource(resName); 404 } 405 return resource; 406 } 407 408 /** 409 * Returns an enumeration of URLs for the resource with the specified name. 410 * This implementation first uses this class loader's parent to find the 411 * resource, then it calls {@link #findResources(String)} to get additional 412 * URLs. The returned enumeration contains the {@code URL} objects of both 413 * find operations. 414 * 415 * @return an enumeration of {@code URL} objects for the requested resource. 416 * @param resName 417 * the name of the resource to find. 418 * @throws IOException 419 * if an I/O error occurs. 420 */ 421 @SuppressWarnings("unchecked") 422 public Enumeration<URL> getResources(String resName) throws IOException { 423 424 Enumeration<URL> first = parent.getResources(resName); 425 Enumeration<URL> second = findResources(resName); 426 427 return new TwoEnumerationsInOne(first, second); 428 } 429 430 /** 431 * Returns a stream for the resource with the specified name. See 432 * {@link #getResource(String)} for a description of the lookup algorithm 433 * used to find the resource. 434 * 435 * @return a stream for the resource or {@code null} if the resource can not be found 436 * @param resName 437 * the name of the resource to find. 438 * @see Class#getResourceAsStream 439 */ 440 public InputStream getResourceAsStream(String resName) { 441 try { 442 URL url = getResource(resName); 443 if (url != null) { 444 return url.openStream(); 445 } 446 } catch (IOException ex) { 447 // Don't want to see the exception. 448 } 449 450 return null; 451 } 452 453 /** 454 * Loads the class with the specified name. Invoking this method is 455 * equivalent to calling {@code loadClass(className, false)}. 456 * <p> 457 * <strong>Note:</strong> In the Android reference implementation, the 458 * second parameter of {@link #loadClass(String, boolean)} is ignored 459 * anyway. 460 * </p> 461 * 462 * @return the {@code Class} object. 463 * @param className 464 * the name of the class to look for. 465 * @throws ClassNotFoundException 466 * if the class can not be found. 467 */ 468 public Class<?> loadClass(String className) throws ClassNotFoundException { 469 return loadClass(className, false); 470 } 471 472 /** 473 * Loads the class with the specified name, optionally linking it after 474 * loading. The following steps are performed: 475 * <ol> 476 * <li> Call {@link #findLoadedClass(String)} to determine if the requested 477 * class has already been loaded.</li> 478 * <li>If the class has not yet been loaded: Invoke this method on the 479 * parent class loader.</li> 480 * <li>If the class has still not been loaded: Call 481 * {@link #findClass(String)} to find the class.</li> 482 * </ol> 483 * <p> 484 * <strong>Note:</strong> In the Android reference implementation, the 485 * {@code resolve} parameter is ignored; classes are never linked. 486 * </p> 487 * 488 * @return the {@code Class} object. 489 * @param className 490 * the name of the class to look for. 491 * @param resolve 492 * Indicates if the class should be resolved after loading. This 493 * parameter is ignored on the Android reference implementation; 494 * classes are not resolved. 495 * @throws ClassNotFoundException 496 * if the class can not be found. 497 */ 498 protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { 499 Class<?> clazz = findLoadedClass(className); 500 501 if (clazz == null) { 502 ClassNotFoundException suppressed = null; 503 try { 504 clazz = parent.loadClass(className, false); 505 } catch (ClassNotFoundException e) { 506 suppressed = e; 507 } 508 509 if (clazz == null) { 510 try { 511 clazz = findClass(className); 512 } catch (ClassNotFoundException e) { 513 e.addSuppressed(suppressed); 514 throw e; 515 } 516 } 517 } 518 519 return clazz; 520 } 521 522 /** 523 * Forces a class to be linked (initialized). If the class has already been 524 * linked this operation has no effect. 525 * <p> 526 * <strong>Note:</strong> In the Android reference implementation, this 527 * method has no effect. 528 * </p> 529 * 530 * @param clazz 531 * the class to link. 532 */ 533 protected final void resolveClass(Class<?> clazz) { 534 // no-op, doesn't make sense on android. 535 } 536 537 /** 538 * Finds the URL of the resource with the specified name. This 539 * implementation just returns {@code null}; it should be overridden in 540 * subclasses. 541 * 542 * @param resName 543 * the name of the resource to find. 544 * @return the {@code URL} object for the requested resource. 545 */ 546 protected URL findResource(String resName) { 547 return null; 548 } 549 550 /** 551 * Finds an enumeration of URLs for the resource with the specified name. 552 * This implementation just returns an empty {@code Enumeration}; it should 553 * be overridden in subclasses. 554 * 555 * @param resName 556 * the name of the resource to find. 557 * @return an enumeration of {@code URL} objects for the requested resource. 558 * @throws IOException 559 * if an I/O error occurs. 560 */ 561 @SuppressWarnings( { 562 "unchecked", "unused" 563 }) 564 protected Enumeration<URL> findResources(String resName) throws IOException { 565 return Collections.emptyEnumeration(); 566 } 567 568 /** 569 * Returns the absolute path of the native library with the specified name, 570 * or {@code null}. If this method returns {@code null} then the virtual 571 * machine searches the directories specified by the system property 572 * "java.library.path". 573 * <p> 574 * This implementation always returns {@code null}. 575 * </p> 576 * 577 * @param libName 578 * the name of the library to find. 579 * @return the absolute path of the library. 580 */ 581 protected String findLibrary(String libName) { 582 return null; 583 } 584 585 /** 586 * Returns the package with the specified name. Package information is 587 * searched in this class loader. 588 * 589 * @param name 590 * the name of the package to find. 591 * @return the package with the requested name; {@code null} if the package 592 * can not be found. 593 */ 594 protected Package getPackage(String name) { 595 synchronized (packages) { 596 return packages.get(name); 597 } 598 } 599 600 /** 601 * Returns all the packages known to this class loader. 602 * 603 * @return an array with all packages known to this class loader. 604 */ 605 protected Package[] getPackages() { 606 synchronized (packages) { 607 Collection<Package> col = packages.values(); 608 Package[] result = new Package[col.size()]; 609 col.toArray(result); 610 return result; 611 } 612 } 613 614 /** 615 * Defines and returns a new {@code Package} using the specified 616 * information. If {@code sealBase} is {@code null}, the package is left 617 * unsealed. Otherwise, the package is sealed using this URL. 618 * 619 * @param name 620 * the name of the package. 621 * @param specTitle 622 * the title of the specification. 623 * @param specVersion 624 * the version of the specification. 625 * @param specVendor 626 * the vendor of the specification. 627 * @param implTitle 628 * the implementation title. 629 * @param implVersion 630 * the implementation version. 631 * @param implVendor 632 * the specification vendor. 633 * @param sealBase 634 * the URL used to seal this package or {@code null} to leave the 635 * package unsealed. 636 * @return the {@code Package} object that has been created. 637 * @throws IllegalArgumentException 638 * if a package with the specified name already exists. 639 */ 640 protected Package definePackage(String name, String specTitle, String specVersion, 641 String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) 642 throws IllegalArgumentException { 643 644 synchronized (packages) { 645 if (packages.containsKey(name)) { 646 throw new IllegalArgumentException("Package " + name + " already defined"); 647 } 648 649 Package newPackage = new Package(name, specTitle, specVersion, specVendor, implTitle, 650 implVersion, implVendor, sealBase); 651 652 packages.put(name, newPackage); 653 654 return newPackage; 655 } 656 } 657 658 /** 659 * Sets the signers of the specified class. This implementation does 660 * nothing. 661 * 662 * @param c 663 * the {@code Class} object for which to set the signers. 664 * @param signers 665 * the signers for {@code c}. 666 */ 667 protected final void setSigners(Class<?> c, Object[] signers) { 668 } 669 670 /** 671 * Sets the assertion status of the class with the specified name. 672 * <p> 673 * <strong>Note: </strong>This method does nothing in the Android reference 674 * implementation. 675 * </p> 676 * 677 * @param cname 678 * the name of the class for which to set the assertion status. 679 * @param enable 680 * the new assertion status. 681 */ 682 public void setClassAssertionStatus(String cname, boolean enable) { 683 } 684 685 /** 686 * Sets the assertion status of the package with the specified name. 687 * <p> 688 * <strong>Note: </strong>This method does nothing in the Android reference 689 * implementation. 690 * </p> 691 * 692 * @param pname 693 * the name of the package for which to set the assertion status. 694 * @param enable 695 * the new assertion status. 696 */ 697 public void setPackageAssertionStatus(String pname, boolean enable) { 698 } 699 700 /** 701 * Sets the default assertion status for this class loader. 702 * <p> 703 * <strong>Note: </strong>This method does nothing in the Android reference 704 * implementation. 705 * </p> 706 * 707 * @param enable 708 * the new assertion status. 709 */ 710 public void setDefaultAssertionStatus(boolean enable) { 711 } 712 713 /** 714 * Sets the default assertion status for this class loader to {@code false} 715 * and removes any package default and class assertion status settings. 716 * <p> 717 * <strong>Note:</strong> This method does nothing in the Android reference 718 * implementation. 719 * </p> 720 */ 721 public void clearAssertionStatus() { 722 } 723} 724 725/* 726 * Provides a helper class that combines two existing URL enumerations into one. 727 * It is required for the getResources() methods. Items are fetched from the 728 * first enumeration until it's empty, then from the second one. 729 */ 730class TwoEnumerationsInOne implements Enumeration<URL> { 731 732 private final Enumeration<URL> first; 733 734 private final Enumeration<URL> second; 735 736 public TwoEnumerationsInOne(Enumeration<URL> first, Enumeration<URL> second) { 737 this.first = first; 738 this.second = second; 739 } 740 741 @Override 742 public boolean hasMoreElements() { 743 return first.hasMoreElements() || second.hasMoreElements(); 744 } 745 746 @Override 747 public URL nextElement() { 748 if (first.hasMoreElements()) { 749 return first.nextElement(); 750 } else { 751 return second.nextElement(); 752 } 753 } 754 755} 756 757/** 758 * Provides an explicit representation of the boot class loader. It sits at the 759 * head of the class loader chain and delegates requests to the VM's internal 760 * class loading mechanism. 761 */ 762class BootClassLoader extends ClassLoader { 763 764 private static BootClassLoader instance; 765 766 @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") 767 public static synchronized BootClassLoader getInstance() { 768 if (instance == null) { 769 instance = new BootClassLoader(); 770 } 771 772 return instance; 773 } 774 775 public BootClassLoader() { 776 super(null, true); 777 } 778 779 @Override 780 protected Class<?> findClass(String name) throws ClassNotFoundException { 781 return Class.classForName(name, false, null); 782 } 783 784 @Override 785 protected URL findResource(String name) { 786 return VMClassLoader.getResource(name); 787 } 788 789 @SuppressWarnings("unused") 790 @Override 791 protected Enumeration<URL> findResources(String resName) throws IOException { 792 return Collections.enumeration(VMClassLoader.getResources(resName)); 793 } 794 795 /** 796 * Returns package information for the given package. Unfortunately, the 797 * Android BootClassLoader doesn't really have this information, and as a 798 * non-secure ClassLoader, it isn't even required to, according to the spec. 799 * Yet, we want to provide it, in order to make all those hopeful callers of 800 * {@code myClass.getPackage().getName()} happy. Thus we construct a Package 801 * object the first time it is being requested and fill most of the fields 802 * with dummy values. The Package object is then put into the ClassLoader's 803 * Package cache, so we see the same one next time. We don't create Package 804 * objects for null arguments or for the default package. 805 * <p> 806 * There a limited chance that we end up with multiple Package objects 807 * representing the same package: It can happen when when a package is 808 * scattered across different JAR files being loaded by different 809 * ClassLoaders. Rather unlikely, and given that this whole thing is more or 810 * less a workaround, probably not worth the effort. 811 */ 812 @Override 813 protected Package getPackage(String name) { 814 if (name != null && !name.isEmpty()) { 815 synchronized (this) { 816 Package pack = super.getPackage(name); 817 818 if (pack == null) { 819 pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", 820 "Unknown", null); 821 } 822 823 return pack; 824 } 825 } 826 827 return null; 828 } 829 830 @Override 831 public URL getResource(String resName) { 832 return findResource(resName); 833 } 834 835 @Override 836 protected Class<?> loadClass(String className, boolean resolve) 837 throws ClassNotFoundException { 838 Class<?> clazz = findLoadedClass(className); 839 840 if (clazz == null) { 841 clazz = findClass(className); 842 } 843 844 return clazz; 845 } 846 847 @Override 848 public Enumeration<URL> getResources(String resName) throws IOException { 849 return findResources(resName); 850 } 851}

 

posted @ 2018-01-19 17:31  不一样的农民  阅读(605)  评论(0编辑  收藏  举报