Java NIO中Charset类源码

来源:互联网 发布:中国作家 知乎 编辑:程序博客网 时间:2024/05/18 01:05

Java NIO中Charset类源码

public abstract class Charset    implements Comparable<Charset>{    private static volatile String bugLevel = null;    static boolean atBugLevel(String bl) {              // package-private        if (bugLevel == null) {            if (!sun.misc.VM.isBooted())                return false;            java.security.PrivilegedAction pa =                new GetPropertyAction("sun.nio.cs.bugLevel");            String value = (String)AccessController.doPrivileged(pa);            bugLevel = (value != null) ? value : "";        }        return bugLevel.equals(bl);    }    private static void checkName(String s) {int n = s.length();if (!atBugLevel("1.4")) {    if (n == 0)throw new IllegalCharsetNameException(s);}for (int i = 0; i < n; i++) {    char c = s.charAt(i);    if (c >= 'A' && c <= 'Z') continue;    if (c >= 'a' && c <= 'z') continue;    if (c >= '0' && c <= '9') continue;    if (c == '-' && i != 0) continue;    if (c == ':' && i != 0) continue;    if (c == '_' && i != 0) continue;    if (c == '.' && i != 0) continue;    throw new IllegalCharsetNameException(s);}    }    /* The standard set of charsets */    private static CharsetProvider standardProvider = new StandardCharsets();    // Cache of the most-recently-returned charsets,    // along with the names that were used to find them    //    private static volatile Object[] cache1 = null; // "Level 1" cache    private static volatile Object[] cache2 = null; // "Level 2" cache    private static void cache(String charsetName, Charset cs) {cache2 = cache1;cache1 = new Object[] { charsetName, cs };    }    // Creates an iterator that walks over the available providers, ignoring    // those whose lookup or instantiation causes a security exception to be    // thrown.  Should be invoked with full privileges.    //    private static Iterator providers() {return new Iterator() {Class c = java.nio.charset.spi.CharsetProvider.class;ClassLoader cl = ClassLoader.getSystemClassLoader();Iterator i = Service.providers(c, cl);Object next = null;private boolean getNext() {    while (next == null) {try {    if (!i.hasNext())return false;    next = i.next();} catch (ServiceConfigurationError sce) {    if (sce.getCause() instanceof SecurityException) {// Ignore security exceptionscontinue;    }    throw sce;}    }    return true;}public boolean hasNext() {    return getNext();}public Object next() {    if (!getNext())throw new NoSuchElementException();    Object n = next;    next = null;    return n;}public void remove() {    throw new UnsupportedOperationException();}    };    }    // Thread-local gate to prevent recursive provider lookups    private static ThreadLocal gate = new ThreadLocal();    private static Charset lookupViaProviders(final String charsetName) {// The runtime startup sequence looks up standard charsets as a// consequence of the VM's invocation of System.initializeSystemClass// in order to, e.g., set system properties and encode filenames.  At// that point the application class loader has not been initialized,// however, so we can't look for providers because doing so will cause// that loader to be prematurely initialized with incomplete// information.//if (!sun.misc.VM.isBooted())    return null;if (gate.get() != null)    // Avoid recursive provider lookups    return null;try {    gate.set(gate);    return (Charset)AccessController.doPrivileged(new PrivilegedAction() {    public Object run() {for (Iterator i = providers(); i.hasNext();) {    CharsetProvider cp = (CharsetProvider)i.next();    Charset cs = cp.charsetForName(charsetName);    if (cs != null)return cs;}return null;    }});} finally {    gate.set(null);}    }    /* The extended set of charsets */    private static Object extendedProviderLock = new Object();    private static boolean extendedProviderProbed = false;    private static CharsetProvider extendedProvider = null;    private static void probeExtendedProvider() {AccessController.doPrivileged(new PrivilegedAction() {public Object run() {    try {Class epc    = Class.forName("sun.nio.cs.ext.ExtendedCharsets");extendedProvider = (CharsetProvider)epc.newInstance();    } catch (ClassNotFoundException x) {// Extended charsets not available// (charsets.jar not present)    } catch (InstantiationException x) {throw new Error(x);    } catch (IllegalAccessException x) {throw new Error(x);    }    return null;}    });    }    private static Charset lookupExtendedCharset(String charsetName) {CharsetProvider ecp = null;synchronized (extendedProviderLock) {    if (!extendedProviderProbed) {probeExtendedProvider();extendedProviderProbed = true;    }    ecp = extendedProvider;}return (ecp != null) ? ecp.charsetForName(charsetName) : null;    }    private static Charset lookup(String charsetName) {if (charsetName == null)    throw new IllegalArgumentException("Null charset name");Object[] a;if ((a = cache1) != null && charsetName.equals(a[0]))    return (Charset)a[1];// We expect most programs to use one Charset repeatedly.// We convey a hint to this effect to the VM by putting the// level 1 cache miss code in a separate method.return lookup2(charsetName);    }    private static Charset lookup2(String charsetName) {Object[] a;if ((a = cache2) != null && charsetName.equals(a[0])) {    cache2 = cache1;    cache1 = a;    return (Charset)a[1];}Charset cs;if ((cs = standardProvider.charsetForName(charsetName)) != null ||    (cs = lookupExtendedCharset(charsetName))           != null ||    (cs = lookupViaProviders(charsetName))              != null){    cache(charsetName, cs);    return cs;}/* Only need to check the name if we didn't find a charset for it */checkName(charsetName);return null;    }    /**     * Tells whether the named charset is supported. </p>     */    public static boolean isSupported(String charsetName) {return (lookup(charsetName) != null);    }    /**     * Returns a charset object for the named charset. </p>     */    public static Charset forName(String charsetName) {Charset cs = lookup(charsetName);if (cs != null)    return cs;throw new UnsupportedCharsetException(charsetName);    }    // Fold charsets from the given iterator into the given map, ignoring    // charsets whose names already have entries in the map.    //    private static void put(Iterator i, Map m) {while (i.hasNext()) {    Charset cs = (Charset)i.next();    if (!m.containsKey(cs.name()))m.put(cs.name(), cs);}    }    /**     * Constructs a sorted map from canonical charset names to charset objects.     */    public static SortedMap<String,Charset> availableCharsets() {return (SortedMap)AccessController    .doPrivileged(new PrivilegedAction() {public Object run() {    TreeMap m = new TreeMap(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);    put(standardProvider.charsets(), m);    for (Iterator i = providers(); i.hasNext();) {CharsetProvider cp = (CharsetProvider)i.next();put(cp.charsets(), m);    }    return Collections.unmodifiableSortedMap(m);}    });    }    private static volatile Charset defaultCharset;    /**     * Returns the default charset of this Java virtual machine.     */    public static Charset defaultCharset() {        if (defaultCharset == null) {    synchronized (Charset.class) {java.security.PrivilegedAction pa =    new GetPropertyAction("file.encoding");String csn = (String)AccessController.doPrivileged(pa);Charset cs = lookup(csn);if (cs != null)    defaultCharset = cs;                else     defaultCharset = forName("UTF-8");            }}return defaultCharset;    }    /* -- Instance fields and methods -- */    private final String name;// tickles a bug in oldjavac    private final String[] aliases;// tickles a bug in oldjavac    private Set aliasSet = null;    /**     * Initializes a new charset with the given canonical name and alias     * set. </p>     */    protected Charset(String canonicalName, String[] aliases) {checkName(canonicalName);String[] as = (aliases == null) ? new String[0] : aliases;for (int i = 0; i < as.length; i++)    checkName(as[i]);this.name = canonicalName;this.aliases = as;    }    /**     * Returns this charset's canonical name. </p>     */    public final String name() {return name;    }    /**     * Returns a set containing this charset's aliases. </p>     */    public final Set<String> aliases() {if (aliasSet != null)    return aliasSet;int n = aliases.length;HashSet hs = new HashSet(n);for (int i = 0; i < n; i++)    hs.add(aliases[i]);aliasSet = Collections.unmodifiableSet(hs);return aliasSet;    }    /**     * Returns this charset's human-readable name for the default locale.     */    public String displayName() {return name;    }    /**     * Tells whether or not this charset is registered in the <a     * href="http://www.iana.org/assignments/character-sets">IANA Charset     * Registry</a>.  </p>     */    public final boolean isRegistered() {return !name.startsWith("X-") && !name.startsWith("x-");    }    /**     * Returns this charset's human-readable name for the given locale.     */    public String displayName(Locale locale) {return name;    }    /**     * Tells whether or not this charset contains the given charset.     */    public abstract boolean contains(Charset cs);    /**     * Constructs a new decoder for this charset. </p>     */    public abstract CharsetDecoder newDecoder();    /**     * Constructs a new encoder for this charset. </p>     */    public abstract CharsetEncoder newEncoder();    /**     * Tells whether or not this charset supports encoding.     */    public boolean canEncode() {return true;    }    /**     * Convenience method that decodes bytes in this charset into Unicode     * characters.     */    public final CharBuffer decode(ByteBuffer bb) {try {    return ThreadLocalCoders.decoderFor(this).onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE).decode(bb);} catch (CharacterCodingException x) {    throw new Error(x);// Can't happen}    }    /**     * Convenience method that encodes Unicode characters into bytes in this     * charset.     */    public final ByteBuffer encode(CharBuffer cb) {try {    return ThreadLocalCoders.encoderFor(this).onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE).encode(cb);} catch (CharacterCodingException x) {    throw new Error(x);// Can't happen}    }    /**     * Convenience method that encodes a string into bytes in this charset.     */    public final ByteBuffer encode(String str) {return encode(CharBuffer.wrap(str));    }    /**     * Compares this charset to another.     */    public final int compareTo(Charset that) {return (name().compareToIgnoreCase(that.name()));    }    /**     * Computes a hashcode for this charset. </p>     */    public final int hashCode() {return name().hashCode();    }    /**     * Tells whether or not this object is equal to another.     */    public final boolean equals(Object ob) {if (!(ob instanceof Charset))    return false;if (this == ob)    return true;return name.equals(((Charset)ob).name());    }    /**     * Returns a string describing this charset. </p>     */    public final String toString() {return name();    }}


0 0
原创粉丝点击