常用类库
泛型
概述
泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
使用
泛型类
定义一个泛型类:
public class ClassName<T>{
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
泛型接口
public interface IntercaceName<T>{
T getData();
}
实现接口时,可以选择指定泛型类型,也可以选择不指定, 如下:
指定类型:
public class Interface1 implements IntercaceName<String> {
private String text;
@Override
public String getData() {
return text;
}
}
不指定类型:
public class Interface1<T> implements IntercaceName<T> {
private T data;
@Override
public T getData() {
return data;
}
}
泛型方法
private static <T> T 方法名(T a, T b) {}
泛型限制类型
1. 在使用泛型时, 可以指定泛型的限定区域 ,
- 例如: 必须是某某类的子类或 某某接口的实现类,格式:
<T extends 类或接口1 & 接口2>
泛型中的通配符 “ ? ”
类型通配符是使用?代替方法具体的类型实参。
1 <? extends Parent> 指定了泛型类型的上届
2 <? super Child> 指定了泛型类型的下届
3 <?> 指定了没有限制的泛型类型
?可以当作object来使用,但是用起来有区别。
作用
- 提高代码复用率
- 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
注意
- 在编译之后程序会采取去泛型化的措施。
- 也就是说Java中的泛型,只在编译阶段有效。
- 在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加
- 类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
Object是所有类的父类
Arrays
- 该类包含用于操作数组的各种方法(例如排序和搜索)。
- 如果指定的数组引用为null,则此类中的方法都抛出NullPointerException
arrays的常用的方法
- toString(Object [] a) 返回指定数组内容的字符串 表现形试
- sort(Object[] a) 将指定的数组按升序排序
- sort(Object[] a, int formIndex, int toIndex) 按升序对指定数组进行排序
- mismatch(Object[] a , Object[] b) 查找并返回两个Object数组之间第一个不匹配的索引,找不到的话返回 -1 .
- copyOfRange(T[] orginal, int from , int to) 将指定范围的数组复制到新数组中
- copyOf(T[] array ,int length) 将数组array扩容到length长度
Math
- 类Math包含用于执行基本数字运算的方法, 例如基本指数,对数,平方根和三角函数
常用方法
- abs(double a) 返回double值的绝对值
- max(int a, int b) 返回int值中较大的那个
- min (int a, int b) 返回int值中较大的那个
Date
- Date类表示特定的时刻,精度为毫秒
- Date类还有两个附加功能。它允许将日期解释为年,月,日,小时,分钟和秒值。它还允许格式化和解析日期字符串
获取当前时间 Date date = new Date();
getTime 获取当前的毫秒数
DateFormat
- DateFormat是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化和分析日期或时间
- DateFormat可帮助您格式化和解析任何区域设置的日期。
/**
y : 年
M : 月
d : 日
H : 时
m : 分
s : 秒
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss")
String text = format.format(new Date())
// 以年月日的形式输出当前时间
String
- String类表示字符串
- 在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
- String 是被 final 修饰的,他的长度是不可变的,就算调用 String 的 concat 方法,那也是把字符串拼接起来并重新创建一个对象
创建字符串有两种方法
直接赋值
String str = "Ruboob";
用构造函数创建字符串
String str2 = new String("Ruboob");
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上:
String s1 = "Runoob"; // String 直接创建
String s2 = "Runoob"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Runoob"); // String 对象创建
String s5 = new String("Runoob"); // String 对象创建
注意:
String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了
如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。
字符串长度
String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数
public class StringDemo {
public static void main(String args[]) {
String site = "www.runoob.com";
int len = site.length();
System.out.println( "菜鸟教程网址长度 : " + len );
}
} // 输出 菜鸟教程网址长度 : 14
连接字符串
String 类提供了连接两个字符串的方法:
//返回 string2 连接 string1 的新字符串。也可以对字符串常量使用 concat() 方法
string1.concat(string2);
//更常用的是使用'+'操作符来连接字符串,如:
"Hello," + " runoob" + "!"
String的其他方法
StringBuffer 和 StringBuilder 类
- 当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
- 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象
注意:
StringBuilder 和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
StringBuffer方法
集合
1、类集设置的目的
普通的对象数组的最大问题在于数组中的元素个数是固定的,不能动态的扩充大小,所以最 早的时候可以通过链表实现一个动态对象数组。但是这样做毕竟太复杂了,所以在 Java 中为了方便用户操作各个数据结构, 所以引入了类集的概念,有时候就可以把类集称为 java 对数据结构的实现
类集中最大的几个操作接口:Collection、Map、Iterator,这三个接口为以后要使用的最重点的接口
- Collection: 主要存放单个数据(单指集合)
- Map : 主要存放两个数据—键值对 key–value 的形式(双指集合)
- Interator:迭代器,获取数据结构数据的最 优方式(输出)
类集是java最数据结构成熟的体现,里面封装所有数据结构类型,直接调用接口即可使用
集合的概述
集合:集合是java中提供的一种容器,可以用来存储多个数据。
集合和数组既然都是容器,它们有啥区别呢?
- 数组的长度是固定的。集合的长度是可变的
- 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类 型可以不一致。在开发中一般当对象多的时候,使用集合进行存储
2、Collection接口
Collection 接口是在整个 Java 类集中保存单值的最大操作父接口,里面每次操作的时候都只能保存一个对象的数据。
接口定义
publice interface Collection<E> extends Iterable<E>
15种常用的方法
- 在开发中不会直接使用 Collection 接口。而使用其操作的子接口:List、Set。
3、List接口
java.util.List 接口继承自 Collection 接口 ,将实现了 List 接口的对象称为List集合
-
在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,
-
在程序中可以通过索引来访问集合中的指定元素
-
List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
-
通过元素的equals方法,来比较是否为重复的元素
list接口定义
public interface List<E> extends Collection<E>
List接口中常用方法
- public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
- public E get(int index) :返回集合中指定位置的元素。
- public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
- public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新 前的元素。
List 接口之后,那么该如何使用该接口呢?需要找到此接口的实现类,常用的实现类有如下几个: · ArrayList(95%)、Vector(4%)、LinkedList(1%)
4、ArrayList接口
java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用 最多的功能为查询数据、遍历数据 ,ArrayList 继承了 AbstractList ,并实现了 List 接口
此类继承了 AbstractList 类。AbstractList 是 List 接口的子类。AbstractList 是个抽象类,适配器设计模式。
范例:增加及取得元素
package org.listdemo.arraylistdemo;
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo01 {
public static void main(String[] args) {
List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型
all.add("hello "); // 增加内容,此方法从Collection接口继承而来
all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
all.add("world"); // 增加内容,此方法从Collection接口继承而来
System.out.println(all); // 打印all对象调用toString()方法
}
}
以上的操作向集合中增加了三个元素,其中在指定位置增加的操作是 List 接口单独定义的。随后进行输出的时候, 实际上调用的是 toString()方法完成输出的。
范例:进一步操作
- 使用 remove()方法删除若干个元素,并且使用循环的方式输出。
- 根据指定位置取的内容的方法,只有 List 接口才有定义,其他的任何接口都没有任何的定义
package org.listdemo.arraylistdemo;
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo02 {
public static void main(String[] args) {
List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型
all.add("hello "); // 增加内容,此方法从Collection接口继承而来
all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
all.add("world"); // 增加内容,此方法从Collection接口继承而来
all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的
all.remove("world");// 删除指定的对象
System.out.print("集合中的内容是:");
for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来
System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的
}
}
}
常用的方法
5、Vector
与 ArrayList 一样,Vector 本身也属于 List 接口的子类,
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
此类与 ArrayList 类一样,都是 AbstractList 的子类。所以,此时的操作只要是 List 接口的子类就都按照 List 进行操作。
package org.listdemo.vectordemo;
import java.util.List;
import java.util.Vector;
public class VectorDemo01 {
public static void main(String[] args) {
List<String> all = new Vector<String>(); // 实例化List对象,并指定泛型类型
all.add("hello "); // 增加内容,此方法从Collection接口继承而来
all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
all.add("world"); // 增加内容,此方法从Collection接口继承而来
all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的
all.remove("world");// 删除指定的对象
System.out.print("集合中的内容是:");
for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来
System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的
}
}
}
-
以上的操作结果与使用 ArrayList 本身并没有任何的区别。因为操作的时候是以接口为操作的标准。
-
但是 Vector 属于 Java 元老级的操作类,是最早的提供了动态对象数组的操作类,在 JDK 1.0 的时候就已经推出了此 类的使用,只是后来在 JDK 1.2 之后引入了 Java 类集合框架。但是为了照顾很多已经习惯于使用 Vector 的用户,所以在 JDK 1.2 之后将 Vector 类进行了升级了,让其多实现了一个 List 接口,这样才将这个类继续保留了下来
6、Vector类和ArrayList类的区别
vector线程安全,arraylist稍微没那么安全
7、LinkedList
java.util.LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合
ArrayList 和 LinkedList 的区别
Java LinkedList(链表) 类似于 ArrayList,是一种常用的数据容器。
与 ArrayList 相比,LinkedList 的增加和删除的操作效率更高,而查找和修改的操作效率较低
以下情况使用 ArrayList :
- 频繁访问列表中的某一个元素。
- 只需要在列表末尾进行添加和删除元素操作。
以下情况使用 LinkedList :
- 你需要通过循环迭代来访问列表中的某些元素。
- 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
public class RunoobTest { //我们可以使用 for 配合 size() 方法来迭代列表中的元素
public static void main(String[] args) {
LinkedList<String> sites = new LinkedList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Weibo");
for (String i : sites) {
System.out.println(i);
}
}
}
输出结果为:
Google
Runoob
Taobao
Weibo
public class RunoobTest {
public static void main(String[] args) {
LinkedList<String> sites = new LinkedList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
// 使用 addFirst() 在头部添加元素
sites.addFirst("Wiki");
System.out.println(sites);
}
}
//[Wiki, Google, Runoob, Taobao]
Set接口
- Set 接口也是 Collection 的子接口,与 List 接口最大的不同在于,Set 接口里面的内容是不允许重复的。
- Set 接口并没有对 Collection 接口进行扩充,基本上还是与 Collection 接口保持一致。因为此接口没有 List 接口中定义 的 get(int index)方法,所以无法使用循环进行输出。
- 那么在此接口中有两个常用的子类:HashSet、TreeSet
散列存放:HashSet
HashSet 属于散列的存放类集,里面的内容是无序存放的。
注意: 给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方 式,才能保证HashSet集合中的对象唯一
范例:
package org.listdemo.hashsetdemo;
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo01 {
public static void main(String[] args) {
Set<String> all = new HashSet<String>(); // 实例化Set接口对象
all.add("A");
all.add("B");
all.add("C");
all.add("D");
all.add("E");
System.out.println(all);
}
}
HashSet本身属于无序存放,要实现通过循环的方式输出Set中的内容,可以先转变为数组
将hashSet变为数组 toArray();
package org.listdemo.hashsetdemo;
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo02 {
public static void main(String[] args) {
Set<String> all = new HashSet<String>(); // 实例化Set接口对象
all.add("A");
all.add("B");
all.add("C");
all.add("D");
all.add("E");
Object obj[] = all.toArray(); // 将集合变为对象数组
for (int x = 0; x < obj.length; x++) {
System.out.print(obj[x] + "、");
}
}
}
但是,以上的操作不好,因为在操作的时候已经指定了操作的泛型类型,那么现在最好的做法是由泛型所指定的类 型变为指定的数组。 所以只能使用以下的方法: T[] to Array(T[] a)
String[] str = all.toArray(new String[] {});
package org.listdemo.hashsetdemo;
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo03 {
public static void main(String[] args) {
Set<String> all = new HashSet<String>(); // 实例化Set接口对象
all.add("A");Java SE 核心技术
第(8)页 共(27)页
all.add("B");
all.add("C");
all.add("D");
all.add("E");
String[] str = all.toArray(new String[] {});// 变为指定的泛型类型数组
for (int x = 0; x < str.length; x++) {
System.out.print(str[x] + "、");
}
}
}
HashMap 与 Hashtable 的区别(重点)
TreeSet 排序 的子类
- TreeSet不允许null值;
- TreeSet不是线程安全的
- 和SortedMap一样,支持自然排序和自定义排序。自然排序要求添加到Set中的元素实现Comparable接口,自定义排序要求实现一个Comparator比较器
与 HashSet 不同的是,TreeSet 本身属于排序的子类,此类的定义如下:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, Serializable
示例:
package org.listdemo.treesetdemo01;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetDemo01 {
public static void main(String[] args) {
Set<String> all = new TreeSet<String>(); // 实例化Set接口对象\
all.add("D");
all.add("X");
all.add("A");
System.out.println(all);
}
}
输出:[A, D, X]
虽然在增加元素的时候属于无序的操作,但是增加之后却可以为用户进行排序功能的实现。
排序的说明
定义一个类进行对象排序
示例
定义person类
public class Person implements Comparable<Person> {
private String name;
private int age;
public int compareTo(Person per) {
if (this.age > per.age) {
return 1;
} else if (this.age < per.age) {
return -1;
} else {
return 0;
}
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "姓名:" + this.name + ",年龄:" + this.age;
}
}
定义一个TreeSet集合,向里面增加若干个 Person 对象。
import java.util.Set;
import java.util.TreeSet;
public class TreeSetPersonDemo01 {
public static void main(String[] args) {
Set<Person> all = new TreeSet<Person>();
all.add(new Person("张三", 10));
all.add(new Person("李四", 10));
all.add(new Person("王五", 11));
all.add(new Person("赵六", 12));
all.add(new Person("孙七", 13));
System.out.println(all);
}
}
结果是:[姓名:张三,年龄:10, 姓名:王五,年龄:11, 姓名:赵六,年龄:12, 姓名:孙七,年龄:13]
从以上的结果中可以发现,李四没有了。因为李四的年龄和张三的年龄是一样的,所以会被认为是同一个对象。则 此时必须修改 Person 类,如果假设年龄相等的话,按字符串进行排序。
public int compareTo(Person per) {
if (this.age > per.age) {
return 1;
} else if (this.age < per.age) {
return -1;
} else {
return this.name.compareTo(per.name);
}
}
小结:
关于 TreeSet 的排序实现,如果是集合中对象是自定义的或者说其他系统定义的类没有实现 Comparable 接口,则不能实现 TreeSet 的排序,会报类型转换(转向 Comparable 接口)错误。 换句话说要添加到 TreeSet 集合中的对象的类型必须实现了 Comparable 接口。
不过 TreeSet 的集合因为借用了 Comparable 接口,同时可以去除重复值,而 HashSet 虽然是 Set 接口子类,但是对于没有复写 Object 的 equals 和 hashCode 方法的对象,加入了 HashSet 集合中也是不能去掉重复值的
集合输出
已经学习过了基本的集合操作,那么对于集合的输出本身也是有多种形式的,可以使用如下的几种方式:
- Iterator 迭代输出(90%)、ListIterator(5%)、Enumeration(1%)、foreach(4%)
但是在讲解输出的时候一定要记住以下的原则:“只要是碰到了集合,则输出的时候想都不想就使用 Iterator 进行输出。”
Iterator
Iterator 属于迭代输出,基本的操作原理:是不断的判断是否有下一个元素,有的话,则直接输出.
publice interface Iterator<E>
要想使用此接口,则必须使用 Collection 接口,在 Collection 接口中规定了一个 iterator()方法,可以用于为 Iterator 接口进行实例化操作。
- 迭代 : 即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果 有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取 出。这种取出方式专业术语称为迭代。
- public E next() :返回迭代的下一个元素。
- public boolean hasNext() :如果仍有元素可以迭代,则返回 true
此接口规定了以下的三个方法:
范例:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo01 {
public static void main(String[] args) {
Collection<String> all = new ArrayList<String>();
all.add("A");
all.add("B");
all.add("C");
all.add("D");
all.add("E");
Iterator<String> iter = all.iterator();
while (iter.hasNext()) {// 判断是否有下一个元素
String str = iter.next(); // 取出当前元素
System.out.print(str + "、");
}
}
}
以上的操作是 Iterator 接口使用最多的形式,也是一个标准的输出形式。
但是在使用 Iterator 输出的时候有一点必须注意,在进行迭代输出的时候如果要想删除当前元素,则只能使用 Iterator 接口中的 remove()方法,而不能使用集合中的 remove()方法。否则将出现未知的错误。
Iterator<String> iter = all.iterator();
while (iter.hasNext()) {// 判断是否有下一个元素
String str = iter.next(); // 取出当前元素
if (str.equals("C")) {
iter.remove(); // 调用Iterator中的删除
} else {
System.out.print(str + "、");
}
}
ListIterator
- ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口
- ListIterator 是可以进行双向输出的迭代接口,
ListIterator 和 lterator
相同:都是迭代器,当需要对集合中元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用
不同:
- 使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型(即不能对Map进行使用)
- ListIterator有add方法,可以向List中添加对象,而Iterator不能。
- ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历
- 都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现
foreach
foreach 可以用来输出数组的内容,那么也可以输出集合中的内容。
import java.util.ArrayList;
import java.util.Collection;
public class ForeachDemo01 {
public static void main(String[] args) {
Collection<String> all = new ArrayList<String>();
all.add("A");
all.add("B");
all.add("C");
all.add("D");
all.add("E");
for (String str : all) {
System.out.println(str) ;
}
}
}
for(类型 定义名 :要输出的对象){
System.out.println(定义名) ;
}
在使用 foreach 输出的时候一定要注意的是,里面的操作泛型要指定具体的类型,这样在输出的时候才会更加有针对 性。
Map接口
以上的 Collection 中,每次操作的都是一个对象,如果现在假设要操作一对对象,则就必须使用 Map 了,类似于以 下一种情况:
- · 张三 123456
- · 李四 23456
那么保存以上信息的时候使用 Collection 就不那么方便,所以要使用 Map 接口。里面的所有内容都按照 key ->value 的形式保存,也称为二元偶对象。
Map 本身是一个接口,所以一般会使用以下的几个子类:HashMap、TreeMap、Hashtable
新的子类:HashMap
- HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
- HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
- HashMap 是无序的,即不会记录插入的顺序。
- HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口
范例:得到全部的 key 或 value
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapDemo02 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "张三A");
map.put(2, "李四");
map.put(3, "王五");
Set<Integer> set = map.keySet(); // 得到全部的key
Collection<String> value = map.values(); // 得到全部的value
Iterator<Integer> iter1 = set.iterator();
Iterator<String> iter2 = value.iterator();
System.out.print("全部的key:");
while (iter1.hasNext()) {
System.out.print(iter1.next() + "、");
}
System.out.print("\n全部的value:");
while (iter2.hasNext()) {
System.out.print(iter2.next() + "、");
}
}
}
既然可以取得全部的 key,那么下面就可以对以上的操作进行扩充,循环输出 Map 中的全部内容。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapDemo03 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
Set<String> set = map.keySet(); // 得到全部的key
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
String i = iter.next(); // 得到key
System.out.println(i + " --:> " + map.get(i));
}
}
Hashtable
TreeMap 子类是允许 key 进行排序的操作子类,其本身在操作的时候将按照 key 进行排序,另外,key 中的内容可以 为任意的对象,但是要求对象所在的类必须实现 Comparable 接口。
public static void main(String[] args) {
Map<String, String> map = new TreeMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
Set<String> set = map.keySet(); // 得到全部的key
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
String i = iter.next(); // 得到key
System.out.println(i + " --:> " + map.get(i));
}
}
关于 Map 集合的输出
在 Collection 接口中,可以使用 iterator()方法为 Iterator 接口实例化,并进行输出操作,但是在 Map 接口中并没有此 方法的定义,所以 Map 接口本身是不能直接使用 Iterator 进行输出的。
Comparable和Comparator两个接口的区别
自然排序Comparable与比较器排序Comparator
Comparable:
强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码 实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进 行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
Comparator强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构 (如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序
总结:自然排序Comparable是类在创建的时候就规定了类的比较的特性,而比较器Comparator是在具体的应用过程中我们根据需求创建一个工具类来完成比较,相比之下比较器的使用更加灵活,不会改变这个类本身,减低了耦合度。
总结
- 类集就是一个动态的对象数组,可以向集合中加入任意多的内容。
- List 接口中是允许有重复元素的,Set 接口中是不允许有重复元素。
- 所有的重复元素依靠 hashCode()和 equals 进行区分
- List 接口的常用子类:ArrayList、Vector
- Set 接口的常用子类:HashSet、TreeSet
- TreeSet 是可以排序,一个类的对象依靠 Comparable 接口排序
- Map 接口中允许存放一对内容,key value
- Map 接口的子类:HashMap、Hashtable、TreeMap
- Map 使用 Iterator 输出的详细步骤
补充小知识
链表和数组的区别
什么 是链表?
链表 [Linked List]:链表是由一组不必相连(不必相连:可以连续也可以不连续)的内 存结构(节点),按特定的顺序链接在一起的抽象数据类型。
补充:
- 抽象数据类型(Abstract Data Type [ADT]):表示数学中抽象出来的一些操作的集合。
- 内存结构:内存中的结构,如:struct、特殊内存块…等等之类;
数组和链表的区别和优缺点:
**数组**:
数组是一种连续存储线性结构,元素类型相同,大小相等
数组的优点 :
存储速度快
数组的缺点:
- 事先必须知道数组的长度
- 插入删除元素很慢
- 空间通常是有限制的
- 需要大块连续的内存块
- 插入删除元素的效率很低
链表:
链表是离散存储线性结构
n 个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一 个后续节点,首节点没有前驱节点,尾节点没有后续节点。
链表优点:
空间没有限制
插入删除元素很快
链表缺点:
存取速度很慢
**链表共分为3类: 单链表、双向链表、循环链表 **
二叉树
二叉树是树的一种,每个节点最多可具有两个子树,即结点的度最大为 2(结点度:结点拥 有的子树数)。
二叉查找树
定义:当前根节点的左边全部比根节点小,当前根节点的右边全部比根节点大。 o 可以看出,这对我们来找一个数是非常方便快捷的
二叉树的种类
斜树
所有结点都只有左子树,或者右子树。
满二叉树
所有的分支节点都具有左右节点。
完全二叉树
若设二叉树的深度为 h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
二叉树的一些性质
- 二叉树第 i 层上的结点数目最多为 2^(i-1) (i≥1)
- 深度为 h 的二叉树至多有 2^h-1 个结点(h≥1)
- 包含 n 个结点的二叉树的高度至少为 log2 (n+1)
- 在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结点数为 n2,则 n0=n2+1
二叉树的遍历方式
**二叉树的遍历方式,一般分为先序遍历,中序遍历,后序遍历。 **
先序遍历
先访问根节点,然后访问左节点,最后访问右节点(根->左->右) •
中序遍历 o
先访问左节点,然后访问根节点,最后访问右节点(左->根->右) •
后序遍历 o
先访问左节点,然后访问右节点,最后访问根节点(左->右->根
常见的数据结构
数据存储的常用结构有:栈、队列、数组、链表和红黑树
栈
栈:stack,又称堆栈, 栈(stack)是限定仅在表尾进行插入和删除操作的线性表。我们把允许插 入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈又称为先进后出 的线性表 。
特点:
- 先进后出
- 栈的入口、出口的都是栈的顶端位置
队列
队列:queue,简称队, 队列是一种特殊的线性表,是运算受到限制的一种线性表,只允许在表的 一端进行插入,而在另一端进行删除元素的线性表。队尾(rear)是允许插入的一端。队头(front)是 允许删除的一端。空队列是不含元素的空表。
特点:
- 先进先出
- 队列的入口、出口各占一侧。例如,下图中的左侧为入口,右侧为出口
数组:
- 数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。
特点:
- 查找元素快:通过索引,可以快速访问指定位置的元素
- 增删元素慢
- 指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原 数组元素根据索引,复制到新数组对应索引的位置。
- 指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应 索引的位置,原数组中指定索引位置元素不复制到新数组中。