3 foreach
foreach(底层是迭代器)无法得到索引
public interface Iterable<T>
实现这个接口允许对象成为 "foreach" 语句的目标
可以用于迭代数组和任何Collection对象
(但数组不是一个Iterable对象)
(定义一个方法, 参数为Iterable类型, 数组对象不能作为参数传递)
(要使其成为一个Iterable, 必须手动转换)
(Arrays.asList(数组))
任何自定义的类, 如果实现了Iterable, 都能用foreach语法遍历
(Iterable接口定义了抽象方法iterator(), 返回一个Iterator对象)
(Iterator是一个迭代器接口)
(定义了几个迭代方法: next, hasNext, remove)
(所以, 写这个类就要实现iterator())
(用匿名内部类的方式, 返回Iterator对象)
(一个Iterator实现类的对象)
(匿名内部类中只要实现了next和hasNext方法,就能用foreach成功遍历该类对象)
(对于不想实现的remove方法有这样一种应付的写法)
(throw new UnsupportedOperationException();)
自定义类示例:
class RandomShapeGenerator implements Iterable<Shape> {
private Random rand = new Random(47);
private final int quantity;
RandomShapeGenerator(int quantity) {
this.quantity = quantity;
}
public Iterator<Shape> iterator() {
//匿名内部类, return的是Iterator实现类对象
return new Iterator<Shape>() {
private int count;
public boolean hasNext() {
//判断是否有下一个可返回的对象
//依据的是生成的Shape数量是否达到上限
return count < quantity;
}
public Shape next() {
++count;
//得到的是随机生成的Shape对象
//并不是存储再容器中的
return nextShape();
}
//没有实现的实现
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
private Shape nextShape() {
switch (rand.nextInt(3)) {
default:
case 0:
return new Circle();
case 1:
return new Square();
case 2:
return new Triangle();
}
}
}
public class E31_IterableRandomShapeGenerator {
public static void main(String[] args) {
RandomShapeGenerator rsg = new RandomShapeGenerator(10);
//rsg内部没有容器, 仍可以产生遍历的效果
//所以只要实现Iterable接口就能用foreach语法
//利用hasNext和next方法就能拿到对象中的值
//被遍历对象可以是包含值的容器, 或者是值的生成器
//本例中是个生成器
for (Shape shape : rsg)
System.out.println(shape.getClass().getSimpleName());
}
}
4
向上转型可以像作用于其他类型一样作用于泛型
5添加一组元素
两个工具类的静态方法:
Arrays.asList(可变参数或者数组对象)
返回一个受指定数组支持的固定大小的List
(可以使用set方法改变元素;但不能使用add添加元素)
List对象会使用底层数组作为其物理实现
Collections.shuffle(该List对象)会使底层数组顺序发生同步改变
List的类型会是所有参数的类型的最近父类
(可以加泛型,指定返回的List的类型是更高等级的父类)
这个List对象可以作为另一个集合构造方法的参数
(在声明语句赋值,添加了一组元素)
(这个新集合可以放心修改,不会改变List的底层数组)
Collections.addAll(Collection对象,可变参数或数组)
将一组元素(第二个参数)添加到集合(第一个参数)中
(元素的类型要是集合类型或其子类)
运行更快,是首选方式
(只是要分两步完成:创建空集合;添加一组元素)
Collection对象.addAll(另一个Collection对象)
成员方法
上面两个方法使用可变参数,更灵活
(Map集合只能靠以另一个Map对象为参数的构造方法添加一组元素)
public class AddingGroups {
public static void main(String[] args) {
//静态方法asList
Collection<Integer> c =
new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));
Integer[] moreInts = { 6, 7, 8, 9, 10 };
//成员方法addAll
c.addAll(Arrays.asList(moreInts));
//静态方法addAll
Collections.addAll(c, 11, 12, 13, 14, 15);
Collections.addAll(c, 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 because the
// underlying array cannot be resized.
}
} ///:~
class Animal {}
class Cat extends Animal {}
class Bosimao extends Cat {}
class Jiafeimao extends Cat {}
class Dog extends Animal {}
class Pig extends Animal {}
public class AsListInference {
public static void main(String[] args) {
List<Animal> a1 = Arrays.asList(
new Dog(), new Pig(), new Cat());
// Won't compile:
//asList返回的是List<Cat>
// List<Animal> a2 = Arrays.asList(
// new Bosimao(), new Jiafeimao());
// Compiler says:
// found : java.util.List<Cat>
// required: java.util.List<Animal>
// Collections.addAll() doesn't get confused:
//用静态方法addAll不会有上面的问题
List<Animal> a3 = new ArrayList<Animal>();
Collections.addAll(a3, new Bosimao(), new Jiafeimao());
// Give a hint using an
// explicit type argument specification:
//在asList上加泛型
List<Animal> a4 = Arrays.<Animal>asList(
new Bosimao(), new Jiafeimao());
}
} ///:~
6容器的打印
数组:使用(工具类的)Arrays.toString()
产生数组的可打印表示;直接打印是地址值
集合:直接打印(toString已重写)
Collection:[]
Map:{}
7 List<Integer>注意事项
使用方法的时候要明确参数是索引还是元素
(Integer的自动包装功能会使两者混淆)
(在需要int索引的位置,即时传Integer对象,也是索引)
重载方法(参数可以是元素或者索引)要有个区分
remove(Integer.valueOf(1))是删除元素
remove(1)是删索引(位置的元素)
8 优化
优化是个很棘手的问题
最好的策略就是置之不顾,直到你发现需要担心它了
例如:
在List中间插入元素时
对LinkedList是廉价操作
对ArrayList是高昂操作
应该意识到这个问题,但不要因噎废食
直到你在一个ArrayList中执行很多插入操作,并且程序开始变慢
那么你的List实现可能就是罪魁祸首
(发现此类瓶颈的最佳方式是使用仿真器??)
9 for中的迭代器
for(Iterator<Gerbil> it = gerbils.iterator();
it.hasNext();
it.next().hop());
for(Iterator<Object> it = sequence.iterator();
it.hasNext();)
System.out.print(it.next() + " ");
for循环的格式:
for(初始化表达式;循环控制条件表达式;循环后操作表达式){
语句体;
}
(所以)
(1语句体可以放到循环后操作表达式的位置)
(2循环后操作表达式也可以放到语句体的位置)
(自己的位置空着)
(第2种用法可以更灵活地控制每次循环”控制变量”增量的多少)
(如下例)
for(int i = 0; i < data.length;)
switch(data[i++]) {//这里加了1
case '+' : stack.push(data[i++]);//这种情况的话总共加2
break;
case '-' : System.out.print(stack.pop());//只加了1
}
10
移位运算符>>
相当于除以2
<< 乘以2
11 LinkedList
实现List
间接实现了Queue接口
Queue接口定义的方法:
element() offer() peek() poll() remove() 简单易混
添加了可以 使其用作栈 队列 双端队列 的方法??
这些方法有的只是名称不同,或者功能有少许差异
以使得这些名字在特定用法的上下文环境中更加适用??
(特别是在Queue中)
相似的方法:(再查API)
getFirst() element() peek(),前两个完全相同
removeFirst() remove() poll(),前两个功能相同
removeLast()
addLast() add() offer()
addFirst()
(区别经常是特定条件时会报错还是给返回值)
12 栈 Stack
“栈”通常是指”后进先出”的容器
压栈push
弹栈pop
经常用来对表达式求值??
LinkedList的功能使其完全可以作为栈来使用
(其实现的Queue接口的方法可以用来模拟栈的行为)
(也许因为它能够被其他容器模拟出来,所以java没有Stack接口??)
(但LinkedList还有其他功能)
也可以自定义一个纯粹的栈类(容器类)
public class Stack<T> {
private LinkedList<T> storage = new LinkedList<T>();
public void push(T v) { storage.addFirst(v); }
public T peek() { return storage.getFirst(); }
public T pop() { return storage.removeFirst(); }
public boolean empty() { return storage.isEmpty(); }
public String toString() { return storage.toString(); }
}
使用了代理(复用类的一种方式)
(拥有一个LinkedList成员对象storage)
(用storage作为自己对外接口的底层实现)
(外界看到的是Stack,但实际干活的是一个LinkedList对象)
(即选择性地拥有了LinkedList的接口,但没有使用继承)
定义类的时候使用了泛型
<T>表示Stack是一个参数化( parameterized)类型
(表示这是一个可以指定泛型的类)
(因为该类的一个成员在创建的时候需要指定泛型)
(即实际使用的时候需要类型参数)
(这个参数是加在类上的,不是方法上)
其中的T为类型参数,在类被使用时会被实际类型替换
这个新类的用法
Stack<String> stack = new Stack<String>();
(泛型其实是指定给其内部的LinkedList的)
stack.push("hello");//压栈
stack.pop();//弹栈
java.util.Stack类是java提供的栈类.
作者认为它设计欠佳(用了继承而不是代理)
认为上面的自定义类是更好的Stack
注意: 要导包或者写全名,以确保使用了正确的Stack类
13
“可选操作”??
实现类里面可以不实现该方法
14 “适配器方法”惯用法
(AdapterMethodIdiom)
idiom 习语
“适配器”部分来自设计模式
当你有一个接口, 并需要另一个接口, 编写适配器可以解决问题
这里的适配器是一个方法
示例:
需求: 用foreach反向迭代一个Iterable类
需要的接口: 还是Iterable接口
但方法返回的对象(匿名内部类)能提供新型迭代器(匿名内部类)
迭代器遍历的还是原对象的元素
方法在朝着需求的方向进行适配
代码:
class ReversibleArrayList<T> extends ArrayList<T> {
public ReversibleArrayList(Collection<T> c) { super(c); }
public Iterable<T> reversed() {
//匿名内部类
return new Iterable<T>() {
public Iterator<T> iterator() {
//匿名内部类
return new Iterator<T>() {
//反向迭代的逻辑
int current = size() - 1;//最后元素的索引
public boolean hasNext() { return current > -1; }
//size和get方法是本类继承自ArrayList的
//所以返回的迭代器对象是和原对象一对一联结的
public T next() { return get(current--); }
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
};
}
}
public class AdapterMethodIdiom {
public static void main(String[] args) {
ReversibleArrayList<String> ral =
new ReversibleArrayList<String>(
Arrays.asList("To be or not to be".split(" ")));
//正常遍历
for(String s : ral)
System.out.print(s + " ");
System.out.println();
//反向遍历
for(String s : ral.reversed())
System.out.print(s + " ");
}
}
15
标记接口:
java.util.RandomAccess
附着到了ArrayList上, 没有附着到LinkedList上
为那些
想要根据
所使用的特定的List
而动态修改其行为
的算法提供了信息??
方法补充
(用到索引的,都是List接口定义的;没用到的,是Collection定义的)
(判断、移除、求索引、求交集等方法都调用了元素对象的equals方法)
List<Pet> sub = pets.subList(1, 4);
(List接口)截取list
没有重载方法,截取到最后:第二个参数为pets.size()
但,截取到的子List是以父List为支持的
如果对父List做了结构性修改,子list会失效
再对子List进行访问和修改会报并发修改异常
(ConcurrentModificationException)
对子list的修改会反映在父list上
(同步增、删、修改)
Collections.shuffle(sub, rand);
(工具类)rand是随机源:Random对象
(Collection接口)boolean retainAll(Collection<?> c)
仅在列表中保留指定 collection 中所包含的元素
(如果因为调用此方法Collection发生了变化, 返回true)
(求“交集”)
(Collection接口)boolean removeAll(Collection<?> c)
从列表中移除指定 collection 中包含的其所有元素
(List接口)E set(int index, E element)
用指定元素替换列表中指定位置的元素
(List接口)boolean addAll(int index, Collection<? extends E> c)
将指定 collection 中的所有元素都插入到列表中的指定位置
(Collection接口)boolean addAll(Collection<? extends E> c)
添加指定collection中的所有元素到此列表的结尾
(Collection接口)Object[] toArray()
转数组
(Collection接口)<T> T[] toArray(T[] a)
加参数,转为指定类型数组
(List接口)int indexOf(Object o)
返回此列表中首次出现的指定元素的索引
或如果此列表不包含元素,则返回 -1
(String也有这方法)
(Integer类)static Integer valueOf(int i)
返回一个表示指定的 int 值的 Integer 实例
(Integer类)static Integer valueOf(String s)
throws NumberFormatException
返回保存指定的 String 的值的 Integer 对象
(Collections工具类)
static <T> void sort(List<T> list, Comparator<? super T> c)
根据指定比较器产生的顺序对指定列表进行排序
(sort方法的参数只能是List对象)
(String类的字段)
static Comparator<String> CASE_INSENSITIVE_ORDER
一个对 String 对象进行排序的 Comparator
作用与 compareToIgnoreCase 相同
(排序, ABab变为AaBb)
(Arrays工具类)
static void sort(Object[] a)
根据元素的自然顺序对指定对象数组按升序进行排序。
(还有参数为基本数据类型数组的重载版本)
(Character类)
static char toLowerCase(char ch)
(System类)
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src和dest应是两个数组
两个int是两个起始位置
static Map<String,String> getenv()
返回一个不能修改的当前系统环境的字符串映射视图
(所有环境变量放到一个Map中)
(该方法被认为与操作系统耦合度过紧, 违反”一次编译, 到处运行”的原则)
(仍然提供它这一事实表明, java的设计者更加务实了)
static String getenv(String name)
获取指定的环境变量值。
|
|