Я бы не использовал URLEncoder
. Помимо неправильного имени (URLEncoder
не имеет ничего общего с URL-адресами), неэффективен (вместо Builder он использует StringBuffer
и делает несколько других вещей, которые медленны). Также слишком легко его испортить.
Вместо этого я использовал бы URIBuilder
или Spring org.springframework.web.util.UriUtils.encodeQuery
или Commons Apache HttpClient
. Причина заключается в том, что вам нужно избегать имени параметров запроса (то есть ответ BalusC q
) иначе, чем значение параметра.
Единственный недостаток вышеизложенного (что я обнаружил болезненно) заключается в том, что URL не является истинным подмножеством URI .
Пример кода:
import org.apache.http.client.utils.URIBuilder;
URIBuilder ub = new URIBuilder("http://example.com/query");
ub.addParameter("q", "random word £500 bank \$");
String url = ub.toString();
// Result: http://example.com/query?q=random+word+%C2%A3500+bank+%24
Поскольку я просто ссылаюсь на другие ответы, я отметил это как вики сообщества. Не стесняйтесь редактировать.
Нет никакой разницы между объектами; у вас есть HashMap<String, Object>
в обоих случаях. Существует разница в интерфейсе , который у вас есть для объекта. В первом случае интерфейс HashMap<String, Object>
, а во втором - Map<String, Object>
. Но основной объект тот же.
Преимущество использования Map<String, Object>
заключается в том, что вы можете изменить базовый объект как другой вид карты, не нарушая контракт с любым кодом, который его использует. Если вы объявите его как HashMap<String, Object>
, вы должны изменить свой контракт, если хотите изменить базовую реализацию.
Пример: допустим, я пишу этот класс:
class Foo {
private HashMap<String, Object> things;
private HashMap<String, Object> moreThings;
protected HashMap<String, Object> getThings() {
return this.things;
}
protected HashMap<String, Object> getMoreThings() {
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Класс имеет пару внутренних карт объекта string->, которые он разделяет (через методы доступа) с подклассами. Скажем, я пишу его с помощью HashMap
s, потому что я думаю, что это подходящая структура для использования при написании класса.
Позже Мэри пишет код, подклассифицирующий его. У нее есть что-то, что ей нужно делать как с things
, так и с moreThings
, поэтому, естественно, она ставит это в общий метод, и она использует тот же тип, который я использовал в getThings
/ getMoreThings
при определении ее метода:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Позже я решил, что на самом деле лучше использовать TreeMap
вместо HashMap
в Foo
. Я обновляю Foo
, меняя HashMap
на TreeMap
. Теперь SpecialFoo
больше не компилируется, потому что я нарушил контракт: Foo
говорил, что он предоставил HashMap
s, но теперь он предоставляет TreeMaps
. Итак, мы должны исправить SpecialFoo
сейчас (и этот вид может пульсировать через кодовую базу).
Если у меня не было действительно веских оснований для совместного использования того, что моя реализация использовала HashMap
(и это это должно произойти), то, что я должен был сделать, было объявлено getThings
и getMoreThings
как только возвращающееся Map<String, Object>
, не будучи более конкретным, чем это. На самом деле, за исключением хорошей причины делать что-то еще, даже внутри Foo
, я должен, вероятно, объявить things
и moreThings
как Map
, а не HashMap
/ TreeMap
:
class Foo {
private Map<String, Object> things; // <== Changed
private Map<String, Object> moreThings; // <== Changed
protected Map<String, Object> getThings() { // <== Changed
return this.things;
}
protected Map<String, Object> getMoreThings() { // <== Changed
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Обратите внимание, как я использую Map<String, Object>
везде, где только могу, только будучи конкретным, когда я создаю фактические объекты.
Если бы я это сделал, Мэри сделала бы это:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
... и смена Foo
не заставили бы SpecialFoo
прекратить компиляцию.
Интерфейсы (и базовые классы) позволяют выявить только столько, сколько необходимо , сохраняя нашу гибкость под обложками, чтобы внести соответствующие изменения. В общем, мы хотим, чтобы наши ссылки были максимально простыми. Если нам не нужно знать, что это HashMap
, просто назовите его Map
.
Это не слепое правило, но, в общем, кодирование для самого общего интерфейса будет менее хрупким, чем кодирование в нечто более конкретное. Если бы я вспомнил об этом, я бы не создал Foo
, который заставил Мэри потерпеть неудачу с SpecialFoo
. Если Mary запомнил это, то, хотя я испортил Foo
, она объявила бы свой частный метод с Map
вместо HashMap
, и мой изменяющийся контракт Foo
t повлияли на ее код.
Иногда вы не можете этого сделать, иногда вам нужно быть конкретным. Но если у вас нет причин для этого, ошибайтесь в отношении наименее специфического интерфейса.
В вашем втором примере ссылка «map» имеет тип Map
, который является интерфейсом, реализованным HashMap
(и другими типами Map
). Этот интерфейс представляет собой контракт, в котором говорится, что объект сопоставляет ключи со значениями и поддерживает различные операции (например, put
, get
). Он ничего не говорит о реализации Map
(в данном случае a HashMap
).
Второй подход обычно предпочтительнее, поскольку вы обычно не хотели бы подвергать конкретную реализацию карты методам, используя Map
или через определение API.
Как отмечалось TJ Crowder и Adamski, одна ссылка - на интерфейс, а другая - на конкретную реализацию интерфейса. Согласно Joshua Block, вы всегда должны пытаться кодировать интерфейсы, чтобы вы могли лучше обрабатывать изменения в базовой реализации - то есть, если HashMap внезапно не был идеальным для вашего решения, и вам нужно было изменить реализацию карты, вы все равно могли бы использовать Map интерфейс и изменить тип экземпляра.
Карта - это интерфейс, а Hashmap - это класс, который реализует это.
Итак, в этой реализации вы создаете те же объекты
HashMap - это реализация Map, так что он совершенно такой же, но имеет метод «clone ()», как я вижу в справочном руководстве))
Карта - это статический тип карты, а HashMap - динамический тип карты. Это означает, что компилятор будет рассматривать ваш объект карты как один из типов Map, хотя во время выполнения он может указывать на любой подтип этого файла.
Эта практика программирования против интерфейсов вместо реализаций имеет добавленную Вы можете, например, заменить динамический тип карты во время выполнения, если это подтип Map (например, LinkedHashMap) и изменить поведение карты на лету.
Хороший эмпирическое правило должно оставаться как можно более абстрактным на уровне API: если, например, метод, который вы программируете, должен работать на картах, то достаточно объявить параметр как карту вместо более строгого (потому что менее абстрактного) типа HashMap. Таким образом, потребитель вашего API может быть гибким в отношении того, какую реализацию карты они хотят передать вашему методу.
Карта - это интерфейс, который реализуется HashMap . Разница в том, что во второй реализации ваша ссылка на HashMap позволит использовать функции, определенные в интерфейсе карты, в то время как первая позволит использовать любые общедоступные функции в HashMap (включая интерфейс карты).
Это, вероятно, будет иметь больше смысла, если вы прочитаете учебник по интерфейсу Sun
HashMap<String, Object> map1 = new HashMap<String, Object>();
Map<String, Object> map2 = new HashMap<String, Object>();
Прежде всего Map
- это интерфейс, который имеет другую реализацию, например - HashMap
, TreeHashMap
, LinkedHashMap
и т. д. Интерфейс работает как суперкласс для класса реализации. Таким образом, согласно правилу ООП, любой конкретный класс, реализующий Map
, также является Map
. Это означает, что мы можем назначить / поместить любую переменную типа HashMap
в переменную типа Map
без какого-либо литья.
В этом случае мы можем назначить map1
на map2
без кастинга или потери данных -
map2 = map1
Вы создаете одни и те же карты.
Но вы можете заполнить разницу, когда будете использовать его. В первом случае вы сможете использовать специальные методы HashMap (но я не помню, чтобы кто-либо действительно был полезен), и вы сможете передать его как параметр HashMap:
public void foo (HashMap<String, Object) { ... }
...
HashMap<String, Object> m1 = ...;
Map<String, Object> m2 = ...;
foo (m1);
foo ((HashMap<String, Object>)m2);
Карта - это интерфейс, а Hashmap - это класс, реализующий интерфейс карты
Добавляя к верхнему проголосовавшему ответу и многим выше, подчеркивая «более общий, лучший», я хотел бы копать немного больше.
Map
является структурным контрактом, а HashMap
представляет собой реализацию, предоставляющую свои собственные методы для решения различных реальных проблем: как рассчитать индекс, какова емкость и как его увеличить, как вставить, как сохранить индекс уникальным и т. д.
Давайте посмотрите в исходный код:
В Map
у нас есть метод containsKey(Object key)
:
boolean containsKey(Object key);
JavaDoc:
boolean java .util.Map.containsValue (значение объекта)
Возвращает true, если эта карта отображает одну или несколько клавиш в указанное значение. Более формально возвращает true тогда и только тогда, когда эта карта содержит хотя бы одно сопоставление со значением
v
, таким как(value==null ? v==null : value.equals(v))
.Параметры: значение
значение, наличие которого на этой карте должно быть указано
Возвращает: true
, если это отображение отображает одну или несколько клавиш в указанное значение
Throws:
ClassCastException - если значение имеет неправильный тип для эта карта (необязательно)
NullPointerException - если указанное значение равно null, и эта карта не допускает нулевые значения (необязательно)
blockquote>Для ее реализации требуются ее реализации, [7]
HashMap
:public boolean containsKey(Object key) { return getNode(hash(key), key) != null; }
Оказывается,
HashMap
использует hashcode для того, чтобы проверьте, содержит ли эта карта ключ. Таким образом, он имеет преимущество алгоритма хеширования.