文章目录
- 11-内部类
- 链接外部类
- 使用.this 和.new
- 匿名内部类
- 12-集合初步
- 思考1,List<Apple> apples = new ArrayList<>();
- 思考2,如何初始化一个collection
- 思考3,Pet关键字
- 思考4,关于ListIterator这个双向迭代器
- 思考5,关于LinkedList的一些方法
- 思考6,关于优先队列
- summary
11-内部类
链接外部类
当生成一个内部类的对象时,此对象与制造它的外部对象(enclosing object)之间就有了一种联系,所以它能访问其外部对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外部类的所有元素的访问权。
SequenceSelector可以访问Selector中的所有元素。
// innerclasses/Sequence.java
// Holds a sequence of Objects
interface Selector {
boolean end();
Object current();
void next();
}
public class Sequence {
private Object[] items;
private int next = 0;
public Sequence(int size) {
items = new Object[size];
}
public void add(Object x) {
if(next < items.length)
items[next++] = x;
}
private class SequenceSelector implements Selector {
private int i = 0;
@Override
public boolean end() { return i == items.length; }
@Override
public Object current() { return items[i]; }
@Override
public void next() { if(i < items.length) i++; }
}
public Selector selector() {
return new SequenceSelector();
}
public static void main(String[] args) {
Sequence sequence = new Sequence(10);
for(int i = 0; i < 10; i++)
sequence.add(Integer.toString(i));
Selector selector = sequence.selector();
while(!selector.end()) {
System.out.print(selector.current() + " ");
selector.next();
}
}
}
使用.this 和.new
如果一个内部类想使用外部类的名义,可以写个outer()函数
// innerclasses/DotThis.java
// Accessing the outer-class object
public class DotThis {
void f() { System.out.println("DotThis.f()"); }
public class Inner {
public DotThis outer() {
return DotThis.this;
// A plain "this" would be Inner's "this"
}
}
public Inner inner() { return new Inner(); }
public static void main(String[] args) {
DotThis dt = new DotThis();
DotThis.Inner dti = dt.inner();
dti.outer().f(); //输出DotThis.f()
}
}
如果一个外部类想生成新的内部类对象,用new
// innerclasses/Parcel3.java
// Using .new to create instances of inner classes
public class Parcel3 {
class Contents {
private int i = 11;
public int value() { return i; }
}
class Destination {
private String label;
Destination(String whereTo) { label = whereTo; }
String readLabel() { return label; }
}
public static void main(String[] args) {
Parcel3 p = new Parcel3();
// Must use instance of outer class
// to create an instance of the inner class:
Parcel3.Contents c = p.new Contents();
Parcel3.Destination d =
p.new Destination("Tasmania");
}
}
匿名内部类
对于一个这样的代码,
// innerclasses/Parcel7b.java
// Expanded version of Parcel7.java
public class Parcel7b {
class MyContents implements Contents {
private int i = 11;
@Override
public int value() { return i; }
}
public Contents contents() {
return new MyContents();
}
public static void main(String[] args) {
Parcel7b p = new Parcel7b();
Contents c = p.contents();
}
}
我们可以用匿名内部类改写为
// innerclasses/Parcel7.java
// Returning an instance of an anonymous inner class
public class Parcel7 {
public Contents contents() {
return new Contents() { // Insert class definition
private int i = 11;
@Override
public int value() { return i; }
}; // Semicolon required
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
12-集合初步
分为两大类,
一类是collection(集合),包含list,set和queue
一类是Map
思考1,List apples = new ArrayList<>();
为啥要这么写,而不是如下写
ArrayList apples = new ArrayList<>();
参考这篇文章
思考2,如何初始化一个collection
Arrays.asList() 方法接受一个数组或是逗号分隔的元素列表(使用可变参数),并将其转换为 List 对象。
Collections.addAll() 方法接受一个 Collection 对象,以及一个数组或是一个逗号分隔的列表,将其中元素添加到 Collection 中。
下边的示例展示了这两个方法,以及更通用的 、所有 Collection 类型都包含的addAll() 方法:
// collections/AddingGroups.java
// Adding groups of elements to Collection objects
import java.util.*;
public class AddingGroups {
public static void main(String[] args) {
Collection<Integer> collection =
new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Integer[] moreInts = { 6, 7, 8, 9, 10 };
collection.addAll(Arrays.asList(moreInts));
// Runs significantly faster, but you can't
// construct a Collection this way:
Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);
// Produces a list "backed by" an array:
List<Integer> list = Arrays.asList(16,17,18,19,20);
list.set(1, 99); // OK -- modify an element
// list.add(21); // Runtime error; the underlying
// array cannot be resized.
}
}
思考3,Pet关键字
看下面这些代码
pets是typeinfo里的,可以随机生成一些宠物类型应该是。
Collections.shuffle() 可以随机打乱数组的位置。
// collections/ListFeatures.java
import typeinfo.pets.*;
import java.util.*;
public class ListFeatures {
public static void main(String[] args) {
Random rand = new Random(47);
List<Pet> pets = Pets.list(7);
System.out.println("1: " + pets);
Hamster h = new Hamster();
pets.add(h); // Automatically resizes
System.out.println("2: " + pets);
}
}
/* Output:
1: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
2: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Hamster]
*/
思考4,关于ListIterator这个双向迭代器
ListIterator 是一个更强大的 Iterator 子类型,它只能由各种 List 类生成。
Iterator 只能向前移动,而 ListIterator 可以双向移动。
它可以生成迭代器在列表中指向位置的后一个和前一个元素的索引,并且可以使用 set() 方法替换它访问过的最近一个元素。可以通过调用 listIterator() 方法来生成指向 List 开头处的 ListIterator ,还可以通过调用 listIterator(n) 创建一个一开始就指向列表索引号为 n 的元素处的 ListIterator 。 下面的示例演示了所有这些能力:
// collections/ListIteration.java
import typeinfo.pets.*;
import java.util.*;
public class ListIteration {
public static void main(String[] args) {
List<Pet> pets = Pets.list(8);
ListIterator<Pet> it = pets.listIterator();
while(it.hasNext())
System.out.print(it.next() +
", " + it.nextIndex() +
", " + it.previousIndex() + "; ");
System.out.println();
// Backwards:
while(it.hasPrevious())
System.out.print(it.previous().id() + " ");
System.out.println();
System.out.println(pets);
it = pets.listIterator(3);
while(it.hasNext()) {
it.next();
it.set(Pets.get());
}
System.out.println(pets);
}
}
/* Output:
Rat, 1, 0; Manx, 2, 1; Cymric, 3, 2; Mutt, 4, 3; Pug,
5, 4; Cymric, 6, 5; Pug, 7, 6; Manx, 8, 7;
7 6 5 4 3 2 1 0
[Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Manx]
[Rat, Manx, Cymric, Cymric, Rat, EgyptianMau, Hamster,
EgyptianMau]
*/
Pets.get() 方法用来从位置 3 开始替换 List 中的所有 Pet 对象。
思考5,关于LinkedList的一些方法
LinkedList 还添加了一些方法,使其可以被用作栈、队列或双端队列(deque) 。在这些方法中,有些彼此之间可能只是名称有些差异,或者只存在些许差异,以使得这些名字在特定用法的上下文环境中更加适用(特别是在 Queue 中)。例如:
getFirst() 和 element() 是相同的,它们都返回列表的头部(第一个元素)而并不删除它,如果 List 为空,则抛出 NoSuchElementException 异常。 peek() 方法与这两个方法只是稍有差异,它在列表为空时返回 null 。
removeFirst() 和 remove() 也是相同的,它们删除并返回列表的头部元素,并在列表为空时抛出 NoSuchElementException 异常。 poll() 稍有差异,它在列表为空时返回 null 。
addFirst() 在列表的开头插入一个元素。
offer() 与 add() 和 addLast() 相同。 它们都在列表的尾部(末尾)添加一个元素。
removeLast() 删除并返回列表的最后一个元素。
思考6,关于优先队列
List<Integer> ints = Arrays.asList(25, 22, 20,
18, 14, 9, 3, 1, 1, 2, 3, 9, 14, 18, 21, 23, 25);
priorityQueue = new PriorityQueue<>(ints);
QueueDemo.printQ(priorityQueue);
priorityQueue = new PriorityQueue<>(
ints.size(), Collections.reverseOrder());
priorityQueue.addAll(ints);
QueueDemo.printQ(priorityQueue);
第二个对 PriorityQueue的调用使用了由 Collections.reverseOrder() (Java 5 中新添加的)产生的反序的 Comparator。正常是从小到大,这样就是从大到小了。
```java
String fact = "EDUCATION SHOULD ESCHEW OBFUSCATION";
List<String> strings =
Arrays.asList(fact.split(""));
PriorityQueue<String> stringPQ =new PriorityQueue<>(strings);
QueueDemo.printQ(stringPQ);
分割字符串的代码
Set<Character> charSet = new HashSet<>();
for(char c : fact.toCharArray())
charSet.add(c); // Autoboxing
PriorityQueue<Character> characterPQ = new PriorityQueue<>(charSet);
QueueDemo.printQ(characterPQ);
过滤重复值的代码
summary
1.数组将数字索引与对象相关联。它保存类型明确的对象,因此在查找对象时不必对结果做类型转换。它可以是多维的,可以保存基本类型的数据。虽然可以在运行时创建数组,但是一旦创建数组,就无法更改数组的大小。
2.Collection 保存单一的元素,而 Map 包含相关联的键值对。使用 Java 泛型,可以指定集合中保存的对象的类型,因此不能将错误类型的对象放入集合中,并且在从集合中获取元素时,不必进行类型转换。各种 Collection 和各种 Map 都可以在你向其中添加更多的元素时,自动调整其尺寸大小。集合不能保存基本类型,但自动装箱机制会负责执行基本类型和集合中保存的包装类型之间的双向转换。
3.像数组一样, List 也将数字索引与对象相关联,因此,数组和 List 都是有序集合。
4.如果要执行大量的随机访问,则使用 ArrayList ,如果要经常从表中间插入或删除元素,则应该使用 LinkedList 。
5.队列和堆栈的行为是通过 LinkedList 提供的。
6.Map 是一种将对象(而非数字)与对象相关联的设计。 HashMap 专为快速访问而设计,而 TreeMap 保持键始终处于排序状态,所以没有 HashMap 快。 LinkedHashMap 按插入顺序保存其元素,但使用散列提供快速访问的能力。
7.Set 不接受重复元素。 HashSet 提供最快的查询速度,而 TreeSet 保持元素处于排序状态。 LinkedHashSet 按插入顺序保存其元素,但使用散列提供快速访问的能力。
8.不要在新代码中使用遗留类 Vector ,Hashtable 和 Stack 。
浏览一下Java集合的简图