|
Игровой клиент Есть вопросы по поводу редактирования dat, utx и других файлов клиента, пожалуйста, задавайте их здесь. |
Ссылки сообщества |
Изображения и альбомы |
Пользователи |
К странице... |
Опции темы |
18.03.2014, 19:18 | #11 |
Участник
|
Re: Core
|
18.03.2014, 19:29 | #12 | |
Забанен за кидаловo/обман/развод
Регистрация: 09.04.2008
Адрес: Ростов-на-Дону
Возраст: 36
Сообщений: 2,100
Отблагодарили 911 раз(а)
Рейтинг мнений:
81
|
Re: Core
Цитата:
daaa:Свернуть ↑
Мне больше кажется, что все эту труЯмуляторы, не делают, а копипастят высер каких то 12 летних программистов, и суют их друг-другу. Ибо та бабуйня что мне кидают в конфу\асю и прочее...стыд пздц(даже я, не кодер, такого гоумна бы не "написал" :\ )
Свернуть ↑Развернуть ↓
|
|
Сказали спасибо: |
18.03.2014, 19:40 | #13 |
Забанен за кидаловo/обман/развод
Регистрация: 27.12.2011
Адрес: Москвабад
Возраст: 31
Сообщений: 1,348
Отблагодарили 248 раз(а)
Рейтинг мнений:
248
|
Re: Core
Типичный l2jcopy-paste:Свернуть ↑
Свернуть ↑Развернуть ↓
18.01 l2jcopy-paste: Привет всем Наша команда начинает работать, мы будем продавать нашу зборку за 9к, так как мы крутые и у нас есть фантомы 20.01 Л2макси(новость) Шара Арбузтим за 5 января 1995 21.01 l2jcopy-paste timeline: ряд фиксов 21.01 l2jcopy-paste: (на з-г) привет ребят мы тут октрываем свою трю команду, как убрать привязку что бы пускало больше 10 человек? 22.01 l2jcopy-paste timeline: хот-фикс, решена проблема с входом более 10 человек. |
Сказали спасибо: |
19.03.2014, 15:53 | #14 |
Изгнанные
|
Re: Core
Соглашусь со многим сказанным, писали спантанно. Да ну и, что. Игра большая...
Думаете, лючера ваша, лучше? Где?) Не вижу... Где логика? Даже нет логики в Html: Код:
case 1: //Choice SubClass save = "choice" + playerName; if (null == Html.get(save) || "".equals(Html.get(save))) { Html.unset("choice"); Html.load(subClasser); Html.ifs("top,home,choiceTitle,choice:,change,replace,replaced,bottom"); Html.tag("%objectId%", super.getObjectId()); for (final String classId : subClasses) { Html.tag("%proff%", ClassId.values()[Integer.valueOf(classId)]); Html.tag("%classId%", classId); Html.parse("choice"); } Html.load(subClasser); Html.ifs("choice,change,replace,replaced"); Html.ifs("home", Html.uses("choice")); Html.parse("index", true); Html.set(save, Html.uses("index")); } html.setHtml(Html.get(save)); player.sendPacket(html); break; save конечно нужно будет передать куда надо, чтобы уже есть, а там уже будет другой разговор. Всего я пояснять не собираюсь, задач достаточно нужно делать. Ну, а логин сервер? Как же так, ну зашел?!!! Хорошо, зашел!!! Хорошо, клон?) Ага! Где же обработка клиента? Куда дели часть, что клиент работает и зашел? И все, что он отдал и все что обработано на сервере - это уже не получиться менять выполнив еще раз. Вся реализация будет запущена и проверена и только это можно, на остальное не будет обращать внимание. На счет "программ читов - самые папулярные и самописные" - не все смогут работать, кроме конечно же кликеров и наведений (чтобы бил цели), скорее тут не удастся защититься на стороне сервера, движение работает со стороны клиента, а сервер лишь утверждает его, существует ли вообще, что он тут пытается отправить, есть ли действия такие? (Не будем же мы убивать сервер пока выполняется запрос с клиента, каждую точечку проверять когда бежит, мало ли куда он бежит?Главное где он завершится) И если клиент существует и действие в клиенте и на сервере - это существует в конечной точке, то она запишится, конечно же будет выполнять, бежать и бить и так бегать по целям, - это скорее можно сделать на стороне клиента, убрать, - это, в остальном мы ничего не сможем отправить "просто так, чтобы получить, что-то ценное или не законно", немного не так построена логика игрового процесса. В игре достаточно действий которые нужно знать серверу. И их концепция должна быть логически построена для сервера. И какой сервер не открываю, у них все тоже самое, почти, только немного "изменена, где-то хуже где-то лучше, кусками" Неудобная конфигурация сервера и настроек, изменений. Зачем так было дико делать. Непонятно, когда есть Java Collection, Generics: Config.get('ConfigNAme') Config.get('ConfigNAme', value) Если данные будут не совпадать то даже не скомпилится и если переданный тип не будет существовать он не передастся, и к тому же мы будет знать все загруженные конфиги и их типы данных, которых принять: 1. String 2. Integer/Long 3. Boolean 4. Float/Double Больше ничего не получим. Когда загрузились мы сможем их преобразовывать во, что нужно на сервере и проверять там где нужно... По этому я и сказал, что больше ничего, даже других настроек: Ибо на сервере точная копия записывается, то есть со стороны (Data Pack) ничего не сможем подсунуть несуществующего. Вся безопасность зависит от сервера. Вообщем все надо делать компактно и удобно, и с логикой, а не копипастом. Последний раз редактировалось gre4ka; 19.03.2014 в 17:41. Причина: Добавлено сообщение |
19.03.2014, 19:06 | #15 | |
Пользователь
Регистрация: 18.10.2010
Адрес: Харьков
Возраст: 30
Сообщений: 527
Отблагодарили 98 раз(а)
Рейтинг мнений:
77
|
Re: Core
Цитата:
С одной стороны это удобно но с другой стороны каждый раз трогать коллекцию для того что бы вытащить конфиг не есть гуд. |
|
20.03.2014, 10:51 | #16 |
Изгнанные
|
Re: Core
Что там было придумано? Да вы даже не понимаете, о чем я говорю и как я придумал.
Ну сразу видно сказали не подумав. Смотрел я ваших опенов и лючер, не вижу ничего ценного. Круглый 0. А коллекции специально были придуманы для этого, и если вы не умеете ими правильно пользоваться, то это уже другой разговор. Да что уж тут говорить, если вы пишите instanceof где надо и не надо, то уж тут и говорить не о чем, тут сразу склонно "непонимание ООП", а ведь этот оператор самый медленный. Как я понял, тут одни быдло на форуме! Очень жаль! думал поделюсь, стоящими вещами, а теперь желания нет! Быдлите дальше! Теперь мне вообще все равно. |
20.03.2014, 11:16 | #17 | |||
Antihero
Регистрация: 03.04.2010
Адрес: Virtual Reality
Сообщений: 2,455
Отблагодарили 1,098 раз(а)
Рейтинг мнений:
919
|
Re: Core
Цитата:
Так вот, о чем это я. Немного опустим Вас. Properties использует функционал HashMap, который при добавлении новых элементов - сортирует их. А теперь подумайте и скажите: как быстро будет произведен поиск по HashMap, если нам надо достать значение ключа конфига? А теперь представьте, что эти вызовы повторяются с некоторой периодичностью. Представили? Добавьте еще с десяток потоков, которые делают тоже самое. Чувствуете? JIT & кеш процессора в этом случае не слишком будет спасать По типам данных. Вы шаблоны выучили (в данном случае не шаблоны, они в цпп, тут дженерики)? - Молодец, четь и хвала Вам. Только вот никто не будет переписывать кучу кода на пару дженерик методов, которые к тому же могут бросать каст эксепшен, если тип изначально не заложен. К сожалению у джавы хреновенькая поддержка мета-программирования. Цитата:
Здесь я говорю от лица большей части программистов этой сферы. В любом случае, никто нифига не сделал, чтобы изменить ситуацию, во всяком случае, я не видел. Цитата:
Немного абстрактных(тм) рассуждений(с).:Свернуть ↑
Свернуть ↑Развернуть ↓
Тащемта правильное клиент-серверное приложение, если существует проблема безопасности, должно быть спроектировано так (вдадимся в конкретику, возьмем ммо-игры), чтобы клиент занимался только и только рендерингом графики под управлением пришедших событий с сервера. Т.е. вся обработка, кроме графической части, должна ложиться на сервер. Называется, это все дело: принципом недоверия к клиенту. P.S: на счет Вашей фразы: "думал поделюсь, стоящими вещами" - Вы сами в это верите? Лол. Ваш код никому нахрен не нужен, нормальные люди, сами все напишут, либо заюзают фреймворк (что упростит задачу, т.к. не нужно будет заниматься отладкой). P.P.S: если у Вас еще остались вопросы по конфигам, то без проблем выложу сорц HashMap + Properties от последнего апдейта 7й оракловской ждк. P.P.P.S: если хотите что-либо обо мне говорить, то пройдите по ссылке в моей подписе, почитайте вики по public-fagot (хоть там и самая малость). Когда запилите такое же - с удовольствием приму, что я дурак Добавлено через 18 минут И да. Для всех негодующих на счет пользователей зоны, администраторов на ней и вообще самой зоны. Вас тут никто не держит. Есть овер9000 других ресурсов похожей направленности. Если вы не хотите принимать правила общения и правила сообщества, то вам прямая дорога на другие форумы, здесь вас никто не держит и задницу лизать не будет, как и плакать по вам. А если еще и правила форума нарушите... То от вас уже избавится не сообщество, а дядька Оззи. Последний раз редактировалось n3k0nation; 20.03.2014 в 11:35. Причина: Добавлено сообщение |
|||
26.03.2014, 16:42 | #18 | |
Изгнанные
|
Re: Core
Цитата:
А то я там ничего не нашел, is empty. Мне интересно про Config. |
|
26.03.2014, 17:16 | #19 | |
Antihero
Регистрация: 03.04.2010
Адрес: Virtual Reality
Сообщений: 2,455
Отблагодарили 1,098 раз(а)
Рейтинг мнений:
919
|
Re: Core
Цитата:
J8u0 Properties:Свернуть ↑
Свернуть ↑Развернуть ↓
Код:
/* * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package java.util; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.io.OutputStreamWriter; import java.io.BufferedWriter; import java.security.AccessController; import java.security.PrivilegedAction; import sun.util.spi.XmlPropertiesProvider; /** * The {@code Properties} class represents a persistent set of * properties. The {@code Properties} can be saved to a stream * or loaded from a stream. Each key and its corresponding value in * the property list is a string. * <p> * A property list can contain another property list as its * "defaults"; this second property list is searched if * the property key is not found in the original property list. * <p> * Because {@code Properties} inherits from {@code Hashtable}, the * {@code put} and {@code putAll} methods can be applied to a * {@code Properties} object. Their use is strongly discouraged as they * allow the caller to insert entries whose keys or values are not * {@code Strings}. The {@code setProperty} method should be used * instead. If the {@code store} or {@code save} method is called * on a "compromised" {@code Properties} object that contains a * non-{@code String} key or value, the call will fail. Similarly, * the call to the {@code propertyNames} or {@code list} method * will fail if it is called on a "compromised" {@code Properties} * object that contains a non-{@code String} key. * * <p> * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt> * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)} * methods load and store properties from and to a character based stream * in a simple line-oriented format specified below. * * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt> * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)} * methods work the same way as the load(Reader)/store(Writer, String) pair, except * the input/output stream is encoded in ISO 8859-1 character encoding. * Characters that cannot be directly represented in this encoding can be written using * Unicode escapes as defined in section 3.3 of * <cite>The Java™ Language Specification</cite>; * only a single 'u' character is allowed in an escape * sequence. The native2ascii tool can be used to convert property files to and * from other character encodings. * * <p> The {@link #loadFromXML(InputStream)} and {@link * #storeToXML(OutputStream, String, String)} methods load and store properties * in a simple XML format. By default the UTF-8 character encoding is used, * however a specific encoding may be specified if required. Implementations * are required to support UTF-8 and UTF-16 and may support other encodings. * An XML properties document has the following DOCTYPE declaration: * * <pre> * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> * </pre> * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is * <i>not</i> accessed when exporting or importing properties; it merely * serves as a string to uniquely identify the DTD, which is: * <pre> * <?xml version="1.0" encoding="UTF-8"?> * * <!-- DTD for properties --> * * <!ELEMENT properties ( comment?, entry* ) > * * <!ATTLIST properties version CDATA #FIXED "1.0"> * * <!ELEMENT comment (#PCDATA) > * * <!ELEMENT entry (#PCDATA) > * * <!ATTLIST entry key CDATA #REQUIRED> * </pre> * * <p>This class is thread-safe: multiple threads can share a single * <tt>Properties</tt> object without the need for external synchronization. * * @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a> * @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a> * * @author Arthur van Hoff * @author Michael McCloskey * @author Xueming Shen * @since JDK1.0 */ public class Properties extends Hashtable<Object,Object> { /** * use serialVersionUID from JDK 1.1.X for interoperability */ private static final long serialVersionUID = 4112578634029874840L; /** * A property list that contains default values for any keys not * found in this property list. * * @serial */ protected Properties defaults; /** * Creates an empty property list with no default values. */ public Properties() { this(null); } /** * Creates an empty property list with the specified defaults. * * @param defaults the defaults. */ public Properties(Properties defaults) { this.defaults = defaults; } /** * Calls the <tt>Hashtable</tt> method {@code put}. Provided for * parallelism with the <tt>getProperty</tt> method. Enforces use of * strings for property keys and values. The value returned is the * result of the <tt>Hashtable</tt> call to {@code put}. * * @param key the key to be placed into this property list. * @param value the value corresponding to <tt>key</tt>. * @return the previous value of the specified key in this property * list, or {@code null} if it did not have one. * @see #getProperty * @since 1.2 */ public synchronized Object setProperty(String key, String value) { return put(key, value); } /** * Reads a property list (key and element pairs) from the input * character stream in a simple line-oriented format. * <p> * Properties are processed in terms of lines. There are two * kinds of line, <i>natural lines</i> and <i>logical lines</i>. * A natural line is defined as a line of * characters that is terminated either by a set of line terminator * characters ({@code \n} or {@code \r} or {@code \r\n}) * or by the end of the stream. A natural line may be either a blank line, * a comment line, or hold all or some of a key-element pair. A logical * line holds all the data of a key-element pair, which may be spread * out across several adjacent natural lines by escaping * the line terminator sequence with a backslash character * {@code \}. Note that a comment line cannot be extended * in this manner; every natural line that is a comment must have * its own comment indicator, as described below. Lines are read from * input until the end of the stream is reached. * * <p> * A natural line that contains only white space characters is * considered blank and is ignored. A comment line has an ASCII * {@code '#'} or {@code '!'} as its first non-white * space character; comment lines are also ignored and do not * encode key-element information. In addition to line * terminators, this format considers the characters space * ({@code ' '}, {@code '\u005Cu0020'}), tab * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed * ({@code '\f'}, {@code '\u005Cu000C'}) to be white * space. * * <p> * If a logical line is spread across several natural lines, the * backslash escaping the line terminator sequence, the line * terminator sequence, and any white space at the start of the * following line have no affect on the key or element values. * The remainder of the discussion of key and element parsing * (when loading) will assume all the characters constituting * the key and element appear on a single natural line after * line continuation characters have been removed. Note that * it is <i>not</i> sufficient to only examine the character * preceding a line terminator sequence to decide if the line * terminator is escaped; there must be an odd number of * contiguous backslashes for the line terminator to be escaped. * Since the input is processed from left to right, a * non-zero even number of 2<i>n</i> contiguous backslashes * before a line terminator (or elsewhere) encodes <i>n</i> * backslashes after escape processing. * * <p> * The key contains all of the characters in the line starting * with the first non-white space character and up to, but not * including, the first unescaped {@code '='}, * {@code ':'}, or white space character other than a line * terminator. All of these key termination characters may be * included in the key by escaping them with a preceding backslash * character; for example,<p> * * {@code \:\=}<p> * * would be the two-character key {@code ":="}. Line * terminator characters can be included using {@code \r} and * {@code \n} escape sequences. Any white space after the * key is skipped; if the first non-white space character after * the key is {@code '='} or {@code ':'}, then it is * ignored and any white space characters after it are also * skipped. All remaining characters on the line become part of * the associated element string; if there are no remaining * characters, the element is the empty string * {@code ""}. Once the raw character sequences * constituting the key and element are identified, escape * processing is performed as described above. * * <p> * As an example, each of the following three lines specifies the key * {@code "Truth"} and the associated element value * {@code "Beauty"}: * <pre> * Truth = Beauty * Truth:Beauty * Truth :Beauty * </pre> * As another example, the following three lines specify a single * property: * <pre> * fruits apple, banana, pear, \ * cantaloupe, watermelon, \ * kiwi, mango * </pre> * The key is {@code "fruits"} and the associated element is: * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre> * Note that a space appears before each {@code \} so that a space * will appear after each comma in the final result; the {@code \}, * line terminator, and leading white space on the continuation line are * merely discarded and are <i>not</i> replaced by one or more other * characters. * <p> * As a third example, the line: * <pre>cheeses * </pre> * specifies that the key is {@code "cheeses"} and the associated * element is the empty string {@code ""}. * <p> * <a name="unicodeescapes"></a> * Characters in keys and elements can be represented in escape * sequences similar to those used for character and string literals * (see sections 3.3 and 3.10.6 of * <cite>The Java™ Language Specification</cite>). * * The differences from the character escape sequences and Unicode * escapes used for characters and strings are: * * <ul> * <li> Octal escapes are not recognized. * * <li> The character sequence {@code \b} does <i>not</i> * represent a backspace character. * * <li> The method does not treat a backslash character, * {@code \}, before a non-valid escape character as an * error; the backslash is silently dropped. For example, in a * Java string the sequence {@code "\z"} would cause a * compile time error. In contrast, this method silently drops * the backslash. Therefore, this method treats the two character * sequence {@code "\b"} as equivalent to the single * character {@code 'b'}. * * <li> Escapes are not necessary for single and double quotes; * however, by the rule above, single and double quote characters * preceded by a backslash still yield single and double quote * characters, respectively. * * <li> Only a single 'u' character is allowed in a Unicode escape * sequence. * * </ul> * <p> * The specified stream remains open after this method returns. * * @param reader the input character stream. * @throws IOException if an error occurred when reading from the * input stream. * @throws IllegalArgumentException if a malformed Unicode escape * appears in the input. * @since 1.6 */ public synchronized void load(Reader reader) throws IOException { load0(new LineReader(reader)); } /** * Reads a property list (key and element pairs) from the input * byte stream. The input stream is in a simple line-oriented * format as specified in * {@link #load(java.io.Reader) load(Reader)} and is assumed to use * the ISO 8859-1 character encoding; that is each byte is one Latin1 * character. Characters not in Latin1, and certain special characters, * are represented in keys and elements using Unicode escapes as defined in * section 3.3 of * <cite>The Java™ Language Specification</cite>. * <p> * The specified stream remains open after this method returns. * * @param inStream the input stream. * @exception IOException if an error occurred when reading from the * input stream. * @throws IllegalArgumentException if the input stream contains a * malformed Unicode escape sequence. * @since 1.2 */ public synchronized void load(InputStream inStream) throws IOException { load0(new LineReader(inStream)); } private void load0 (LineReader lr) throws IOException { char[] convtBuf = new char[1024]; int limit; int keyLen; int valueStart; char c; boolean hasSep; boolean precedingBackslash; while ((limit = lr.readLine()) >= 0) { c = 0; keyLen = 0; valueStart = limit; hasSep = false; //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">"); precedingBackslash = false; while (keyLen < limit) { c = lr.lineBuf[keyLen]; //need check if escaped. if ((c == '=' || c == ':') && !precedingBackslash) { valueStart = keyLen + 1; hasSep = true; break; } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { valueStart = keyLen + 1; break; } if (c == '\\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } keyLen++; } while (valueStart < limit) { c = lr.lineBuf[valueStart]; if (c != ' ' && c != '\t' && c != '\f') { if (!hasSep && (c == '=' || c == ':')) { hasSep = true; } else { break; } } valueStart++; } String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf); String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf); put(key, value); } } /* Read in a "logical line" from an InputStream/Reader, skip all comment * and blank lines and filter out those leading whitespace characters * (\u0020, \u0009 and \u000c) from the beginning of a "natural line". * Method returns the char length of the "logical line" and stores * the line in "lineBuf". */ class LineReader { public LineReader(InputStream inStream) { this.inStream = inStream; inByteBuf = new byte[8192]; } public LineReader(Reader reader) { this.reader = reader; inCharBuf = new char[8192]; } byte[] inByteBuf; char[] inCharBuf; char[] lineBuf = new char[1024]; int inLimit = 0; int inOff = 0; InputStream inStream; Reader reader; int readLine() throws IOException { int len = 0; char c = 0; boolean skipWhiteSpace = true; boolean isCommentLine = false; boolean isNewLine = true; boolean appendedLineBegin = false; boolean precedingBackslash = false; boolean skipLF = false; while (true) { if (inOff >= inLimit) { inLimit = (inStream==null)?reader.read(inCharBuf) :inStream.read(inByteBuf); inOff = 0; if (inLimit <= 0) { if (len == 0 || isCommentLine) { return -1; } if (precedingBackslash) { len--; } return len; } } if (inStream != null) { //The line below is equivalent to calling a //ISO8859-1 decoder. c = (char) (0xff & inByteBuf[inOff++]); } else { c = inCharBuf[inOff++]; } if (skipLF) { skipLF = false; if (c == '\n') { continue; } } if (skipWhiteSpace) { if (c == ' ' || c == '\t' || c == '\f') { continue; } if (!appendedLineBegin && (c == '\r' || c == '\n')) { continue; } skipWhiteSpace = false; appendedLineBegin = false; } if (isNewLine) { isNewLine = false; if (c == '#' || c == '!') { isCommentLine = true; continue; } } if (c != '\n' && c != '\r') { lineBuf[len++] = c; if (len == lineBuf.length) { int newLength = lineBuf.length * 2; if (newLength < 0) { newLength = Integer.MAX_VALUE; } char[] buf = new char[newLength]; System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length); lineBuf = buf; } //flip the preceding backslash flag if (c == '\\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } } else { // reached EOL if (isCommentLine || len == 0) { isCommentLine = false; isNewLine = true; skipWhiteSpace = true; len = 0; continue; } if (inOff >= inLimit) { inLimit = (inStream==null) ?reader.read(inCharBuf) :inStream.read(inByteBuf); inOff = 0; if (inLimit <= 0) { if (precedingBackslash) { len--; } return len; } } if (precedingBackslash) { len -= 1; //skip the leading whitespace characters in following line skipWhiteSpace = true; appendedLineBegin = true; precedingBackslash = false; if (c == '\r') { skipLF = true; } } else { return len; } } } } } /* * Converts encoded \uxxxx to unicode chars * and changes special saved chars to their original forms */ private String loadConvert (char[] in, int off, int len, char[] convtBuf) { if (convtBuf.length < len) { int newLen = len * 2; if (newLen < 0) { newLen = Integer.MAX_VALUE; } convtBuf = new char[newLen]; } char aChar; char[] out = convtBuf; int outLen = 0; int end = off + len; while (off < end) { aChar = in[off++]; if (aChar == '\\') { aChar = in[off++]; if(aChar == 'u') { // Read the xxxx int value=0; for (int i=0; i<4; i++) { aChar = in[off++]; switch (aChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': value = (value << 4) + aChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': value = (value << 4) + 10 + aChar - 'a'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': value = (value << 4) + 10 + aChar - 'A'; break; default: throw new IllegalArgumentException( "Malformed \\uxxxx encoding."); } } out[outLen++] = (char)value; } else { if (aChar == 't') aChar = '\t'; else if (aChar == 'r') aChar = '\r'; else if (aChar == 'n') aChar = '\n'; else if (aChar == 'f') aChar = '\f'; out[outLen++] = aChar; } } else { out[outLen++] = aChar; } } return new String (out, 0, outLen); } /* * Converts unicodes to encoded \uxxxx and escapes * special characters with a preceding slash */ private String saveConvert(String theString, boolean escapeSpace, boolean escapeUnicode) { int len = theString.length(); int bufLen = len * 2; if (bufLen < 0) { bufLen = Integer.MAX_VALUE; } StringBuffer outBuffer = new StringBuffer(bufLen); for(int x=0; x<len; x++) { char aChar = theString.charAt(x); // Handle common case first, selecting largest block that // avoids the specials below if ((aChar > 61) && (aChar < 127)) { if (aChar == '\\') { outBuffer.append('\\'); outBuffer.append('\\'); continue; } outBuffer.append(aChar); continue; } switch(aChar) { case ' ': if (x == 0 || escapeSpace) outBuffer.append('\\'); outBuffer.append(' '); break; case '\t':outBuffer.append('\\'); outBuffer.append('t'); break; case '\n':outBuffer.append('\\'); outBuffer.append('n'); break; case '\r':outBuffer.append('\\'); outBuffer.append('r'); break; case '\f':outBuffer.append('\\'); outBuffer.append('f'); break; case '=': // Fall through case ':': // Fall through case '#': // Fall through case '!': outBuffer.append('\\'); outBuffer.append(aChar); break; default: if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) { outBuffer.append('\\'); outBuffer.append('u'); outBuffer.append(toHex((aChar >> 12) & 0xF)); outBuffer.append(toHex((aChar >> 8) & 0xF)); outBuffer.append(toHex((aChar >> 4) & 0xF)); outBuffer.append(toHex( aChar & 0xF)); } else { outBuffer.append(aChar); } } } return outBuffer.toString(); } private static void writeComments(BufferedWriter bw, String comments) throws IOException { bw.write("#"); int len = comments.length(); int current = 0; int last = 0; char[] uu = new char[6]; uu[0] = '\\'; uu[1] = 'u'; while (current < len) { char c = comments.charAt(current); if (c > '\u00ff' || c == '\n' || c == '\r') { if (last != current) bw.write(comments.substring(last, current)); if (c > '\u00ff') { uu[2] = toHex((c >> 12) & 0xf); uu[3] = toHex((c >> 8) & 0xf); uu[4] = toHex((c >> 4) & 0xf); uu[5] = toHex( c & 0xf); bw.write(new String(uu)); } else { bw.newLine(); if (c == '\r' && current != len - 1 && comments.charAt(current + 1) == '\n') { current++; } if (current == len - 1 || (comments.charAt(current + 1) != '#' && comments.charAt(current + 1) != '!')) bw.write("#"); } last = current + 1; } current++; } if (last != current) bw.write(comments.substring(last, current)); bw.newLine(); } /** * Calls the {@code store(OutputStream out, String comments)} method * and suppresses IOExceptions that were thrown. * * @deprecated This method does not throw an IOException if an I/O error * occurs while saving the property list. The preferred way to save a * properties list is via the {@code store(OutputStream out, * String comments)} method or the * {@code storeToXML(OutputStream os, String comment)} method. * * @param out an output stream. * @param comments a description of the property list. * @exception ClassCastException if this {@code Properties} object * contains any keys or values that are not * {@code Strings}. */ @Deprecated public void save(OutputStream out, String comments) { try { store(out, comments); } catch (IOException e) { } } /** * Writes this property list (key and element pairs) in this * {@code Properties} table to the output character stream in a * format suitable for using the {@link #load(java.io.Reader) load(Reader)} * method. * <p> * Properties from the defaults table of this {@code Properties} * table (if any) are <i>not</i> written out by this method. * <p> * If the comments argument is not null, then an ASCII {@code #} * character, the comments string, and a line separator are first written * to the output stream. Thus, the {@code comments} can serve as an * identifying comment. Any one of a line feed ('\n'), a carriage * return ('\r'), or a carriage return followed immediately by a line feed * in comments is replaced by a line separator generated by the {@code Writer} * and if the next character in comments is not character {@code #} or * character {@code !} then an ASCII {@code #} is written out * after that line separator. * <p> * Next, a comment line is always written, consisting of an ASCII * {@code #} character, the current date and time (as if produced * by the {@code toString} method of {@code Date} for the * current time), and a line separator as generated by the {@code Writer}. * <p> * Then every entry in this {@code Properties} table is * written out, one per line. For each entry the key string is * written, then an ASCII {@code =}, then the associated * element string. For the key, all space characters are * written with a preceding {@code \} character. For the * element, leading space characters, but not embedded or trailing * space characters, are written with a preceding {@code \} * character. The key and element characters {@code #}, * {@code !}, {@code =}, and {@code :} are written * with a preceding backslash to ensure that they are properly loaded. * <p> * After the entries have been written, the output stream is flushed. * The output stream remains open after this method returns. * <p> * * @param writer an output character stream writer. * @param comments a description of the property list. * @exception IOException if writing this property list to the specified * output stream throws an <tt>IOException</tt>. * @exception ClassCastException if this {@code Properties} object * contains any keys or values that are not {@code Strings}. * @exception NullPointerException if {@code writer} is null. * @since 1.6 */ public void store(Writer writer, String comments) throws IOException { store0((writer instanceof BufferedWriter)?(BufferedWriter)writer : new BufferedWriter(writer), comments, false); } /** * Writes this property list (key and element pairs) in this * {@code Properties} table to the output stream in a format suitable * for loading into a {@code Properties} table using the * {@link #load(InputStream) load(InputStream)} method. * <p> * Properties from the defaults table of this {@code Properties} * table (if any) are <i>not</i> written out by this method. * <p> * This method outputs the comments, properties keys and values in * the same format as specified in * {@link #store(java.io.Writer, java.lang.String) store(Writer)}, * with the following differences: * <ul> * <li>The stream is written using the ISO 8859-1 character encoding. * * <li>Characters not in Latin-1 in the comments are written as * {@code \u005Cu}<i>xxxx</i> for their appropriate unicode * hexadecimal value <i>xxxx</i>. * * <li>Characters less than {@code \u005Cu0020} and characters greater * than {@code \u005Cu007E} in property keys or values are written * as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal * value <i>xxxx</i>. * </ul> * <p> * After the entries have been written, the output stream is flushed. * The output stream remains open after this method returns. * <p> * @param out an output stream. * @param comments a description of the property list. * @exception IOException if writing this property list to the specified * output stream throws an <tt>IOException</tt>. * @exception ClassCastException if this {@code Properties} object * contains any keys or values that are not {@code Strings}. * @exception NullPointerException if {@code out} is null. * @since 1.2 */ public void store(OutputStream out, String comments) throws IOException { store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")), comments, true); } private void store0(BufferedWriter bw, String comments, boolean escUnicode) throws IOException { if (comments != null) { writeComments(bw, comments); } bw.write("#" + new Date().toString()); bw.newLine(); synchronized (this) { for (Enumeration<?> e = keys(); e.hasMoreElements();) { String key = (String)e.nextElement(); String val = (String)get(key); key = saveConvert(key, true, escUnicode); /* No need to escape embedded and trailing spaces for value, hence * pass false to flag. */ val = saveConvert(val, false, escUnicode); bw.write(key + "=" + val); bw.newLine(); } } bw.flush(); } /** * Loads all of the properties represented by the XML document on the * specified input stream into this properties table. * * <p>The XML document must have the following DOCTYPE declaration: * <pre> * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> * </pre> * Furthermore, the document must satisfy the properties DTD described * above. * * <p> An implementation is required to read XML documents that use the * "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may * support additional encodings. * * <p>The specified stream is closed after this method returns. * * @param in the input stream from which to read the XML document. * @throws IOException if reading from the specified input stream * results in an <tt>IOException</tt>. * @throws java.io.UnsupportedEncodingException if the document's encoding * declaration can be read and it specifies an encoding that is not * supported * @throws InvalidPropertiesFormatException Data on input stream does not * constitute a valid XML document with the mandated document type. * @throws NullPointerException if {@code in} is null. * @see #storeToXML(OutputStream, String, String) * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character * Encoding in Entities</a> * @since 1.5 */ public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException { XmlSupport.load(this, Objects.requireNonNull(in)); in.close(); } /** * Emits an XML document representing all of the properties contained * in this table. * * <p> An invocation of this method of the form <tt>props.storeToXML(os, * comment)</tt> behaves in exactly the same way as the invocation * <tt>props.storeToXML(os, comment, "UTF-8");</tt>. * * @param os the output stream on which to emit the XML document. * @param comment a description of the property list, or {@code null} * if no comment is desired. * @throws IOException if writing to the specified output stream * results in an <tt>IOException</tt>. * @throws NullPointerException if {@code os} is null. * @throws ClassCastException if this {@code Properties} object * contains any keys or values that are not * {@code Strings}. * @see #loadFromXML(InputStream) * @since 1.5 */ public void storeToXML(OutputStream os, String comment) throws IOException { storeToXML(os, comment, "UTF-8"); } /** * Emits an XML document representing all of the properties contained * in this table, using the specified encoding. * * <p>The XML document will have the following DOCTYPE declaration: * <pre> * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> * </pre> * * <p>If the specified comment is {@code null} then no comment * will be stored in the document. * * <p> An implementation is required to support writing of XML documents * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An * implementation may support additional encodings. * * <p>The specified stream remains open after this method returns. * * @param os the output stream on which to emit the XML document. * @param comment a description of the property list, or {@code null} * if no comment is desired. * @param encoding the name of a supported * <a href="../lang/package-summary.html#charenc"> * character encoding</a> * * @throws IOException if writing to the specified output stream * results in an <tt>IOException</tt>. * @throws java.io.UnsupportedEncodingException if the encoding is not * supported by the implementation. * @throws NullPointerException if {@code os} is {@code null}, * or if {@code encoding} is {@code null}. * @throws ClassCastException if this {@code Properties} object * contains any keys or values that are not * {@code Strings}. * @see #loadFromXML(InputStream) * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character * Encoding in Entities</a> * @since 1.5 */ public void storeToXML(OutputStream os, String comment, String encoding) throws IOException { XmlSupport.save(this, Objects.requireNonNull(os), comment, Objects.requireNonNull(encoding)); } /** * Searches for the property with the specified key in this property list. * If the key is not found in this property list, the default property list, * and its defaults, recursively, are then checked. The method returns * {@code null} if the property is not found. * * @param key the property key. * @return the value in this property list with the specified key value. * @see #setProperty * @see #defaults */ public String getProperty(String key) { Object oval = super.get(key); String sval = (oval instanceof String) ? (String)oval : null; return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval; } /** * Searches for the property with the specified key in this property list. * If the key is not found in this property list, the default property list, * and its defaults, recursively, are then checked. The method returns the * default value argument if the property is not found. * * @param key the hashtable key. * @param defaultValue a default value. * * @return the value in this property list with the specified key value. * @see #setProperty * @see #defaults */ public String getProperty(String key, String defaultValue) { String val = getProperty(key); return (val == null) ? defaultValue : val; } /** * Returns an enumeration of all the keys in this property list, * including distinct keys in the default property list if a key * of the same name has not already been found from the main * properties list. * * @return an enumeration of all the keys in this property list, including * the keys in the default property list. * @throws ClassCastException if any key in this property list * is not a string. * @see java.util.Enumeration * @see java.util.Properties#defaults * @see #stringPropertyNames */ public Enumeration<?> propertyNames() { Hashtable<String,Object> h = new Hashtable<>(); enumerate(h); return h.keys(); } /** * Returns a set of keys in this property list where * the key and its corresponding value are strings, * including distinct keys in the default property list if a key * of the same name has not already been found from the main * properties list. Properties whose key or value is not * of type <tt>String</tt> are omitted. * <p> * The returned set is not backed by the <tt>Properties</tt> object. * Changes to this <tt>Properties</tt> are not reflected in the set, * or vice versa. * * @return a set of keys in this property list where * the key and its corresponding value are strings, * including the keys in the default property list. * @see java.util.Properties#defaults * @since 1.6 */ public Set<String> stringPropertyNames() { Hashtable<String, String> h = new Hashtable<>(); enumerateStringProperties(h); return h.keySet(); } /** * Prints this property list out to the specified output stream. * This method is useful for debugging. * * @param out an output stream. * @throws ClassCastException if any key in this property list * is not a string. */ public void list(PrintStream out) { out.println("-- listing properties --"); Hashtable<String,Object> h = new Hashtable<>(); enumerate(h); for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) { String key = e.nextElement(); String val = (String)h.get(key); if (val.length() > 40) { val = val.substring(0, 37) + "..."; } out.println(key + "=" + val); } } /** * Prints this property list out to the specified output stream. * This method is useful for debugging. * * @param out an output stream. * @throws ClassCastException if any key in this property list * is not a string. * @since JDK1.1 */ /* * Rather than use an anonymous inner class to share common code, this * method is duplicated in order to ensure that a non-1.1 compiler can * compile this file. */ public void list(PrintWriter out) { out.println("-- listing properties --"); Hashtable<String,Object> h = new Hashtable<>(); enumerate(h); for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) { String key = e.nextElement(); String val = (String)h.get(key); if (val.length() > 40) { val = val.substring(0, 37) + "..."; } out.println(key + "=" + val); } } /** * Enumerates all key/value pairs in the specified hashtable. * @param h the hashtable * @throws ClassCastException if any of the property keys * is not of String type. */ private synchronized void enumerate(Hashtable<String,Object> h) { if (defaults != null) { defaults.enumerate(h); } for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) { String key = (String)e.nextElement(); h.put(key, get(key)); } } /** * Enumerates all key/value pairs in the specified hashtable * and omits the property if the key or value is not a string. * @param h the hashtable */ private synchronized void enumerateStringProperties(Hashtable<String, String> h) { if (defaults != null) { defaults.enumerateStringProperties(h); } for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) { Object k = e.nextElement(); Object v = get(k); if (k instanceof String && v instanceof String) { h.put((String) k, (String) v); } } } /** * Convert a nibble to a hex character * @param nibble the nibble to convert. */ private static char toHex(int nibble) { return hexDigit[(nibble & 0xF)]; } /** A table of hex digits */ private static final char[] hexDigit = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; /** * Supporting class for loading/storing properties in XML format. * * <p> The {@code load} and {@code store} methods defined here delegate to a * system-wide {@code XmlPropertiesProvider}. On first invocation of either * method then the system-wide provider is located as follows: </p> * * <ol> * <li> If the system property {@code sun.util.spi.XmlPropertiesProvider} * is defined then it is taken to be the full-qualified name of a concrete * provider class. The class is loaded with the system class loader as the * initiating loader. If it cannot be loaded or instantiated using a zero * argument constructor then an unspecified error is thrown. </li> * * <li> If the system property is not defined then the service-provider * loading facility defined by the {@link ServiceLoader} class is used to * locate a provider with the system class loader as the initiating * loader and {@code sun.util.spi.XmlPropertiesProvider} as the service * type. If this process fails then an unspecified error is thrown. If * there is more than one service provider installed then it is * not specified as to which provider will be used. </li> * * <li> If the provider is not found by the above means then a system * default provider will be instantiated and used. </li> * </ol> */ private static class XmlSupport { private static XmlPropertiesProvider loadProviderFromProperty(ClassLoader cl) { String cn = System.getProperty("sun.util.spi.XmlPropertiesProvider"); if (cn == null) return null; try { Class<?> c = Class.forName(cn, true, cl); return (XmlPropertiesProvider)c.newInstance(); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException x) { throw new ServiceConfigurationError(null, x); } } private static XmlPropertiesProvider loadProviderAsService(ClassLoader cl) { Iterator<XmlPropertiesProvider> iterator = ServiceLoader.load(XmlPropertiesProvider.class, cl).iterator(); return iterator.hasNext() ? iterator.next() : null; } private static XmlPropertiesProvider loadProvider() { return AccessController.doPrivileged( new PrivilegedAction<XmlPropertiesProvider>() { public XmlPropertiesProvider run() { ClassLoader cl = ClassLoader.getSystemClassLoader(); XmlPropertiesProvider provider = loadProviderFromProperty(cl); if (provider != null) return provider; provider = loadProviderAsService(cl); if (provider != null) return provider; return new jdk.internal.util.xml.BasicXmlPropertiesProvider(); }}); } private static final XmlPropertiesProvider PROVIDER = loadProvider(); static void load(Properties props, InputStream in) throws IOException, InvalidPropertiesFormatException { PROVIDER.load(props, in); } static void save(Properties props, OutputStream os, String comment, String encoding) throws IOException { PROVIDER.store(props, os, comment, encoding); } } } Hashtable:Свернуть ↑
Свернуть ↑Развернуть ↓
Код:
/* * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package java.util; import java.io.*; import java.util.concurrent.ThreadLocalRandom; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.BiFunction; /** * This class implements a hash table, which maps keys to values. Any * non-<code>null</code> object can be used as a key or as a value. <p> * * To successfully store and retrieve objects from a hashtable, the * objects used as keys must implement the <code>hashCode</code> * method and the <code>equals</code> method. <p> * * An instance of <code>Hashtable</code> has two parameters that affect its * performance: <i>initial capacity</i> and <i>load factor</i>. The * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the * <i>initial capacity</i> is simply the capacity at the time the hash table * is created. Note that the hash table is <i>open</i>: in the case of a "hash * collision", a single bucket stores multiple entries, which must be searched * sequentially. The <i>load factor</i> is a measure of how full the hash * table is allowed to get before its capacity is automatically increased. * The initial capacity and load factor parameters are merely hints to * the implementation. The exact details as to when and whether the rehash * method is invoked are implementation-dependent.<p> * * Generally, the default load factor (.75) offers a good tradeoff between * time and space costs. Higher values decrease the space overhead but * increase the time cost to look up an entry (which is reflected in most * <tt>Hashtable</tt> operations, including <tt>get</tt> and <tt>put</tt>).<p> * * The initial capacity controls a tradeoff between wasted space and the * need for <code>rehash</code> operations, which are time-consuming. * No <code>rehash</code> operations will <i>ever</i> occur if the initial * capacity is greater than the maximum number of entries the * <tt>Hashtable</tt> will contain divided by its load factor. However, * setting the initial capacity too high can waste space.<p> * * If many entries are to be made into a <code>Hashtable</code>, * creating it with a sufficiently large capacity may allow the * entries to be inserted more efficiently than letting it perform * automatic rehashing as needed to grow the table. <p> * * This example creates a hashtable of numbers. It uses the names of * the numbers as keys: * <pre> {@code * Hashtable<String, Integer> numbers * = new Hashtable<String, Integer>(); * numbers.put("one", 1); * numbers.put("two", 2); * numbers.put("three", 3);}</pre> * * <p>To retrieve a number, use the following code: * <pre> {@code * Integer n = numbers.get("two"); * if (n != null) { * System.out.println("two = " + n); * }}</pre> * * <p>The iterators returned by the <tt>iterator</tt> method of the collections * returned by all of this class's "collection view methods" are * <em>fail-fast</em>: if the Hashtable is structurally modified at any time * after the iterator is created, in any way except through the iterator's own * <tt>remove</tt> method, the iterator will throw a {@link * ConcurrentModificationException}. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than risking * arbitrary, non-deterministic behavior at an undetermined time in the future. * The Enumerations returned by Hashtable's keys and elements methods are * <em>not</em> fail-fast. * * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators * throw <tt>ConcurrentModificationException</tt> on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: <i>the fail-fast behavior of iterators * should be used only to detect bugs.</i> * * <p>As of the Java 2 platform v1.2, this class was retrofitted to * implement the {@link Map} interface, making it a member of the * <a href="{@docRoot}/../technotes/guides/collections/index.html"> * * Java Collections Framework</a>. Unlike the new collection * implementations, {@code Hashtable} is synchronized. If a * thread-safe implementation is not needed, it is recommended to use * {@link HashMap} in place of {@code Hashtable}. If a thread-safe * highly-concurrent implementation is desired, then it is recommended * to use {@link java.util.concurrent.ConcurrentHashMap} in place of * {@code Hashtable}. * * @author Arthur van Hoff * @author Josh Bloch * @author Neal Gafter * @see Object#equals(java.lang.Object) * @see Object#hashCode() * @see Hashtable#rehash() * @see Collection * @see Map * @see HashMap * @see TreeMap * @since JDK1.0 */ public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable { /** * The hash table data. */ private transient Entry<?,?>[] table; /** * The total number of entries in the hash table. */ private transient int count; /** * The table is rehashed when its size exceeds this threshold. (The * value of this field is (int)(capacity * loadFactor).) * * @serial */ private int threshold; /** * The load factor for the hashtable. * * @serial */ private float loadFactor; /** * The number of times this Hashtable has been structurally modified * Structural modifications are those that change the number of entries in * the Hashtable or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the Hashtable fail-fast. (See ConcurrentModificationException). */ private transient int modCount = 0; /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 1421746759512286392L; /** * Constructs a new, empty hashtable with the specified initial * capacity and the specified load factor. * * @param initialCapacity the initial capacity of the hashtable. * @param loadFactor the load factor of the hashtable. * @exception IllegalArgumentException if the initial capacity is less * than zero, or if the load factor is nonpositive. */ public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); } /** * Constructs a new, empty hashtable with the specified initial capacity * and default load factor (0.75). * * @param initialCapacity the initial capacity of the hashtable. * @exception IllegalArgumentException if the initial capacity is less * than zero. */ public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } /** * Constructs a new, empty hashtable with a default initial capacity (11) * and load factor (0.75). */ public Hashtable() { this(11, 0.75f); } /** * Constructs a new hashtable with the same mappings as the given * Map. The hashtable is created with an initial capacity sufficient to * hold the mappings in the given Map and a default load factor (0.75). * * @param t the map whose mappings are to be placed in this map. * @throws NullPointerException if the specified map is null. * @since 1.2 */ public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); } /** * Returns the number of keys in this hashtable. * * @return the number of keys in this hashtable. */ public synchronized int size() { return count; } /** * Tests if this hashtable maps no keys to values. * * @return <code>true</code> if this hashtable maps no keys to values; * <code>false</code> otherwise. */ public synchronized boolean isEmpty() { return count == 0; } /** * Returns an enumeration of the keys in this hashtable. * * @return an enumeration of the keys in this hashtable. * @see Enumeration * @see #elements() * @see #keySet() * @see Map */ public synchronized Enumeration<K> keys() { return this.<K>getEnumeration(KEYS); } /** * Returns an enumeration of the values in this hashtable. * Use the Enumeration methods on the returned object to fetch the elements * sequentially. * * @return an enumeration of the values in this hashtable. * @see java.util.Enumeration * @see #keys() * @see #values() * @see Map */ public synchronized Enumeration<V> elements() { return this.<V>getEnumeration(VALUES); } /** * Tests if some key maps into the specified value in this hashtable. * This operation is more expensive than the {@link #containsKey * containsKey} method. * * <p>Note that this method is identical in functionality to * {@link #containsValue containsValue}, (which is part of the * {@link Map} interface in the collections framework). * * @param value a value to search for * @return <code>true</code> if and only if some key maps to the * <code>value</code> argument in this hashtable as * determined by the <tt>equals</tt> method; * <code>false</code> otherwise. * @exception NullPointerException if the value is <code>null</code> */ public synchronized boolean contains(Object value) { if (value == null) { throw new NullPointerException(); } Entry<?,?> tab[] = table; for (int i = tab.length ; i-- > 0 ;) { for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; } /** * Returns true if this hashtable maps one or more keys to this value. * * <p>Note that this method is identical in functionality to {@link * #contains contains} (which predates the {@link Map} interface). * * @param value value whose presence in this hashtable is to be tested * @return <tt>true</tt> if this map maps one or more keys to the * specified value * @throws NullPointerException if the value is <code>null</code> * @since 1.2 */ public boolean containsValue(Object value) { return contains(value); } /** * Tests if the specified object is a key in this hashtable. * * @param key possible key * @return <code>true</code> if and only if the specified object * is a key in this hashtable, as determined by the * <tt>equals</tt> method; <code>false</code> otherwise. * @throws NullPointerException if the key is <code>null</code> * @see #contains(Object) */ public synchronized boolean containsKey(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false; } /** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * <p>More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key.equals(k))}, * then this method returns {@code v}; otherwise it returns * {@code null}. (There can be at most one such mapping.) * * @param key the key whose associated value is to be returned * @return the value to which the specified key is mapped, or * {@code null} if this map contains no mapping for the key * @throws NullPointerException if the specified key is null * @see #put(Object, Object) */ @SuppressWarnings("unchecked") public synchronized V get(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null; } /** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * Increases the capacity of and internally reorganizes this * hashtable, in order to accommodate and access its entries more * efficiently. This method is called automatically when the * number of keys in the hashtable exceeds this hashtable's capacity * and load factor. */ @SuppressWarnings("unchecked") protected void rehash() { int oldCapacity = table.length; Entry<?,?>[] oldMap = table; // overflow-conscious code int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE; } Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); table = newMap; for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry<K,V>)newMap[index]; newMap[index] = e; } } } private void addEntry(int hash, K key, V value, int index) { modCount++; Entry<?,?> tab[] = table; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; } /** * Maps the specified <code>key</code> to the specified * <code>value</code> in this hashtable. Neither the key nor the * value can be <code>null</code>. <p> * * The value can be retrieved by calling the <code>get</code> method * with a key that is equal to the original key. * * @param key the hashtable key * @param value the value * @return the previous value of the specified key in this hashtable, * or <code>null</code> if it did not have one * @exception NullPointerException if the key or value is * <code>null</code> * @see Object#equals(Object) * @see #get(Object) */ public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; } /** * Removes the key (and its corresponding value) from this * hashtable. This method does nothing if the key is not in the hashtable. * * @param key the key that needs to be removed * @return the value to which the key had been mapped in this hashtable, * or <code>null</code> if the key did not have a mapping * @throws NullPointerException if the key is <code>null</code> */ public synchronized V remove(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; } /** * Copies all of the mappings from the specified map to this hashtable. * These mappings will replace any mappings that this hashtable had for any * of the keys currently in the specified map. * * @param t mappings to be stored in this map * @throws NullPointerException if the specified map is null * @since 1.2 */ public synchronized void putAll(Map<? extends K, ? extends V> t) { for (Map.Entry<? extends K, ? extends V> e : t.entrySet()) put(e.getKey(), e.getValue()); } /** * Clears this hashtable so that it contains no keys. */ public synchronized void clear() { Entry<?,?> tab[] = table; modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; } /** * Creates a shallow copy of this hashtable. All the structure of the * hashtable itself is copied, but the keys and values are not cloned. * This is a relatively expensive operation. * * @return a clone of the hashtable */ public synchronized Object clone() { try { Hashtable<?,?> t = (Hashtable<?,?>)super.clone(); t.table = new Entry<?,?>[table.length]; for (int i = table.length ; i-- > 0 ; ) { t.table[i] = (table[i] != null) ? (Entry<?,?>) table[i].clone() : null; } t.keySet = null; t.entrySet = null; t.values = null; t.modCount = 0; return t; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } } /** * Returns a string representation of this <tt>Hashtable</tt> object * in the form of a set of entries, enclosed in braces and separated * by the ASCII characters "<tt>, </tt>" (comma and space). Each * entry is rendered as the key, an equals sign <tt>=</tt>, and the * associated element, where the <tt>toString</tt> method is used to * convert the key and element to strings. * * @return a string representation of this hashtable */ public synchronized String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder(); Iterator<Map.Entry<K,V>> it = entrySet().iterator(); sb.append('{'); for (int i = 0; ; i++) { Map.Entry<K,V> e = it.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key.toString()); sb.append('='); sb.append(value == this ? "(this Map)" : value.toString()); if (i == max) return sb.append('}').toString(); sb.append(", "); } } private <T> Enumeration<T> getEnumeration(int type) { if (count == 0) { return Collections.emptyEnumeration(); } else { return new Enumerator<>(type, false); } } private <T> Iterator<T> getIterator(int type) { if (count == 0) { return Collections.emptyIterator(); } else { return new Enumerator<>(type, true); } } // Views /** * Each of these fields are initialized to contain an instance of the * appropriate view the first time this view is requested. The views are * stateless, so there's no reason to create more than one of each. */ private transient volatile Set<K> keySet = null; private transient volatile Set<Map.Entry<K,V>> entrySet = null; private transient volatile Collection<V> values = null; /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own <tt>remove</tt> operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> * operations. It does not support the <tt>add</tt> or <tt>addAll</tt> * operations. * * @since 1.2 */ public Set<K> keySet() { if (keySet == null) keySet = Collections.synchronizedSet(new KeySet(), this); return keySet; } private class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return getIterator(KEYS); } public int size() { return count; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return Hashtable.this.remove(o) != null; } public void clear() { Hashtable.this.clear(); } } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own <tt>remove</tt> operation, or through the * <tt>setValue</tt> operation on a map entry returned by the * iterator) the results of the iteration are undefined. The set * supports element removal, which removes the corresponding * mapping from the map, via the <tt>Iterator.remove</tt>, * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and * <tt>clear</tt> operations. It does not support the * <tt>add</tt> or <tt>addAll</tt> operations. * * @since 1.2 */ public Set<Map.Entry<K,V>> entrySet() { if (entrySet==null) entrySet = Collections.synchronizedSet(new EntrySet(), this); return entrySet; } private class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return getIterator(ENTRIES); } public boolean add(Map.Entry<K,V> o) { return super.add(o); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> entry = (Map.Entry<?,?>)o; Object key = entry.getKey(); Entry<?,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index]; e != null; e = e.next) if (e.hash==hash && e.equals(entry)) return true; return false; } public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> entry = (Map.Entry<?,?>) o; Object key = entry.getKey(); Entry<?,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash==hash && e.equals(entry)) { modCount++; if (prev != null) prev.next = e.next; else tab[index] = e.next; count--; e.value = null; return true; } } return false; } public int size() { return count; } public void clear() { Hashtable.this.clear(); } } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress * (except through the iterator's own <tt>remove</tt> operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding * mapping from the map, via the <tt>Iterator.remove</tt>, * <tt>Collection.remove</tt>, <tt>removeAll</tt>, * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not * support the <tt>add</tt> or <tt>addAll</tt> operations. * * @since 1.2 */ public Collection<V> values() { if (values==null) values = Collections.synchronizedCollection(new ValueCollection(), this); return values; } private class ValueCollection extends AbstractCollection<V> { public Iterator<V> iterator() { return getIterator(VALUES); } public int size() { return count; } public boolean contains(Object o) { return containsValue(o); } public void clear() { Hashtable.this.clear(); } } // Comparison and hashing /** * Compares the specified Object with this Map for equality, * as per the definition in the Map interface. * * @param o object to be compared for equality with this hashtable * @return true if the specified Object is equal to this Map * @see Map#equals(Object) * @since 1.2 */ public synchronized boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map<?,?> t = (Map<?,?>) o; if (t.size() != size()) return false; try { Iterator<Map.Entry<K,V>> i = entrySet().iterator(); while (i.hasNext()) { Map.Entry<K,V> e = i.next(); K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(t.get(key)==null && t.containsKey(key))) return false; } else { if (!value.equals(t.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; } /** * Returns the hash code value for this Map as per the definition in the * Map interface. * * @see Map#hashCode() * @since 1.2 */ public synchronized int hashCode() { /* * This code detects the recursion caused by computing the hash code * of a self-referential hash table and prevents the stack overflow * that would otherwise result. This allows certain 1.1-era * applets with self-referential hash tables to work. This code * abuses the loadFactor field to do double-duty as a hashCode * in progress flag, so as not to worsen the space performance. * A negative load factor indicates that hash code computation is * in progress. */ int h = 0; if (count == 0 || loadFactor < 0) return h; // Returns zero loadFactor = -loadFactor; // Mark hashCode computation in progress Entry<?,?>[] tab = table; for (Entry<?,?> entry : tab) { while (entry != null) { h += entry.hashCode(); entry = entry.next; } } loadFactor = -loadFactor; // Mark hashCode computation complete return h; } @Override public synchronized V getOrDefault(Object key, V defaultValue) { V result = get(key); return (null == result) ? defaultValue : result; } @SuppressWarnings("unchecked") @Override public synchronized void forEach(BiConsumer<? super K, ? super V> action) { Objects.requireNonNull(action); // explicit check required in case // table is empty. final int expectedModCount = modCount; Entry<?, ?>[] tab = table; for (Entry<?, ?> entry : tab) { while (entry != null) { action.accept((K)entry.key, (V)entry.value); entry = entry.next; if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } } @SuppressWarnings("unchecked") @Override public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { Objects.requireNonNull(function); // explicit check required in case // table is empty. final int expectedModCount = modCount; Entry<K, V>[] tab = (Entry<K, V>[])table; for (Entry<K, V> entry : tab) { while (entry != null) { entry.value = Objects.requireNonNull( function.apply(entry.key, entry.value)); entry = entry.next; if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } } @Override public synchronized V putIfAbsent(K key, V value) { Objects.requireNonNull(value); // Makes sure the key is not already in the hashtable. Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for (; entry != null; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; if (old == null) { entry.value = value; } return old; } } addEntry(hash, key, value, index); return null; } @Override public synchronized boolean remove(Object key, Object value) { Objects.requireNonNull(value); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; e.value = null; return true; } } return false; } @Override public synchronized boolean replace(K key, V oldValue, V newValue) { Objects.requireNonNull(oldValue); Objects.requireNonNull(newValue); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { if (e.value.equals(oldValue)) { e.value = newValue; return true; } else { return false; } } } return false; } @Override public synchronized V replace(K key, V value) { Objects.requireNonNull(value); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { V oldValue = e.value; e.value = value; return oldValue; } } return null; } @Override public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { Objects.requireNonNull(mappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (; e != null; e = e.next) { if (e.hash == hash && e.key.equals(key)) { // Hashtable not accept null value return e.value; } } V newValue = mappingFunction.apply(key); if (newValue != null) { addEntry(hash, key, newValue, index); } return newValue; } @Override public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { V newValue = remappingFunction.apply(key, e.value); if (newValue == null) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; } else { e.value = newValue; } return newValue; } } return null; } @Override public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && Objects.equals(e.key, key)) { V newValue = remappingFunction.apply(key, e.value); if (newValue == null) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; } else { e.value = newValue; } return newValue; } } V newValue = remappingFunction.apply(key, null); if (newValue != null) { addEntry(hash, key, newValue, index); } return newValue; } @Override public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { V newValue = remappingFunction.apply(e.value, value); if (newValue == null) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; } else { e.value = newValue; } return newValue; } } if (value != null) { addEntry(hash, key, value, index); } return value; } /** * Save the state of the Hashtable to a stream (i.e., serialize it). * * @serialData The <i>capacity</i> of the Hashtable (the length of the * bucket array) is emitted (int), followed by the * <i>size</i> of the Hashtable (the number of key-value * mappings), followed by the key (Object) and value (Object) * for each key-value mapping represented by the Hashtable * The key-value mappings are emitted in no particular order. */ private void writeObject(java.io.ObjectOutputStream s) throws IOException { Entry<Object, Object> entryStack = null; synchronized (this) { // Write out the length, threshold, loadfactor s.defaultWriteObject(); // Write out length, count of elements s.writeInt(table.length); s.writeInt(count); // Stack copies of the entries in the table for (int index = 0; index < table.length; index++) { Entry<?,?> entry = table[index]; while (entry != null) { entryStack = new Entry<>(0, entry.key, entry.value, entryStack); entry = entry.next; } } } // Write out the key/value objects from the stacked entries while (entryStack != null) { s.writeObject(entryStack.key); s.writeObject(entryStack.value); entryStack = entryStack.next; } } /** * Reconstitute the Hashtable from a stream (i.e., deserialize it). */ private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the length, threshold, and loadfactor s.defaultReadObject(); // Read the original length of the array and number of elements int origlength = s.readInt(); int elements = s.readInt(); // Compute new size with a bit of room 5% to grow but // no larger than the original size. Make the length // odd if it's large enough, this helps distribute the entries. // Guard against the length ending up zero, that's not valid. int length = (int)(elements * loadFactor) + (elements / 20) + 3; if (length > elements && (length & 1) == 0) length--; if (origlength > 0 && length > origlength) length = origlength; table = new Entry<?,?>[length]; threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1); count = 0; // Read the number of elements and then all the key/value objects for (; elements > 0; elements--) { @SuppressWarnings("unchecked") K key = (K)s.readObject(); @SuppressWarnings("unchecked") V value = (V)s.readObject(); // synch could be eliminated for performance reconstitutionPut(table, key, value); } } /** * The put method used by readObject. This is provided because put * is overridable and should not be called in readObject since the * subclass will not yet be initialized. * * <p>This differs from the regular put method in several ways. No * checking for rehashing is necessary since the number of elements * initially in the table is known. The modCount is not incremented * because we are creating a new instance. Also, no return value * is needed. */ private void reconstitutionPut(Entry<?,?>[] tab, K key, V value) throws StreamCorruptedException { if (value == null) { throw new java.io.StreamCorruptedException(); } // Makes sure the key is not already in the hashtable. // This should not happen in deserialized version. int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { throw new java.io.StreamCorruptedException(); } } // Creates the new entry. @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; } /** * Hashtable bucket collision list entry */ private static class Entry<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Entry<K,V> next; protected Entry(int hash, K key, V value, Entry<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } @SuppressWarnings("unchecked") protected Object clone() { return new Entry<>(hash, key, value, (next==null ? null : (Entry<K,V>) next.clone())); } // Map.Entry Ops public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { if (value == null) throw new NullPointerException(); V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; return (key==null ? e.getKey()==null : key.equals(e.getKey())) && (value==null ? e.getValue()==null : value.equals(e.getValue())); } public int hashCode() { return hash ^ Objects.hashCode(value); } public String toString() { return key.toString()+"="+value.toString(); } } // Types of Enumerations/Iterations private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2; /** * A hashtable enumerator class. This class implements both the * Enumeration and Iterator interfaces, but individual instances * can be created with the Iterator methods disabled. This is necessary * to avoid unintentionally increasing the capabilities granted a user * by passing an Enumeration. */ private class Enumerator<T> implements Enumeration<T>, Iterator<T> { Entry<?,?>[] table = Hashtable.this.table; int index = table.length; Entry<?,?> entry = null; Entry<?,?> lastReturned = null; int type; /** * Indicates whether this Enumerator is serving as an Iterator * or an Enumeration. (true -> Iterator). */ boolean iterator; /** * The modCount value that the iterator believes that the backing * Hashtable should have. If this expectation is violated, the iterator * has detected concurrent modification. */ protected int expectedModCount = modCount; Enumerator(int type, boolean iterator) { this.type = type; this.iterator = iterator; } public boolean hasMoreElements() { Entry<?,?> e = entry; int i = index; Entry<?,?>[] t = table; /* Use locals for faster loop iteration */ while (e == null && i > 0) { e = t[--i]; } entry = e; index = i; return e != null; } @SuppressWarnings("unchecked") public T nextElement() { Entry<?,?> et = entry; int i = index; Entry<?,?>[] t = table; /* Use locals for faster loop iteration */ while (et == null && i > 0) { et = t[--i]; } entry = et; index = i; if (et != null) { Entry<?,?> e = lastReturned = entry; entry = e.next; return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e); } throw new NoSuchElementException("Hashtable Enumerator"); } // Iterator methods public boolean hasNext() { return hasMoreElements(); } public T next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); return nextElement(); } public void remove() { if (!iterator) throw new UnsupportedOperationException(); if (lastReturned == null) throw new IllegalStateException("Hashtable Enumerator"); if (modCount != expectedModCount) throw new ConcurrentModificationException(); synchronized(Hashtable.this) { Entry<?,?>[] tab = Hashtable.this.table; int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { modCount++; expectedModCount++; if (prev == null) tab[index] = e.next; else prev.next = e.next; count--; lastReturned = null; return; } } throw new ConcurrentModificationException(); } } } } P.S: автор трида удивительный таки человек, раз пишет свои велосипеды (намек на apache commons с их configuration), когда они невостребованны. |
|
26.03.2014, 17:47 | #20 |
Изгнанные
|
Re: Core
Пардон
Я думал вы про другое, а вы дали исходы с SDK. На сколько я понял, автор имел ввиду "ConcurrentHashMap или CopyOnWriteArrayList" и грузить конфиги в один объект, без нагрузки с Properties, так как в нем используются устаревшие расширения коллекций "Hashtable" которые синхронизируются по этому производительность уменьшается, так как в данной области будут одновременные обращения. В многопоточности "Hashtable" проиграет в скорости и производительности в целом. "HashMap" проиграет "ConcurrentHashMap" - так как будет эффективнее с большим количеством хранимых данных и операций доступа к ним. |
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1) | |
|
|
Похожие темы | ||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
Компиляция ядра, создание сборки Trinity Core 3.3.5a под Win32 | PuShKinG | Документация | 199 | 30.10.2019 10:18 |
unmetered выделенные серверы от $50, VPS от $7.50, оффшорные VPS от $9 | MultiServers | Рынок / Marketplace | 0 | 11.10.2013 13:40 |
Требуется программер Java Core Developer на частиную основу | niko42 | Рынок / Marketplace | 12 | 21.05.2011 23:24 |
Java Core Developer на интересную работу. | Bugsoft | Рынок / Marketplace | 0 | 26.03.2011 09:28 |