黑马程序员-Java基础总结08——集合与集合框架(…

时间:2022-10-20 00:43:11

集合与集合框架

-------android培训java培训、期待与您交流!----------

内容:  String、字符串缓冲区(StringBuffer、StringBuilder)、基本数据类型包装类、
       集合Collection(列表List、集Set)与映射Map(双列集合)、泛型

1String     字符串,即多个字符组成的一个序列。

String字符串是一个特殊的对象不属于数据类型(八种基本、三种引用)。

 

特点: 字符串是常量;它们一旦被创建、初始化就不可以被改变

             (重新赋值,改变的是String变量的引用地址值。)

因为String对象是不可变的,存在于字符串池(常量池之一),所以可以共享

 

初始化格式(常见前两种)

String s1 =abcd; //s1是一个类类型变量,“abc是一个对象。

String s2 = new String(abc);   

Strings3 = new String(ab+cd);

注意: s1s2s3的区别: 区别在于它们在内存中创建的对象数不同;

      s1:内存中创建1对象:“abcd”;    

s2 :内存中创建2对象:new关键字、“abcd”;

s3 :内存中创建4对象:”ab””cd”,以及两者组合”abcd”与其new的对象。

 

解析:        String s2 = new String(“abc”);             详见StringTest.java

abc     字符串池创建并返回了对象的引用

new关键字 new是在内存当中新建一个对象,并将内存地址赋给了s2

   属于两个对象,一个是字符串池的引用,另一个是内存地址的引用

区别:一个是字符串池引用,一个是内存地址。速度*问内存较快,但它是在内存中创建了对象。

注意: 对象默认值为nullString的默认值也为null,因为它是个特殊的对象

             String s =“”;new String(“”);表示的该字符串为空的对象不同于null

 

String类中方法:  (其他详见API中的java.lang.String类)

boolean equals(ObjectanObj) :将此字符串与指定的对象比较(复写Object方法);

char    charAt(int index);  : 返回字符串指定角标位上的字符;

int     length( );           :返回此字符串的长度(该字符串的字符个数);

char[ ] toCharArray();       :返回包含该字符串所有字符的字符数组;

int     indexOf(String str);  :返回指定子字符串在此字符串中第一次出现处的索引;

boolean  endsWith(String str);:测试此字符串是否以指定的后缀结束;

String[] split(String reg);   :根据给定正则表达式的匹配拆分此字符串;

String  substring(int index); :返回从指定角标位起的子字符串;

String  valueOf(char[] arr);  :返回 char数组参数的字符串表示形式;

  

2.1StringBuffer(字符串缓冲区/字符序列) 

特点:               线程安全(支持同步)的可变字符序列(容器)。

1、是可变长度(数据)容器

2、可以直接操作多个数据类型

3StringBuffer可以对容器中字符串内容进行增删改查(CURD

Create创建、Update修改、Read查找、Delete删除】

3、最终会通过toString方法变成字符串;

4、很多方法与String相同,而字符串的组成原理就是通过该类实现的;

StringBuffer类中方法:    (其他详见java.lang.StringBuffer类)

.append(Object obj) : Object 参数追加StringBuffer末尾

.insert(intoffset,Objectobj): Object参数插入到此字符序列指定位置中;

.toString()     :StringBuffer中数据以String形式返回;

.lastIndexOf(String str):返回最右边出现的指定子字符串在此字符串中的索引。

 

2.2StringBuilder(也属于字符串缓冲区)

特点:               不支持同步的可变字符序列(容器);

1、简易替换StringBuffer的字符串缓冲区;

2、StringBuffer具有相同的操作功能(方法)但不支持多线程(同步)

3、因为不需要执行同步,所以在多数实现中比StringBuffer速度快;

4、如果可行,建议优先采用此方法(多用于字符串缓冲区被单线程使用,很普遍);

5StringBuilder类方法基本上与StringBuffer相同(详见java.lang.StringBuilder类)。

 

2.3字符串与字符串容器:

String       :字符串,属于常量,一旦初始化就不可以被改变。

StringBuffer :线程安全的可变字符序列;(同步、适用于多线程)

字符串缓冲区,可对其中字符序列进行添加、删除等)

StringBuilder: 简易替换StringBuffer可变字符序列,但不支持同步

(推荐优先使用StringBuilder,因为不执行同步,在单线程中执行速度快,且拥有相同功能)

 

3.1基本数据类型对象包装类: 

Java中一切皆对象,但是基本数据类型却不能算是对象,也就无法通过类/方法来操作基本数据类型值。因此为了方便操作基本数据类型值,将其封装成对象,在对象中定义更多的功能方法操作该数据,而用于描述该对象的类就称为基本数据类型对象包装类

   每种基本数据类型都有与之对应的包装类。

基本数据类型  基本数据类型包装类
byte             Byte
short            Short
int              Integer(
特殊,名称不同)   

long             Long
float            Float
double           Double
char             Character(
特殊,名称不同)
boolean          Boolean

PS: 实际上,Java中还存在另外一种基本类型void,它也有对应的包装类java.lang.Void不过我们无法直接对其进行操作。

 

最常用的作用: 用于基本数据类型与字符串之间的转换;

1、基本数据类型(包装类)转成字符串:

    基本数据类型包装类+"" ; (字符串为空的双引号)

    基本数据类型包装类.toString(基本数据类型值);

   如:Integer.toString(34);//34整数变成"34";

2、字符串转成基本数据类型:

例如: Integer类中的方法:            

int 
parseInt
(String s)  :将字符串参数作为有符号的十进制整数进行解析;

int intValue()           :int 类型返回该Integer 的值。

示例1:    格式:xxx a = Xxx.parseXxx(String);

   int a = Integer.parseInt("123");  //转换成int类型数据。

   double b = Double.parseDouble("12.23");

示例2:

   Integer i = new Integer("123");

   int num = i.intValue();

(文件等中基本上都是字符(或字节),应用:将字符串转换成基本数据类型参与运算等)

 

基本数据类型包装类可通过方法来转换数值的进制(进制转换):

A、十进制转成其他进制: 

   toBinaryString();     :将十进制数转换成二进制

   toOctalString();      :将十进制数转换成八进制

   toHexString();     :将十进制数转换成十六进制

B、其他进制转成十进制:

   parseInt(Stringstrint radix);  //radix为进制str该进制数字符串形式;

: 如果radix2,则str为二进制的数,将提取str中的二进制数并转换成十进制数;

注意:str不属于该进制的数会抛出异常。

 

3.2JDK1.5新特性———自动装箱、自动拆箱:

随着基本数据类型包装类的出现,Java提供自动装箱与拆箱功能;

示例:

Integer x = 4;   //自动装箱,“4”是个对象,相当于new Integer(4);

x = x + 2;       //等同于: x = valueOf( x.intValue() +2);

//x+2: x进行自动拆箱,变成int类型,和2进行加法运算,再将两者和进行装箱赋给x

 

注意:  创建字节byte范围(-128+127内的相等的基本数据类型包装类数值在内存中指向同一片内存空间

:    Integer a = 127; (即Integer a = new Integer(127);

Integer b = 127;   判断a == b,结果为true

因为ab指向了同一个Integer对象;

因为当数组在byte范围内,对于新特性,如果该数值已经存在,则不会再开辟新的空间(享元模式)

(注意:如果ab数值大于127,则两者不相等,因为new新建了Integer的对象,所以两者地址值不同

 

4、集合类:

A、集合类概述:

Java中对事物的体现都是以对象的形式(即一切皆对象),所以在Java中对数据的操作其实就是对对象的操作或存储,而集合就是存储对象的一种方式。

B、数组和集合的区别:

数组可存储基本数据类型与对象,但数组长度固定(初始化时指定)

集合只能存储对象,集合长度是可变,集合可以存储不同类型的对象。

 

集合框架图:

黑马程序员-Java基础总结08——集合与集合框架(…
Collection(集合)

   |--List:元素是有序的,元素可重复。因为该集合体系有索引。

      |ArrayList:底层使用的是数组数据结构

特点:查询速度很快。但是增删稍慢。线程不同步。

      |LinkedList:底层使用的是链表数据结构

特点:增删速度很快,查询稍慢。线程不同步。

      |Vector:底层是数组数据结构。线程同步,效率低;被ArrayList替代。

   |Set:无序,元素不可重复(元素唯一性)

      |HashSet:数据结构是哈希表。线程是非同步的。

             保证元素唯一性的原理:判断元素的hashCode是否相同。

             如果相同,还会继续判断元素的equals方法,是否为true

      |TreeSet:底层是二叉树数据结构。可以Set集合中的元素进行排序

             保证元素唯一性的依据:compareTo方法return 0。(大于为正,小于为负)

 

Collection集合方法详见java.util包中的类。

1、添加: add(e);addAll(collection); 添加单个元素或其他集合中全部元素到该集合中;

2、删除: remove(e);removeAll(collection);删除指定元素或与某集合(交集部分)的元素;

      清空: .clear();: 清空集合中所有元素】

3、判断: contains(e);  :判断集合是否存在元素‘e’;

isEmpty( );  :判断集合是否为空;

4、获取: iterator();: 获取迭代器,用于取出集合中的元素。

//格式:Iteratorit = al.iterator()

           size();             :获取个数,即集合长度【是方法(带括号),不同于数组.length】。

5、获取交集: retainAll(); :  al1.retainAll(al2); al1中只会保留和al2中相同的元素。

6,集合变数组: toArray();      :将指定集合转变为数组;

注意:  1add方法的参数类型是Object。以便于接收任意类型对象;

2、集合中存储的都是对象的引用(地址)

 

Collection各子类特点简要】

5List(列表):可存放重复元素,元素存取是有序的(带角标)。

   ArrayList:线程不安全,查询速度快。

   LinkedList:链表结构,增删速度快。

   Vector:线程安全,但速度慢,已被ArrayList替代。

 

取出List集合中元素的方式:

   get(int index):通过脚标获取元素。

遍历集合,获取集合中全部元素的方法:Iterator迭代器(仅删除、获取功能)

Collection共性方法:  .iterator(); 通过迭代方法获取迭代器对象。

示例:  Collection cl = newArrayList();

Iterator it =cl.iterator();

while(it.hasNext()){     //判断集合中是否还有元素可迭代;

   System.out.println(it.next());   //返回迭代到的元素。

}

节省内存书写方式:

for(Iterator it =l.iterator();it.hasNext(); ){

       System.out.println(it.next());

} //for循环中创建Iterator对象,而循环结束后jvm会擦除该对象在内存中占用的空间。

 

PS: List列表由于拥有脚标,可使用特有的列表迭代器(ListIterator)

ListIterator中提供方法可对List列表进行遍历同时对元素增删改

 

6Set()不可以存放重复元素(元素唯一性),元素存取是无序的。

HashSet:线程不安全,存取速度快。

   通过equals方法和hashCode方法来保证元素的唯一性

TreeSet:线程不安全,可以对Set集合中的元素进行排序

   通过compareTo或者compare方法中的来保证元素的唯一性。元素是以二叉树的形式存放的。

 

TreeSet排序两种方式:

1、让元素自身具备比较性:   元素需要实现Comparable接口覆盖compareTo方法

这种方式也成为元素的自然顺序,或者叫做默认顺序。

 

2、给存储元素的容器TreeSet等添加比较器;

用于: 当元素自身不具备比较性时,或者具备的比较性不是所需要的。

要求创建实现Comparator接口覆盖compare方法的比较器()

注意: 两者同时存在时,优先使用比较器排序方式。

 

Collection集合与子类的使用与特点简要: (个人观点)

   存储对象需要保留存储先后顺序时可以使用List列表(查询多使用ArrayList、增删多使用LinkedList)

   而如果需要对存储对象进行排序则使用Set集合(哈希表排序使用HashSet,自然排序或自定义排序则用TreeSet)

   但是如果要对集合中对象进行多次不同排序方式,建议使用List列表配合Collections工具类的排序方法: Collection.sort(List<T>list,Comparator<? super T>c)

 

7Map映射:

Map集合:该集合存储键值对。一对一对往里存。而且要保证键的唯一性

 

I、Map

   |Hashtable:底层是哈希表数据结构,不可以存入nullnull。该集合是线程同步的jdk1.0,效率低,被HashMap替代。   

   |HashMap:底层是哈希表数据结构,允许使用null 值和 null,线程不同步的。开始于JDK1.2,效率高。  (根据哈希表排序

   |TreeMap:底层是二叉树数据结构,用于给Map集合中的键进行排序, 线程不同步。

             (根据自然顺序(字典顺序)排序)

【注意: Set类是基于Map实现的,由Map的键值(只保留唯一的键)转变而成。

所以他们具有共性: 

1HashMap的键KeyHashSet元素都是通过hashCodeequals来保证/元素的唯一性

2TreeMap的键TreeSet元素都是通过compareTocompare方法来保证元素唯一性和实现集、映射容器的排序功能;

 

MapCollection的区别

1MapCollection在集合框架中属并列存在

2Map属于双列集合(键=值);而Collection(ListSet)单列集合

3Map存储元素使用put(键,值)方法,Collection使用add()方法;

4Map集合中要保证唯一性,对应Set集中元素(唯一性)

5Map集合没有直接取出元素的方法,需要先转成Set集合,再通过迭代获取元素

 

II、接口Map<K,V>的共性方法:

  映射集合基本格式:     Map<?
extends K, ? extends
V>

1、添加:    put(K key, V value)       :添加键值对

putAll(Map<? extends K,? extendsV> m)  :复制某映射中所有映射关系到此映射;

2、删除:    clear()         :移除映射中所有的映射关系(即清空);

remove(Object key)   :根据键,删除该键值对(映射)

3、判断:   containsValue(Objectvalue)  : 判断是否有一个或多个键对应该值

   containsKey(Objectkey)  : 判断是否有包含此键的映射关系?     

isEmpty()              :判断此映射是否为空?

4、获取:   get(Object key): 返回指定键所映射的值;(没有则返回null值);

   size()            :返回此映射中的键-映射关系数

Collection<V>      values()    :返回map映射中所有值Collection集合;

Set<K>         keySet()   : 返回此映射中所有键Set集合;

Set<Map.Entry<K,V>>  entrySet()    :返回此映射中所有映射关系Set集合;

 

嵌套类:

(staticinterface)Map.Entry<K,V>  : 映射项(键-值对);

注解: Entry是一个接口,它是Map接口中的一个内部接口

      Entry代表Map集合中的映射关系直接访问Map中的键-,所以定义在内部

 

Map子类的特有方法:

1HashMapHashSet相同,没有特有方法,同Map接口方法一致。

2TreeMapTreeSet相同,因为自动排序功能,具有以下特有方法:

 

TreeMap特有方法:      (TreeSet的底层原理,基本相同,仅使用方法代码差异)

1、获取(比较性质):

E firstKey()         返回此映射中当前第一个(最低)

E  lastKey()      返回映射中当前最后一个(最高)

E  ceilingKey(K key)   返回大于等于给定键的最小键;如果不存在这样的键,则返回null

E  floorKey(K key)      返回小于等于给定键的最大键;如果不存在该键,则返回null

Map.Entry<K,V>  firstEntry()返回此映射中最小键关联的键值映射,映射为空返回null

lastEntry() 返回最大键关联的键值映射关系(否则返回null)

higherEntry(K key) 返回严格大于给定键的最小-映射关系(否则返回null)

lowerEntry(K key)  返回严格小于给定键的最大-映射关系(否则返回null)

 

2、删除返回:

Map.Entry<K,V>  pollFirstEntry() 删除并返回最小键关联的键-映射(否则返回null)

  pollLastEntry() 删除并返回最大键关联的键-映射(否则返回null)

提取/转换 :

SortedMap<K,V> subMap(fromKey,toKey);   tailMap(fromKey); headMap(toKey);

NavigableMap<K,V> 同上,但需添加boolean判断是否包含fromKeytoKey

descendingMap() 返回包含此映射中所有映射关系逆序视图。

NavigableSet<K>  navigableKeySet()  返回包含此映射中所有键NavigableSet 视图。

descendingKeySet() 返回包含此映射中所有键逆序NavigableSet视图。

3获取比较器:

Comparator<? SuperK>      comparator()
     
返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回null

【更多详见APIjava.util.TreeMap类】

 

4、注意: 调用方法代码多有类似,可按规律记忆:

返回存储对象 功能简化代码 + 操作的对象  :  “first +Key”

例如: E firstKey();  Map.Entry<K,V> firstEntry();  等。

 

III、Map集合的取出方式:

Map集合不能直接取出键值对,只能通过转换成Set集合,通过Set迭代器获取

 

两种间接取出方式     Map<T> map = newMap<T>();

   1Set<k>    keySet();  : 提取map中所有键存储到Set集合;

   调用Set集合的迭代器方法获取键,调用Map集合方法通过键获取对应的值

   代码格式: Set<T> keyset =map.keySet();

   Iterator<T> it =keyset.iterator();

 

   2Set<Map.Entry<k,v>>   entrySet();

map集合中的映射关系存入到Set集合中,存放为数据类型Map.Entry<k,v>

再调用Set集合迭代器获取映射关系,通过Map.Entry<k,v>方法获取键、值。

   代码格式:Set<Map.Entry<k,v>>entryset = map.entrySet();

             (getKey()getValue())

理解:

接口Map.Entry  :其中Entry也是一个接口,它是Map接口中的一个内部接口

      Entry代表Map集合中的映射关系直接访问Map中的键-,所以定义在内部。

源码,参考理解:

interface Map{

public static interface Entry{

   public abstract Object getKey();

   public abstract Object getValue();

}} 

//因此方法二可解释为往Set集合中存储的是实现Map.Entry的子类对象。

 

IV、扩展理解:      Map<Key,Value>

Map映射的存储格式是:Map<? extends
K, ? extends
V>

   即存储的KeyValue既可以是String、类对象,也可以是集合容器Collection等。

 

例如: Map<String,List<Student>>Map<Student,Set<Person> >等。

扩展理解、使用:

虽然Map多用于配置文件的属性键值对但也能用来实现一对多(集合)等。

(例如学校属性: 学校名——学校, 学校中:不同班级——相同学号的不同学生对象等)

 

———————————————泛型————————————————

八、泛型:  用于解决安全问题,是一个类型安全机制

(它使程序运行时可能出现的问题,提前在编译时出现,在程序中添加限制(泛型)

例如: List<T>li = new ArrayList<T>();

   通过定义<T>中的数据类型,可避免添加了不同数据类型,在运行时出现异常。


原因:  在迭代List时处理的是Student类数据(进行强转等操作Student特有内容),而List存放错误存放了Demo类型,则会在程序运行时出现类型转换异常,为避免这种情况引进了泛型,即规定了在添加数据时只能添加指定数据类型及其子类。)

 

 

2泛型通配符:

API文档中可看到以下符号——泛型通配符,解析帮助理解。】

  ? :占位符,不明确具体类型;

(通常用于定义方法参数,表示不明确接收集合等的元素的具体类型,将参数集合的数据类型定义为“?”,即可接收任意数据类型的集合,但也就不能调用与具体数据类型相关的方法)

 

 TE: 具体数据类型(等待指定数据类型)例如:Collection<T>等。

【在向方法等传递集合时指定数据类型,可在方法中调用涉及具体数据类型的方法,但建议在方法多处使用到相关数据类型时使用,例:返回值类型、接收参数、调用具体数据类型的方法

 ? super T : 泛型下限定,表示允许传入指定数据类型及其父类;

: 比较器: void Comparator<? super E> :即可传入要比较的对象类型或其父类;

例如: Student继承Person,要比较Student对象,则可传入PersonStudent

   【注意:前提是比较器使用的成员属性两者都有,或是继承自Person

 

 ? extends T  :泛型上限定,表示允许传入指定数据类型及其子类;

   多用于集合容器等,Collection<? extendsT> : 即可存储T 类型及其子类。

 

注意: 出现以上通配符的方法表示:调用方法时要传入具体数据类型

实际应用时在创建类/方法(自定义比较器、集合等)时才可添加/使用这些通配符,即表示调用该方法时也是要指定方法操作的数据类型。

 

3、泛型类、泛型方法:       (下面有代码详解)

A、泛型类的泛型字符 与泛型方法的字符相同,那么它们指向同一个泛型;

B、泛型方法间的泛型字符是相互独立,即使相同,也指向不同泛型(数据类型)

C静态泛型方法不能与泛型类的泛型字符指向同一个泛型

 

创建泛型类、泛型方法的格式:     【自己的理解】

class Student<T>{

    public       voidshow1(T t){.........}  //调用类上的泛型T

    public        T  show2(Tt){.........}   //调用类上的泛型T  

    public static<T> T  show3(T t){.........}//调用静态方法上的泛型T

    public    <T> T show4(T t){.........}  //调用方法上的泛型T

}

在方法的修饰符之后、返回值之前的添加<T>表示在该方法新建自己的泛型T

【该泛型T仅在该方法有效即使与泛型类上的同名也是调用本方法上的。】

 

解释:

1泛型类上定义<T>,表示本类中同名泛型字符方法默认调用此泛型T

   【所以对show1show2方法有效】

2、如果泛型方法上自己定义了<T>,则调用自己的泛型相对泛型类独立

   【所以类的泛型限定对show3show4无效,它们调用自身方法上的泛型T

3静态泛型方法必须要自行定义<T>,因为静态泛型方法不能访问类(非静态)上的泛型

4、非泛型类(或与泛型类泛型字符不同)泛型方法也必须要自定义泛型(<T>),如果有使用到泛型的话。