《JAVA编程思想》第十一章(容器)、十六章、十七章总结

我将十一章容器部分和十七章写在一块,所以十六章先写在前面。

一.十六章

1.数组和集合的区别

储存元素的区别:数组可以存放基本数据类型,也可以存放引用数据类型,基本数据类型存放的是数值,而引用数据类型存放的是地址值。集合只能存放引用数据类型(对象),基本数据类型会被JAVA的自动装箱机制,变成对象。

储存长度:数组在创建时,就必须规定好长度,后不能改变。而集合可以随时改变它的长度。

对元素的访问:数组使用的是[],而集合则是添加add,获取get等方法。

数组唯一的优势就是效率高一点,但在平时开发过程中,优先使用集合。

2.Arrays一些常用功能

1.arraycopy()方法

这个方法里有四个参数,第1个参数,被复制数组;第2个参数,被复制数组复制的起始位置;第3个参数,复制到的数组;第4个参数,复制到的数组复制的起始位置;第5个参数,复制多少个。

arrayCopy( arr1, 2, arr2, 5, 10);意思是;将arr1数组里从索引为2的元素开始, 复制到数组arr2里的索引为5的位置, 复制的元素个数为10个.。

tips:复制一维数组没有问题,复制二维数组时,改变一个另一个也会跟着改变。因为二维数组就是元素是一维数组的一维数组,相当于元素时引用类型了。有指向性了

 

2.equals()方法

Arrays.equals(a1,a2)  比较a1,a2两个数组,相同返回true

 

3.comparable接口和comparator接口

先说说comparable接口,是排序接口。首先需要我们要排序的类来实现此接口。然后重写一下compareTo()方法,下面的例子明显规定了比较的是年龄。若一个类实现了Comparable接口,就意味着该类支持排序。实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。

下面是格式:

目前对象.compareTo(需要比较的对象)

实现比较大小,

  • 如果返回值等于零:o1=o2
  • 返回值大于零则o1>o2
  • 返回值小于于零则o1<o2
class Person implements Comparable<Person> {

	String name;
	int age;
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
	@Override
	public int compareTo(Person o) {
		return this.age-o.age;
	}
}
public class ComparableTest {

	public static void main(String[] args) {
		List<Person> personList = new ArrayList<P>();
		personList.add(new Person("ace",22));
		personList.add(new Person("xb",21));
		personList.add(new Person("glm",36));
		personList.add(new Person("sxy",20));

		System.out.println("比较大小");
		Person ace = new Person("ace",22);
		Person xb = new Person("xb",21);
		String result = ace.compareTo(xb)==0?"一样大":ace.compareTo(xb)>0?"ace大":"xb大";
		System.out.println(result);
		
		System.out.println("按照年龄");
		Collections.sort(personList);//Arrays.sort也行
		for(Person p:personList)
			System.out.println(p);
		System.out.println();
	}

}

上面的列子,完整展示了comparable接口的使用。下面再来说comparator接口的使用,先建立一个“该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过实现Comparator来新建一个比较器,然后通过这个比较器对类进行排序。

note:

1、若一个类要实现Comparator接口:它一定要实现compare(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。

2、int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。

同样拿person类来举例

class Person{
	String name;
	int age;
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}

//单独自定义一个类,而不是写在Person类里面
class PersonSortByAge implements Comparator<Person>{
	@Override
	public int compare(Person o1, Person o2) {
		return o1.age-o2.age;
	}
}
//在主方法里使用
public class ComparatorTest {

	public static void main(String[] args) {

		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("ace",22));
		personList.add(new Person("xb",21));
		personList.add(new Person("glm",36));
		personList.add(new Person("sxy",20));
        //在sort()方法里使用匿名类创建匿名对象,来排序
		personList.sort(new PersonSortByAge());
		for(Person p:personList)
			System.out.println(p);
		
	}
}

这样就完成按照Person的年龄进行排序。总结一下两者的区别

1.Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。

2.Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。前者属于静态绑定,后者属于动态绑定。

两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。

 

4.Arrays.binarySearch()方法

https://blog.csdn.net/wanderlustLee/article/details/79208630

首先,binarySearch方法为二分法查找,所以数组必须是有序的或者是用sort()方法排序之后的。

格式: binarySearch(Object[], Object key) 方法的object[]参数是要查找的数组,key参数为要查找的key值。

方法的返回值有几种:

1.找到的情况下:如果key在数组中,则返回搜索值的索引。

2.找不到的情况下:

 [1] 搜索值不是数组元素,且在数组范围内,从1开始计数,得“ - 插入点索引值”;
 [2] 搜索值不是数组元素,且大于数组内元素,索引值为 – (length + 1);
 [3] 搜索值不是数组元素,且小于数组内元素,索引值为 – 1。

举例:

int a[] = new int[] {1, 3, 4, 6, 8, 9};  
        int x1 = Arrays.binarySearch(a, 5);  
        int x2 = Arrays.binarySearch(a, 4);  
        int x3 = Arrays.binarySearch(a, 0);  
        int x4 = Arrays.binarySearch(a, 10);
//结果为:x1=-4      x2=2    x3=-1    x4=-7

第二种参数形式:

binarySearch(Object[], int fromIndex, int toIndex, Object key)  方法的object[]参数为要查找的数组,fromindex参数为开始索引(包括),toindex为结束索引(不包括),两个参数之间为查找的范围。key为要查找的key。

方法的返回值有几种:

1.找到的情况下:如果key在数组中,则返回搜索值的索引。

2.找不到的情况下:

 [1] 该搜索键在范围内,但不是数组元素,由1开始计数,得“ - 插入点索引值”;
 [2] 该搜索键不在范围内,且小于范围(数组)内元素,返回–(fromIndex + 1);
 [3] 该搜索键不在范围内,且大于范围(数组)内元素,返回 –(toIndex + 1)。

举例:

 int a[] = new int[] {1, 3, 4, 6, 8, 9};  
        int x1 = Arrays.binarySearch(a, 1, 4, 5);  
        int x2 = Arrays.binarySearch(a, 1, 4, 4);  
        int x3 = Arrays.binarySearch(a, 1, 4, 2);  
        int x4 = Arrays.binarySearch(a, 1, 4, 10);
//结果为   x1=-4    x2=2    x3=-2    x4=-5

 

十一章和十七章(初步总结,不断修订)

一.collection总结

这个图片里包含了整个collection中完整全部内容,非常全面。

首先必须明确的是collection:定义的是所有单列集合中共性的方法,所有的单列集合都可以使用共性方法。

Collection 接口有 3 种子类型集合: List、Set 和 Queue(图中),再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、TreeSet 等等。

Ⅰ Collection 集合常用方法

Ⅱ 上图中的Iterator接口(迭代器)

1.迭代器的概念:Collection集合元素的通用获取方式。在取元素之前先判断集合中有没有元素,如果有,就把这个元素取出来;继续判断,如果还有就再取出来。

2.为什么需要迭代器?因为Collection集合中有许多的容器,比如一开始你使用的是List,但后来由于各种原因改用了Set,原来针对List编写的遍历程序全部要重写了。所以我们在遍历容器时,不关心它具体是什么容器,我们只想要一个通用的遍历方法。

3.迭代器使用步骤:

   1.使用集合中的方法 iterator()获取迭代器的实现对象,使用Iterator接口来接受(多态)。

   2.使用Iterator接口中的方法hasNext判断还有没有下一个元素。

   3.使用Iterator接口中的方法next取出集合中的下一个元素。

实现代码:

 

Ⅲ Listlterator接口

特点:

1.只能用于List容器

2.Iterator接口只能向前,而这个可以向前向后。

3.ListIterator还可以返回指向对象前一个和后一个的索引,并可以用set()方法,替换你最后一个访问的元素。

4.不像Iterator接口只能从容器一开始向后移动,ListIterator可以通过listIterator(n)方法,指定索引位置开始向后。

代码实现:

 

Ⅳ 增强for循环

首先明确增强for循环底层也是迭代器,目的是为了简化迭代器的书写。

tips:增强for循环只能用来遍历数组和集合。

格式: for(集合/数组的数据类型  变量名 : 集合名/数组名){}

代码实现如下:

 

二.List集合总结

Ⅰ List集合特点

1.有序的集合,储存元素和取出元素的顺序是一致的。

2.有索引,所以包含了一些带索引的方法

3.允许存储重复的元素

 

Ⅱ List独有的带索引的方法

1.public void add(int index, E element):在指定索引位置,添加元素

2.public E get(int index):返回集合中指定位置的元素

3.public E remove(int index):移除这个索引的元素

4.public E set(int index,E elemet):用指定元素(第二个参数),去替换索引位置的元素。

 

List集合主要包含了两个容器,一个就是非常熟悉的ArrayList,另一个就是LinkedList。ArrayList底层是数组,所以查找快,插入删除慢些。LinkedList底层是链表,正好与之相反。需要大量的随机访问的时候,肯定首选ArrayList,需要大量增删的时候,首选Linkedlist。

Ⅲ LinkedList特有的方法

1.public void addFirst(E e):将指定元素插入表头

2.public void addLast(E e):将指定元素插入表尾

3.public void push(E e):将指定元素推入堆栈(因为LinkedList是可以去实现Stack 和queue)

4.public void pop():从堆栈中弹出元素

5.public E getFirst():返回表头元素

6.public E getLast():返回表尾元素

7.public E removeFirst():移除并返回表头元素

8.public E removeLast():移除并返回表尾元素

9.public boolean isEmpty():如果列表不包含元素,则返回true

 

三.Set集合总结

Ⅰ Set集合特点

Set集合特点就是没有重复的元素,且没有索引。在每次存入元素前,都会检查Set中是否已经有这个元素了,这里就要用到equals()和hashcode()这两个方法。

Set集合里包含三个,HashSet 、TreeSet、LinkedHashSet 。HashSet就是查找速度快,底层就是散列表实现,储存顺序并不是安装存入顺序。TreeSet底层是红黑树实现,里面储存的元素都会被排序,元素必须要实现Comparable接口,所以将TreeSet中的元素输出时,相当于都是排序过的。

LinkedHashSet 特点就是里面储存顺序和存入顺序是一致的,底层是散列表和链表实现。

 

Ⅱ 如何选择使用

Ⅲ SortedSet

SortedSet类其实就是TreeSet的基本实现,里面所有元素也是经过排序的。

格式:

SortedSet<String> set = new TreeSet<String>();

一些常用方法:

//返回此 set 中当前第一个(最低)元素
String fe = set.first();
//返回此 set 中当前最后一个(最高)元素。
String le = set.last();
//返回此 set 的部分视图,其元素严格小于 toElement。
SortedSet<String> headE = set.headSet("ccc");
//返回此 set 的部分视图,其元素大于等于 fromElement。
SortedSet<String> tailE = set.tailSet("ccc");
//返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
SortedSet<String> subE = set.subSet("ccc", "eee");

四.队列

除了并发以外,实现队列有两个,一个是LinkedList,另一个是PriorityQueue(优先队列)。

Ⅰ  Queue的一些常用方法

add(E)其实是collection的通用方法, offer(E) 都为添加方法,不同之处在于 add() 方法在添加失败(比如队列已满)时会报 一些运行时错误 ;而 offer() 方法即使在添加失败时也不会奔溃,只会返回 false。

remove(), poll() 删除并返回头部元素,当队列为空时 remove() 方法会报 NoSuchElementException 错; 而 poll() 不会奔溃,只会返回 null。

element(), peek() 获取但不删除,当队列为空时 element() 抛出异常;peek() 不会奔溃,只会返回 null。

Ⅱ PriorityQueue(优先队列)

优先队列,输出顺序就不和普通的队列是一样的了,它遵循的是一个优先情况,就是优先级别。支持你自定义Comparable,如果没有自定义那就是按照自然顺序。由小到大。

如下面优先队列储存着Integer类型的元素:

public class CreatePriorityQueueExample {
    public static void main(String[] args) {
        // Create a Priority Queue
        PriorityQueue<Integer> numbers = new PriorityQueue<>();

        // Add items to a Priority Queue (ENQUEUE)
        numbers.add(750);
        numbers.add(500);
        numbers.add(900);
        numbers.add(100);

        // Remove items from the Priority Queue (DEQUEUE)
        while (!numbers.isEmpty()) {
            System.out.println(numbers.remove());
        }

    }
}

# Output
100
500
750
900

优先队列储存着String类型的元素:

public class CreatePriorityQueueStringExample {
    public static void main(String[] args) {
        // Create a Priority Queue
        PriorityQueue<String> namePriorityQueue = new PriorityQueue<>();

        // Add items to a Priority Queue (ENQUEUE)
        namePriorityQueue.add("Lisa");
        namePriorityQueue.add("Robert");
        namePriorityQueue.add("John");
        namePriorityQueue.add("Chris");
        namePriorityQueue.add("Angelina");
        namePriorityQueue.add("Joe");

        // Remove items from the Priority Queue (DEQUEUE)
        while (!namePriorityQueue.isEmpty()) {
            System.out.println(namePriorityQueue.remove());
        }

    }
}

# Output
Angelina
Chris
Joe
John
Lisa
Robert

也可以自己定义如何比较,比较什么,这里采用的new一个Comparator对象。

public class PriorityQueueCustomComparatorExample {
    public static void main(String[] args) {
        // A custom comparator that compares two Strings by their length.
        Comparator<String> stringLengthComparator = new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s1.length() - s2.length();
            }
        };

        // Create a Priority Queue with a custom Comparator
        PriorityQueue<String> namePriorityQueue = new PriorityQueue<>(stringLengthComparator);

        // Add items to a Priority Queue (ENQUEUE)
        namePriorityQueue.add("Lisa");
        namePriorityQueue.add("Robert");
        namePriorityQueue.add("John");
        namePriorityQueue.add("Chris");
        namePriorityQueue.add("Angelina");
        namePriorityQueue.add("Joe");
        while (!namePriorityQueue.isEmpty()) {
            System.out.println(namePriorityQueue.remove());
        }
    }
}

# Output
Joe
John
Lisa
Chris
Robert
Angelina

优先队列的底层原理:使用二叉小顶堆来实现,具体地看下数据结构那块的总结。

五.Map

Map里面的元素都是一个个键值对,键(key)和值(value)完全是一一对应的,键不能重复而值可以重复。

Ⅰ  Map的一些常用方法

1.public V put(K key , V value): 把指定的键与指定的值添加到Map集合。存储键值对的时候,key重复,会使用新的value 替换Map中重复的value,返回被替代的value值。

2.public V remove(Object key):删除对应键的元素,key存在的话,返回被删除的值。key不存在的话,返回null。

3.public V get(Object key):获取键值。若key存在的话,返回对应的value值。若key不存在,返回null。

4.boolean containsKey(Object key):判断集合中是否已经有这个键了

5.boolean containsValue(V value ):判断集合中是否已经有这个值了

Ⅱ Map集合遍历

有四种方法区遍历Map集合,一般用前两种。

/**
* 最常见也是大多数情况下用的最多的,一般在键值对都需要使用
 */
Map <String,String>map = new HashMap<String,String>();
map.put("熊大", "棕色");
map.put("熊二", "黄色");

//方法一:在for循环中使用entries实现Map的遍历:
for(Map.Entry<String, String> entry : map.entrySet()){
    String mapKey = entry.getKey();
    String mapValue = entry.getValue();
    System.out.println(mapKey+":"+mapValue);
}
//方法二:在for循环中遍历key或者values,一般适用于只需要map中的key或者value时使用,在性能上比使用entrySet较好;
for(String key : map.keySet()){
    System.out.println(key);
}
for(String value : map.values()){
    System.out.println(value);
}
//方法三:通过Iterator遍历;
Iterator<Entry<String, String>> entries = map.entrySet().iterator();//创建迭代器对象
while(entries.hasNext()){
    Entry<String, String> entry = entries.next();
    String key = entry.getKey();
    String value = entry.getValue();
    System.out.println(key+":"+value);
}
//方法四:通过键找值遍历,这种方式的效率比较低,因为本身从键取值是耗时的操作;
for(String key : map.keySet()){
    String value = map.get(key);
    System.out.println(key+":"+value);
}

Ⅲ 各种Map的特点:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章