集合与集合框架
-------android培训、java培训、期待与您交流!----------
内容: String、字符串缓冲区(StringBuffer、StringBuilder)、基本数据类型包装类、
集合Collection(列表List、集Set)与映射Map(双列集合)、泛型
1、String类 : 字符串,即多个字符组成的一个序列。
String字符串是一个特殊的对象,不属于数据类型(八种基本、三种引用)。
特点: 字符串是常量;它们一旦被创建、初始化就不可以被改变。
(重新赋值,改变的是String变量的引用地址值。)
因为String 对象是不可变的,存在于字符串池(常量池之一),所以可以共享。
初始化格式(常见前两种):
String s1 =“abcd”; (//s1 是一个类类型变量,“abc”是一个对象。)
String s2 = new String(“abc”);
Strings3 = new String(“ab”+“cd”);
注意: s1、s2、s3的区别: 区别在于它们在内存中创建的对象数不同;
s1 :内存中创建1个对象:“abcd”;
s2 :内存中创建2个对象:new关键字、“abcd”;
s3 :内存中创建4个对象:”ab”、”cd”,以及两者组合”abcd”与其new的对象。
解析: String s2 = new String(“abc”); (详见StringTest.java)
“abc” : 在字符串池创建并返回了对象的引用。
new关键字 : new是在内存当中新建一个对象,并将内存地址赋给了s2。
属于两个对象,一个是字符串池的引用,另一个是内存地址的引用。
区别:一个是字符串池引用,一个是内存地址。速度上访问内存较快,但它是在内存中创建了对象。
注意: 对象默认值为null,String的默认值也为null,因为它是个特殊的对象。
String s =“”; 或new String(“”); 表示的该字符串为空的对象,不同于null。
String类中方法: (其他详见API中的java.lang.String类)
boolean equals(Object anObj
) :将此字符串与指定的对象比较(复写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.1、StringBuffer(字符串缓冲区/ 字符序列)
特点: 是线程安全(支持同步)的可变字符序列(容器)。
1、是可变长度的(数据)容器;
2、可以直接操作多个数据类型;
3、StringBuffer可以对容器中字符串内容进行增删改查(CURD);
【Create创建、Update修改、Read查找、Delete删除】
3、最终会通过toString方法变成字符串;
4、很多方法与String相同,而字符串的组成原理就是通过该类实现的;
StringBuffer类中方法: (其他详见java.lang.StringBuffer类)
.append(Object obj) : 将Object 参数追加到StringBuffer末尾;
.insert(intoffset,
Object obj)
: 将 Object
参数插入到此字符序列指定位置中;
.toString() :将StringBuffer中数据以String形式返回;
.lastIndexOf(String str): 返回最右边出现的指定子字符串在此字符串中的索引。
2.2、StringBuilder(也属于字符串缓冲区)
特点: 是不支持同步的可变字符序列(容器);
1、简易替换StringBuffer的字符串缓冲区;
2、与StringBuffer具有相同的操作功能(方法),但不支持多线程(同步);
3、因为不需要执行同步,所以在多数实现中比StringBuffer速度快;
4、如果可行,建议优先采用此方法(多用于字符串缓冲区被单线程使用,很普遍);
5、StringBuilder类方法基本上与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(Stringstr,int radix); //radix为进制,str为该进制数的字符串形式;
例: 如果radix为2,则str为二进制的数,将提取str中的二进制数并转换成十进制数;
注意: 当str不属于该进制的数会抛出异常。
3.2、JDK1.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;
因为a和b指向了同一个Integer对象;
因为当数组在byte范围内,对于新特性,如果该数值已经存在,则不会再开辟新的空间(享元模式)。
(注意:如果a、b数值大于127,则两者不相等,因为new新建了Integer的对象,所以两者地址值不同)
4、 集合类:
A、集合类概述:
Java中对事物的体现都是以对象的形式(即一切皆对象),所以在Java中对数据的操作其实就是对对象的操作或存储,而集合就是存储对象的一种方式。
B、数组和集合的区别:
数组可存储基本数据类型与对象,但数组长度固定(初始化时指定);
集合只能存储对象,集合长度是可变,集合可以存储不同类型的对象。
集合框架图:
|--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(); : 将指定集合转变为数组;
注意: 1、add方法的参数类型是Object。以便于接收任意类型对象;
2、集合中存储的都是对象的引用(地址)。
【Collection各子类特点简要】
5、List(列表):可存放重复元素,元素存取是有序的(带角标)。
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列表进行遍历同时对元素增删改;
6、Set(集):不可以存放重复元素(元素唯一性),元素存取是无序的。
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
7、Map映射:
Map集合:该集合存储键值对。一对一对往里存。而且要保证键的唯一性。
I、Map
|—Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0,效率低,被HashMap替代。
|—HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,线程不同步的。开始于JDK1.2,效率高。 (根据哈希表排序)
|—TreeMap:底层是二叉树数据结构,用于给Map集合中的键进行排序, 线程不同步。
(根据自然顺序(字典顺序)排序)
【注意: Set类是基于Map实现的,由Map的键值(只保留唯一的键)转变而成。】
所以他们具有共性:
1、HashMap的键Key、HashSet元素都是通过hashCode、equals来保证键/元素的唯一性;
2、TreeMap的键、TreeSet元素都是通过compareTo或compare方法来保证元素唯一性和实现集、映射容器的排序功能;
Map与Collection的区别:
1、Map与Collection在集合框架中属并列存在
2、Map属于双列集合(键=值);而Collection(List和Set)是单列集合。
3、Map存储元素使用put(键,值)方法,Collection使用add()方法;
4、Map集合中键要保证唯一性,对应Set集中元素(唯一性);
5、Map集合没有直接取出元素的方法,需要先转成Set集合,再通过迭代获取元素。
II、接口Map
映射集合基本格式: Map extends K, ? extends V>
1、添加: put(K key, V value) : 添加键值对;
putAll(Map extends K,? extendsV> m) : 复制某映射中所有映射关系到此映射;
2、删除: clear() : 移除映射中所有的映射关系(即清空);
remove(Object key) : 根据键,删除该键值对(映射)。
3、判断: containsValue(Object value) : 判断是否有一个或多个键对应该值?
containsKey(Objectkey) : 判断是否有包含此键的映射关系?
isEmpty() : 判断此映射是否为空?
4、获取: get(Object key) : 返回指定键所映射的值;(没有则返回null值);
size() : 返回此映射中的键-值映射关系数;
Collection
Set
Set
嵌套类:
(staticinterface) Map.Entry
注解: Entry是一个接口,它是Map接口中的一个内部接口;
Entry代表Map集合中的映射关系,直接访问Map中的键-值,所以定义在内部。
Map子类的特有方法:
1、HashMap同HashSet相同,没有特有方法,同Map接口方法一致。
2、TreeMap同TreeSet相同,因为自动排序功能,具有以下特有方法:
TreeMap特有方法: (是TreeSet的底层原理,基本相同,仅使用方法代码差异)
1、获取(比较性质):
E firstKey() 返回此映射中当前第一个(最低)键。
E lastKey() 返回映射中当前最后一个(最高)键。
E ceilingKey(K key) 返回大于等于给定键的最小键;如果不存在这样的键,则返回 null。
E floorKey(K key) 返回小于等于给定键的最大键;如果不存在该键,则返回 null。
Map.Entry
lastEntry() 返回最大键关联的键值映射关系(否则返回null)。
higherEntry(K key) 返回严格大于给定键的最小键-值映射关系(否则返回null)。
lowerEntry(K key) 返回严格小于给定键的最大键-值映射关系(否则返回null)。
2、删除返回 :
Map.Entry
pollLastEntry() 删除并返回最大键关联的键-值映射(否则返回 null)。
提取/转换 :
SortedMap
NavigableMap
descendingMap() 返回包含此映射中所有映射关系的逆序视图。
NavigableSet
descendingKeySet() 返回包含此映射中所有键的逆序 NavigableSet视图。
3、获取比较器:
Comparator SuperK> comparator()
返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回null。
【更多详见API中java.util.TreeMap类】
4、注意: 调用方法代码多有类似,可按规律记忆 :
返回存储对象 “功能简化代码 + 操作的对象” : “first +Key”;
例如: E firstKey(); Map.Entry
III、Map集合的取出方式:
Map集合不能直接取出键值对,只能通过转换成Set集合,通过Set迭代器获取。
两种间接取出方式: Map
1、Set
调用Set集合的迭代器方法获取键,调用Map集合方法通过键获取对应的值。
代码格式: Set
Iterator
2、Set
将map集合中的映射关系存入到Set集合中,存放为数据类型Map.Entry
再调用Set集合迭代器获取映射关系,通过Map.Entry
代码格式:Set
(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
Map映射的存储格式是: Map extends K, ? extends V>
;
即存储的Key、Value既可以是String、类对象,也可以是集合容器Collection等。
例如: Map
扩展理解、使用:
虽然Map多用于配置文件的属性键值对等,但也能用来实现一对多(集合)等。
(例如学校属性: 学校名——学校, 学校中:不同班级——相同学号的不同学生对象等)
———————————————泛型————————————————
八、泛型: 用于解决安全问题,是一个类型安全机制。
(它使程序运行时可能出现的问题,提前在编译时出现,在程序中添加限制(泛型))
例如: List
通过定义
原因: 在迭代List时处理的是Student类数据(进行强转等操作Student特有内容),而List存放错误存放了Demo类型,则会在程序运行时出现类型转换异常,为避免这种情况引进了泛型,即规定了在添加数据时只能添加指定数据类型及其子类。)
2、泛型通配符:
【在API文档中可看到以下符号——泛型通配符,解析帮助理解。】
? :占位符,不明确具体类型;
(通常用于定义方法参数,表示不明确接收集合等的元素的具体类型,将参数集合的数据类型定义为“?”,即可接收任意数据类型的集合,但也就不能调用与具体数据类型相关的方法。)
T、E等 : 具体数据类型(等待指定数据类型);例如:Collection
【在向方法等传递集合时指定数据类型,可在方法中调用涉及具体数据类型的方法,但建议在方法多处使用到相关数据类型时使用,例: 返回值类型、接收参数、调用具体数据类型的方法】
? super T : 泛型下限定,表示允许传入指定数据类型及其父类;
例: 比较器: void Comparator super E> :即可传入要比较的对象类型或其父类;
例如: Student继承Person,要比较Student对象,则可传入Person或Student;
【注意:前提是比较器使用的成员属性两者都有,或是继承自Person 】
? extends T : 泛型上限定,表示允许传入指定数据类型及其子类;
多用于集合容器等,Collection extendsT> : 即可存储 T 类型及其子类。
注意: 出现以上通配符的方法表示: 调用方法时要传入具体数据类型;
而实际应用时在创建类/方法(自定义比较器、集合等)时才可添加/使用这些通配符,即表示调用该方法时也是要指定方法操作的数据类型。
3、泛型类、泛型方法: (下面有代码详解)
A、泛型类的泛型字符 与泛型方法的字符相同,那么它们指向同一个泛型;
B、泛型方法间的泛型字符是相互独立,即使相同,也指向不同泛型(数据类型);
C、静态泛型方法不能与泛型类的泛型字符指向同一个泛型。
创建泛型类、泛型方法的格式: 【自己的理解】
class Student
public voidshow1(T t){.........} //调用类上的泛型T;
public T show2(Tt){.........} //调用类上的泛型T;
public static
public
}
在方法的修饰符之后、返回值之前的添加
【该泛型T 仅在该方法有效,即使与泛型类上的同名也是调用本方法上的。】
解释:
1、泛型类上定义
【所以对show1、show2方法有效】
2、如果泛型方法上自己定义了
【所以类的泛型限定对show3、show4无效,它们调用自身方法上的泛型T】
3、静态泛型方法必须要自行定义
4、非泛型类(或与泛型类泛型字符不同)的泛型方法也必须要自定义泛型(