A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 321哈哈哈 中级黑马   /  2017-11-17 03:34  /  692 人查看  /  1 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

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)
获取指定的环境变量值。

1 个回复

倒序浏览
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马