목차
2 队列
3 Map
3.1 性能
4 散列与散列码
4.1 散列概念
2 Queue
3 맵
3.1 성능
4 해시 및 해시 코드
4.1 해시 개념
4.2 理解散列
4.3 HashMap查询过程(快速原因)
4.4 简单散列Map的实现
4.5 覆盖hashCode()
5 选择不同接口的实现
5.1 微基准测试的危险(Microbenchmarking dangers)
5.2 HashMap的性能因子
6 Collection或Map的同步控制
6.1 快速报错(fail-fast)
Java java지도 시간 자바 프로그래밍 사고 학습 수업(4) 17장 - 컨테이너에 대한 심층 토론

자바 프로그래밍 사고 학습 수업(4) 17장 - 컨테이너에 대한 심층 토론

Aug 09, 2018 pm 02:42 PM
java

1 집합 및 저장 순서

  • SetSet的元素必须定义equals()方法以确保对象的唯一性

  • hashCode()只有这个类被置于HashSet或者LinkedHashSet中时才是必需的。但是对于良好的编程风格而言,你应该在覆盖equals()方法时,总是同时覆盖hashCode()方法。

  • 如果一个对象被用于任何种类的排序容器中,例如SortedSetTreeSet是其唯一实现),那么它必须实现Comparable接口。

  • 注意,SortedSet的意思是“按对象的比较函数对元素排序”,而不是指“元素插入的次序”。插入顺序LinkedHashSet来保存。

2 队列

  • 队了并发应用,Queue在Java SE5中仅有的两个实现是LinkiedListPriorityQueue,它们仅有排序行为的差异,性能上没有差异。

  • 优先级队列PriorityQueue的排列顺序也是通过实现Comparable而进行控制的。

3 Map

  映射表(也称为关联数组Associative Array)。

3.1 性能

  HashMap使用了特殊的值,称作散列码(hash code),来取代对键的缓慢搜索。散列码是“相对唯一”的、用以代表对象的int值,它是通过将该对象的某些信息进行转换而生成的。
hashCode()是根类Object中的方法,因此所有对象都能产生散列码。

  对Map中使用的键的要求与对Set中的元素的要求一样:

  • 任何键都必须具有一个equals()方法;

  • 如果键被用于散列Map,那么它必须还具有恰当的hashCode()方法;

  • 如果键被用于TreeMap,那么它必须实现Comparable

4 散列与散列码

  HashMap使用equals()判断当前的键是否与表中存在的键相同。
  默认的Object.equals()只是比较对象的地址如果要使用自己的类作为HashMap的键,必须同时重写hashCode()equals()
  正确的equals()方法必须满足下列5个条件:

  • 自反性。

  • 对称性。

  • 传递性。

  • 一致性。

  • 对任何不是null的xx.equals(null)一定返回false

4.1 散列概念

  使用散列的目的在于:想要使用一个对象来查找另一个对象
  Map的实现类使用散列是为了提高查询速度

散列的价值在于速度散列使得查询得以快速进行。由于瓶颈位于查询速度,因此解决方案之一就是保持键的排序状态,然后使用Collections.binarySearch()에 추가된 요소는

equals()

메서드를 정의하여 객체가 독특한 섹스입니다.

🎜🎜🎜hashCode()🎜이 클래스는 HashSet 또는 LinkedHashSet에 배치된 경우에만 필요합니다. 그러나 좋은 프로그래밍 스타일의 문제로, equals() 메서드를 재정의할 때는 항상 hashCode() 메서드를 재정의해야 합니다. 🎜🎜🎜SortedSet(이 중 TreeSet이 유일한 구현임)과 같은 모든 종류의 🎜🎜정렬된 컨테이너🎜🎜에서 개체가 사용되는 경우 그런 다음 🎜Comparable🎜 인터페이스를 구현해야 합니다. 🎜🎜🎜 🎜SortedSet🎜은 "요소가 삽입되는 순서"가 아니라 "객체의 🎜🎜 비교 함수🎜🎜에 따라 요소를 정렬하는 것"을 의미합니다. 🎜🎜삽입 순서🎜🎜는 🎜LinkedHashSet🎜에 저장됩니다. 🎜

2 Queue

🎜🎜🎜Java SE5에서 Queue의 유일한 두 가지 구현은 🎜LinkedList🎜 및 🎜 입니다. PriorityQueue🎜는 🎜정렬 동작🎜만 다를 뿐 성능에는 차이가 없습니다. 🎜🎜🎜우선순위 큐 PriorityQueue의 순서도 🎜Comparable🎜 구현을 통해 제어됩니다. 🎜

3 맵

🎜 — 🎜🎜Map table🎜🎜(🎜associative array🎜🎜Associative Array🎜이라고도 함). 🎜

3.1 성능

🎜 HashMap은 🎜🎜hash code🎜🎜(해시 코드)라는 특수 값을 사용하여 느린 키 검색을 대체합니다. 해시 코드는 객체를 나타내는 데 사용되는 🎜🎜 "상대적으로 고유한" 🎜🎜 int 값으로, 객체에 대한 🎜특정 정보를 변환하여 생성됩니다. 🎜hashCode()는 루트 클래스 Object의 메소드이므로 모든 객체가 해시 코드를 생성할 수 있습니다. 🎜🎜 Map에 사용되는 키에 대한 요구 사항은 Set의 요소에 대한 요구 사항과 동일합니다. 🎜🎜🎜🎜모든 키에는 🎜equals()🎜 메서드가 있어야 합니다. 🎜🎜 🎜If 키가 해시된 맵에 사용되는 경우 적절한 🎜hashCode()🎜메서드도 있어야 합니다. 🎜🎜🎜키가 🎜TreeMap에 사용되는 경우 code>🎜인 경우 🎜<code>Comparable🎜을 구현해야 합니다. 🎜

4 해시 및 해시 코드

🎜 HashMap은 🎜equals()🎜를 사용하여 현재 키가 존재하는 키와 동일한지 확인합니다. 테이블에. 🎜 🎜기본 Object.equals()는 객체의 주소만 비교합니다 🎜. 🎜자신의 클래스를 HashMap🎜의 키로 사용하려면 🎜🎜hashCode()equals()🎜🎜을 동시에 재정의해야 합니다. 🎜 올바른 equals() 메서드는 다음 5가지 조건을 충족해야 합니다: 🎜🎜🎜🎜재귀성. 🎜🎜🎜대칭. 🎜🎜🎜전환성. 🎜🎜🎜일관성. 🎜🎜🎜null이 아닌 모든 x의 경우 x.equals(null)false를 반환해야 합니다. 🎜

4.1 해시 개념

🎜 해싱을 사용하는 목적은 다음과 같습니다. 🎜한 객체를 사용하여 다른 객체를 찾고 싶습니다🎜. 🎜 Map의 구현 클래스는 해싱을 사용하여 🎜🎜쿼리 속도를 높입니다🎜🎜. 🎜
🎜🎜해싱의 가치는 속도입니다🎜: 🎜해싱은 쿼리를 빠르게 만듭니다🎜. 병목 현상이 🎜🎜쿼리 속도🎜🎜에 있으므로 해결 방법 중 하나는 키를 정렬된 상태로 유지한 다음 Collections.binarySearch()를 사용하여 쿼리하는 것입니다. 🎜🎜🎜🎜해싱은 한 단계 더 발전하여 키를 빠르게 찾을 수 있도록 어딘가에 키를 저장합니다🎜🎜. 요소 집합을 저장하는 가장 빠른 데이터 구조는 배열이므로 이를 사용하여 키 정보를 나타냅니다(키 자체가 아니라 키 정보를 의미한다는 점에 주의하세요). 하지만 배열이 용량을 조정할 수 없기 때문에 문제가 있습니다. 불확실한 수의 값을 맵에 저장하고 싶지만 배열의 용량에 따라 키 수가 제한되면 어떻게 될까요? 🎜

答案就是:数组并不保存键本身。而是通过键对象生成一个数字,将其作为数组的下标。这个数字就是散列码,由定义在Object中的、且可能由你的类覆盖的hashCode()方法(在计算机科学的术语中称为散列函数)生成。

为解决数组容量固定的问题,不同的键可以产生相同的下标。也就是说,可能会有冲突,即散列码不必是独一无二的。因此,数组多大就不重要了,任何键总能在数组中找到它的位置。

4.2 理解散列

  综上,散列就是将一个对象生成一个数字保存下来(作为数组的下标),然后在查找这个对象时直接找到这个数字就可以了,所以散列的目的是为了提高查找速度,而手段是将一个对象生成的数字与其关联并保存下来(通过数组,称为散列表)。这个生成的数字就是散列码。而生成这个散列码的方法称为散列函数hashCode())。

4.3 HashMap查询过程(快速原因)

  因此,HashMap中查询一个key的过程就是:

  • 首先计算散列码

  • 然后使用散列码查询数组(散列码作变数组下标)

  • 如果没有冲突,即生成这个散列码的对象只有一个,则散列码对应的数组下标的位置就是这个要查找的元素

  • 如果有冲突,则散列码对应的下标所在数组元素保存的是一个list,然后对list中的值使用equals()方法进行线性查询。

  因此,不是查询整个list,而是快速地跳到数组的某个位置,只对很少的元素进行比较。这便是HashMap会如此快速的原因

4.4 简单散列Map的实现

  • 散列表中的槽位(slot)通常称为桶位(bucket)

  • 为使散列均匀,桶的数量通常使用质数JDK5中是质数,JDK7中已经是2的整数次方了)。

    事实证明,质数实际上并不是散列桶的理想容量。近来,(通过广泛的测试)Java的散列函数都使用2的整数次方。对现代处理器来说,除法与求余数是最慢的操作。使用2的整数次方长度的散列表,可用掩码代替除法。因为get()是使用最多的操作,求余数的%操作是其开销最大的部分,而使用2的整数次方可以消除此开销(也可能对hashCode()有些影响)。
  • get()方法按照与put()方法相同的方式计算在buckets数组中的索引,这很重要,因为这样可以保证两个方法可以计算出相同的位置

package net.mrliuli.containers;

import java.util.*;public class SimpleHashMap<K, V> extends AbstractMap<K, V> {    // Choose a prime number for the hash table size, to achieve a uniform distribution:
    static final int SIZE = 997;    // You can&#39;t have a physical array of generics, but you can upcast to one:
    @SuppressWarnings("unchecked")
    LinkedList<MapEntry<K,V>>[] buckets = new LinkedList[SIZE];

    @Override    public V put(K key, V value){        int index = Math.abs(key.hashCode()) % SIZE;        if(buckets[index] == null){
            buckets[index] = new LinkedList<MapEntry<K,V>>();
        }

        LinkedList<MapEntry<K,V>> bucket = buckets[index];
        MapEntry<K,V> pair = new MapEntry<K,V>(key, value);

        boolean found = false;
        V oldValue = null;
        ListIterator<MapEntry<K,V>> it = bucket.listIterator();        while(it.hasNext()){
            MapEntry<K,V> iPair = it.next();            if(iPair.equals(key)){
                oldValue = iPair.getValue();
                it.set(pair); // Replace old with new
                found = true;                break;
            }
        }        if(!found){
            buckets[index].add(pair);
        }        return oldValue;
    }

    @Override    public V get(Object key){        int index = Math.abs(key.hashCode()) % SIZE;        if(buckets[index] == null) return null;        for(MapEntry<K,V> iPair : buckets[index]){            if(iPair.getKey().equals(key)){                return iPair.getValue();
            }
        }        return null;
    }

    @Override    public Set<Map.Entry<K,V>> entrySet(){
        Set<Map.Entry<K,V>> set = new HashSet<Map.Entry<K, V>>();        for(LinkedList<MapEntry<K,V>> bucket : buckets){            if(bucket == null) continue;            for(MapEntry<K,V> mpair : bucket){                set.add(mpair);
            }
        }        return set;
    }    public static void main(String[] args){
        SimpleHashMap<String, String> m = new SimpleHashMap<String, String>();        for(String s : "to be or not to be is a question".split(" ")){
            m.put(s, s);
            System.out.println(m);
        }
        System.out.println(m);
        System.out.println(m.get("be"));
        System.out.println(m.entrySet());
    }
}
로그인 후 복사

4.5 覆盖hashCode()

  设计`hashCode()`时要考虑的因素:

  • 最重要的因素:无论何时,对同一相对象调用hashCode()都应该生成同样的值

  • 此外,不应该使hashCode()依赖于具有唯一性的对象信息,尤其是使用this的值,这只能产生很糟糕的hashCode()。因为这样做无法生成一个新的键,使之与put()中原始的键值对中的键相同。即应该使用对象内有意义的识别信息。也就是说,它必须基于对象的内容生成散列码。

  • 但是,通过hashCode() equals()必须能够完全确定对象的身份。

  • 因为在生成桶的下标前,hashCode()还需要进一步处理,所以散列码的生成范围并不重要,只要是int即可。

  • 好的hashCode()应该产生分布均匀的散列码。

《Effective Java™ Programming Language Guide (Addison-Wesley, 2001)》为怎样写出一个像样的hashCode()给出了一个基本的指导:

  1. int变量result赋予一个非零值常量,如17

  2. 为对象内每个有意义的域f(即每个可以做equals()操作的域)计算出一个int散列码c

域类型计算
booleanc=(f?0:1)
byte、char、short或intc=(int)f
longc=(int)(f^(f>>>32))
floatc=Float.floatToIntBits(f);
doublelong l = Double.doubleToLongBits(f);
Object,其equals()调用这个域的equals()c=f.hashCode()
数组对每个元素应用上述规则

3. 合并计算散列码:result = 37 * result + c;
4. 返回result。
5. 检查hashCode()最后生成的结果,确保相同的对象有相同的散列码。

5 选择不同接口的实现

5.1 微基准测试的危险(Microbenchmarking dangers)

已证明0.0是包含在Math.random()的输出中的,按照数学术语,即其范围是[0,1)

5.2 HashMap的性能因子

  HashMap中的一些术语:

  • 容量(Capacity):表中的桶位数(The number of buckets in the table)。

  • 初始容量(Initial capacity):表在创建时所拥有的桶位数。HashMapHashSet都具有允许你指定初始容量的构造器。

  • 尺寸(Size):表中当前存储的项数。

  • 负载因子(Loadfactor):尺寸/容量。空表的负载因子是0,而半满表的负载因子是0.5,依此类推。负载轻的表产生冲突的可能性小,因此对于插入和查找都是最理想的(但是会减慢使用迭代器进行遍历的过程)。HashMapHashSet都具有允许你指定负载因子的构造器,表示当负载情况达到该负载的水平时,容器将自动增加其容量(桶位数),实现方式是使容量大致加倍,并重新将现有对象分布到新的桶位集中(这被称为再散列)。

HashMap使用的默认负载因子是0.75(只有当表达到四分之三满时,才进行再散列),这个因子在时间和空间代价之间达到了平衡。更高的负载因子可以降低表所需的空间,但会增加查找代价,这很重要,因为查找是我们在大多数时间里所做的操作(包括get()put())。

6 Collection或Map的同步控制

  Collections类有办法能够自动同步整个容器。其语法与“不可修改的”方法相似:

package net.mrliuli.containers;

import java.util.*;public class Synchronization {    public static void main(String[] args){
        Collection<String> c = Collections.synchronizedCollection(new ArrayList<String>());
        List<String> list = Collections.synchronizedList(new ArrayList<String>());        Set<String> s = Collections.synchronizedSet(new HashSet<String>());        Set<String> ss = Collections.synchronizedSortedSet(new TreeSet<String>());
        Map<String, String> m = Collections.synchronizedMap(new HashMap<String, String>());
        Map<String, String> sm = Collections.synchronizedSortedMap(new TreeMap<String, String>());
    }
}
로그인 후 복사

6.1 快速报错(fail-fast)

  Java容器有一种保护机制能够防止多个进行同时修改同一个容器的内容。Java容器类类库采用快速报错(fail-fast)机制。它会探查容器上的任何除了你的进程所进行的操作以外的所有变化,一旦它发现其他进程修改了容器,就会立刻抛出ConcurrentModificationException异常。这就是“快速报错”的意思——即,不是使用复杂的算法在事后来检查问题。

package net.mrliuli.containers;
import java.util.*;public class FailFast {    public static void main(String[] args){
        Collection<String> c = new ArrayList<>();
        Iterator<String> it = c.iterator();
        c.add("An Object");        try{
            String s = it.next();
        }catch(ConcurrentModificationException e){
            System.out.println(e);
        }
    }
}
로그인 후 복사

相关文章:

Java编程思想学习课时(三)第15章-泛型

Java编程思想学习课时(五)第18章-Java IO系统

위 내용은 자바 프로그래밍 사고 학습 수업(4) 17장 - 컨테이너에 대한 심층 토론의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. 크로스 플레이가 있습니까?
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

자바의 완전수 자바의 완전수 Aug 30, 2024 pm 04:28 PM

Java의 완전수 가이드. 여기서는 정의, Java에서 완전 숫자를 확인하는 방법, 코드 구현 예제에 대해 논의합니다.

자바의 웨카 자바의 웨카 Aug 30, 2024 pm 04:28 PM

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 스미스 번호 Java의 스미스 번호 Aug 30, 2024 pm 04:28 PM

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

Java Spring 인터뷰 질문 Java Spring 인터뷰 질문 Aug 30, 2024 pm 04:29 PM

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Feb 07, 2025 pm 12:09 PM

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 날짜까지의 타임스탬프 Java의 날짜까지의 타임스탬프 Aug 30, 2024 pm 04:28 PM

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.

캡슐의 양을 찾기위한 Java 프로그램 캡슐의 양을 찾기위한 Java 프로그램 Feb 07, 2025 am 11:37 AM

캡슐은 3 차원 기하학적 그림이며, 양쪽 끝에 실린더와 반구로 구성됩니다. 캡슐의 부피는 실린더의 부피와 양쪽 끝에 반구의 부피를 첨가하여 계산할 수 있습니다. 이 튜토리얼은 다른 방법을 사용하여 Java에서 주어진 캡슐의 부피를 계산하는 방법에 대해 논의합니다. 캡슐 볼륨 공식 캡슐 볼륨에 대한 공식은 다음과 같습니다. 캡슐 부피 = 원통형 볼륨 2 반구 볼륨 안에, R : 반구의 반경. H : 실린더의 높이 (반구 제외). 예 1 입력하다 반경 = 5 단위 높이 = 10 단위 산출 볼륨 = 1570.8 입방 단위 설명하다 공식을 사용하여 볼륨 계산 : 부피 = π × r2 × h (4

Spring Tool Suite에서 첫 번째 Spring Boot 응용 프로그램을 실행하는 방법은 무엇입니까? Spring Tool Suite에서 첫 번째 Spring Boot 응용 프로그램을 실행하는 방법은 무엇입니까? Feb 07, 2025 pm 12:11 PM

Spring Boot는 강력하고 확장 가능하며 생산 가능한 Java 응용 프로그램의 생성을 단순화하여 Java 개발에 혁명을 일으킨다. Spring Ecosystem에 내재 된 "구성에 대한 협약"접근 방식은 수동 설정, Allo를 최소화합니다.

See all articles