天天看點

《Think in Java》閱讀筆記·第二卷

内部類

從外部類的非靜态方法之外的任意位置建立某個内部類的對象,都需要以外部類.内部類的格式指明對象類型

内部類擁有外圍類的所有元素的通路權

外圍類對象建立一個内部類對象時,此内部類對象會秘密地捕獲一個指向那個外圍類對象的引用。

在外圍類靜态方法中建立内部類對象源碼如下:

public class InnerClass {
    class InnerClass1{
        public InnerClass1() {
            int i1=;
            System.out.println("InnerClass1");
        }
        public void f1() {
            System.out.println("InnerClass1_f1");
        }
    }
    class InnerClass2{
        int i2=;
        public InnerClass2() {
            System.out.println("InnerClass2");
        }
        public void f2() {
            System.out.println("InnerClass2_f2");
        }
    }
    public InnerClass1 getInnerClass1() {
        return new InnerClass1();
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        InnerClass.InnerClass1 i1=ic.getInnerClass1();
        i1.f1();

        InnerClass.InnerClass2 i2=ic.new InnerClass2();
        i2.f2();
    }
}
           

InnerClass1

InnerClass1_f1

InnerClass2

InnerClass2_f2

匿名内部類

匿名類版:

new NoNameClass(){
    public void f3() {
        System.out.println("f3");
    }
}
           

完整版:

interface INoNameClass{
        public void f3();
    }
    class NoNameClass implements INoNameClass{
        public void f3() {
            System.out.println("f3");
        }
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        INoNameClass innc=ic.new NoNameClass();
    }
           

注意:

abstract class NoNameClass2{
        public NoNameClass2(int i){
            System.out.println("構造器:"+i);
        }
        public abstract void f2();
        //{System.out.println("{     }");}
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        ic.new NoNameClass2(){
            {System.out.println("{     }");}
            public void f2() {
                System.out.println("f2");
            }
        };
    }
           

構造器:53

{ }

abstract class NoNameClass2{
        public NoNameClass2(int i){
            System.out.println("構造器:"+i);
        }
        public abstract void f2();
        //{System.out.println("{     }");}
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        ic.new NoNameClass2(){
            {System.out.println("{     }");}
            public void f2() {
                System.out.println("f2");
            }
        };
    }
           

{ }

構造器:53

匿名内部類若想要通路外部對象,則該對象需要加final

引用為什麼匿名内部類隻能通路其所在方法中的final類型的局部變量?中的一段話:

匿名内部類不能通路外部類方法中的局部變量,除非該變量被聲明為final類型

  1. 這裡所說的“匿名内部類”主要是指在其外部類的成員方法内定義的同時完成執行個體化的類,若其通路該成員方法中的局部變量,局部變量必須要被final修飾。原因是編譯器實作上的困難:内部類對象的生命周期很有可能會超過局部變量的生命周期。

  2. 局部變量的生命周期:當該方法被調用時,該方法中的局部變量在棧中被建立,當方法調用結束時,退棧,這些局部變量全部死亡。而内部類對象生命周期與其它類對象一樣:自建立一個匿名内部類對象,系統為該對象配置設定記憶體,直到沒有引用變量指向配置設定給該對象的記憶體,它才有可能會死亡(被JVM垃圾回收)。是以完全可能出現的一種情況是:成員方法已調用結束,局部變量已死亡,但匿名内部類的對象仍然活着。

  3. 如果匿名内部類的對象通路了同一個方法中的局部變量,就要求隻要匿名内部類對象還活着,那麼棧中的那些它要所通路的局部變量就不能“死亡”。

  4. 解決方法:匿名内部類對象可以通路同一個方法中被定義為final類型的局部變量。定義為final後,編譯器會把匿名内部類對象要通路的所有final類型局部變量,都拷貝一份作為該對象的成員變量。這樣,即使棧中局部變量已經死亡,匿名内部類對象照樣可以拿到該局部變量的值,因為它自己拷貝了一份,且與原局部變量的值始終保持一緻(final類型不可變)。

隻有該局部變量為不可變時,即為final時才能保證資料的可靠性。

嵌套類

普通内部類不能包含靜态字段和方法,而嵌套類可以

嵌套類與static字段和方法都是一編譯便存在,并且記憶體位址不再變化,直到gc回收。

接口内部的類
public class Staticer implements IStaticer{
    @Override
    public void fun() {
    }
    public static final void main(String...args) {
        IStaticer is=new Staticer();
        is.fun();
    }
}
           
IStaticer_fun

内部類的作用

當存在抽象類時實作多重繼承

public class Multipler extends Multipler1{
    private AMultipler newClass() {
        return new AMultipler(){
            @Override
            public void f1() {
                System.out.println("AMultipler_f1");
            }
        };
    }
    public static final void main(String[] args) {
        Multipler m=new Multipler();
        m.f2();
        AMultipler am=m.newClass();
        am.f1();
    }
}
class Multipler1{
    public void f2() {
        System.out.println("Multipler_f2");
    }
}
abstract class AMultipler{
    public abstract void f1();
}
           

Multipler_f2

AMultipler_f1

控制架構是一類特殊的應用程式架構,用來解決響應事件的需求

主要用來響應事件的系統被稱做事件驅動系統

回調

類A調用類B的方法b,然後類B的方法b調用類A的方法a

interface ICallBacker{
    public void fun();
}
class CallBacker2 implements ICallBacker{
    @Override
    public void fun() {
        System.out.println("CallBacker2_ICallBackers_fun");
    }
}
class CallBacker1{
    public void fun() {
        System.out.println("CallBacker1_fun");
    }
    private class InnerClass implements ICallBacker{
        public void fun() {
            System.out.println("CallBacker1_ICallBackers_fun");
            CallBacker1.this.fun();
        }
    }
    public InnerClass getInnerClass(CallBacker1 cb) {
        return cb.new InnerClass();
    }
}
public class CallBacker{
    public static final void main(String...args) {
        CallBacker1 cb1=new CallBacker1();
        ICallBacker ic1=cb1.getInnerClass(cb1);
        ic1.fun();
        ICallBacker ic2=new CallBacker2();
        ic2.fun();
    }
}
           

CallBacker1_ICallBackers_fun

CallBacker1_fun

CallBacker2_ICallBackers_fun

在内部類InnerClass的fun方法中提供了一個CallBacker1鈎子進行回調。

内部類的繼承

由于内部類含有指向外圍類的引用,應以以下方式使用繼承

public class InnerExtend extends InnerExtend1.InnerExtend2{
    public InnerExtend(InnerExtend1 ie1) {
        //super();
        ie1.super();
    }
    public static final void main(String...args) {
        InnerExtend1 ie1=new InnerExtend1();
        InnerExtend ie=new InnerExtend(ie1);
    }
}
class InnerExtend1{
    public InnerExtend1() {
        System.out.println("InnerExtend1");
    }
    class InnerExtend2{
        public InnerExtend2() {
            System.out.println("InnerExtend2");
        }
    }
}
           

InnerExtend1

InnerExtend2

若将ie1.super()改成super()會報以下錯誤:

No enclosing instance of type InnerExtend1 is available due to some intermediate constructor invocation

容器

《Think in Java》閱讀筆記·第二卷

注意:List接口位于java.util包中,而在java.awt 包中也有一個List類

Set:隻有元素不存在才會添加

TreeSet:按照值大小的順序進行排序

LinkedHashSet:按照添加的順序進行排序

HashSet:無序散亂地分布

List:不考慮重複,會按照添加順序進行排序

容器選擇:

要進行大量的随機通路:ArrayList

要從表中間插入或删除元素:LinkedList

各種Queue隊列以及棧的行為,可由LinkedList建構

注意:

不應該适用vector,Hashtable和stack等過時的類

public static final void main(String...args) {
        Vector v=new Vector();
        System.out.print("showSet: ");
        v.showSet();
        System.out.println();
        System.out.print("showList: ");
        v.showList();
    }
    private void showList() {
        Collection<Integer> cl=new ArrayList<Integer>();
        Collection<Integer> cls=new ArrayList<Integer>();
        cls.addAll(Arrays.<Integer>asList(,,,,));
        Collections.addAll(cls, ,,,,);
        cl.add();
        cl.add();
        cl.add();
        cl.add();
        cl.add();
        cl.add();
        for(Integer i:cl) {
            System.out.print(i+" ");
        }
        System.out.print("|");
        for(Integer i:cls) {
            System.out.print(i+" ");
        }
    }
    private void showSet() {
        Collection<Integer> cl=new LinkedHashSet<Integer>();
        Collection<Integer> clt=new TreeSet<Integer>();
        cl.add();
        cl.add();
        cl.add();
        cl.add();
        cl.add();
        cl.add();
        clt.addAll(Arrays.asList(,,,,));
        for(Integer i:cl) {
            System.out.print(i+" ");
        }
        System.out.print("|");
        for(Integer i:clt) {
            System.out.print(i+" ");
        }
    }
           

showSet: 1 2 3 8 5 |1 3 6 7

showList: 1 1 2 3 8 5 |1 2 3 4 5 6 7 8 9 10

在後續會探究各集合之間的算法實作和性能差別

《Think in Java》閱讀筆記·第二卷

注:點線框表示接口,實線框表示類,空心箭頭的點線表示類實作了接口,實心箭頭表示某個類可以生産箭頭所指向類的對象。

疊代器

疊代器為輕量級對象也屬于一種設計模式

不必為數量和類型操心:

private void showIterator() {
        List<Integer> l=new ArrayList<Integer>();
        for(int i=;i<;i++) {
            l.add(i);
        }
        Iterator<Integer> i=l.iterator();
        Set<Integer> s=new HashSet<Integer>();
        for(int j=;j<;j++) {
            s.add(j);
        }
        display(s.iterator());
        display(l.iterator());
        i=l.iterator();
        while(i.hasNext()) {
            i.next();
            i.remove();
        }
        System.out.println(l.toString());
    }
    private void display(Iterator i) {
        while(i.hasNext()) {
            System.out.print(i.next()+" ");
        }
        System.out.print("\n");
    }
           

0 1 2 3 4

0 1 2 3 4

[]

注意:疊代器對象要先調用一次next才是list容器中的第一個資料

ListIterator

一種隻适用于List容器可雙向周遊的疊代器

棧(疊加棧)

一個後進先出(LIFO)容器

用LinkedList實作棧存儲:

public class Stacker {
    public static final void main(String...args) {
        String str="";
        MyStack ms=new MyStack();
        List<String> l=new ArrayList<String>(Arrays.asList("+","U","+","n","+","x","-","-"));;
        System.out.println(l.toString());
        Iterator i=l.iterator();
        while(i.hasNext()) {
            str=(String) i.next();
            if(str.equals("+")) {
                ms.push(i.next());
            }
            else if(str.equals("-")) {
                ms.pop();
            }
        }
        System.out.println(ms.toString());
    }
}
class MyStack<T>{
    public MyStack() {  
    }
    LinkedList<T> stack=new LinkedList<T>();
    public void push(T t) {
        stack.add(t);
    }
    public T pop() {
        //先進後出特性
        return stack.removeLast();
    }
    public boolean isEmpty() {
        return stack.isEmpty();
    }
    public String toString() {
        return stack.toString();
    }
}
           

[+, U, +, n, +, x, -, -]

[x]

隊列

一個典型的先進先出(FIFO)的容器

LinkedList向上轉型為Queue實作隊列

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
public class Queuer {
    static void printer(Queue q) {
        while(q.peek()!=null) {
            //先進先出特性
            System.out.print(q.remove()+" ");
        }
        System.out.println();
    }
    public static final void main(String...args) {
        Random rand=new Random();
        Queue q=new LinkedList<Integer>();
        int r=;
        for(int i=;i<;i++) {
            r=rand.nextInt();
            q.offer(r);
            System.out.print(r+" ");
        }
        System.out.println();
        printer(q);
    }
}
           

16 7 16 1 8 15 12 2 10 0

16 7 16 1 8 15 12 2 10 0

PriorityQueue的使用

PriorityQueue

該類可以設定隊列元素中的優先級

import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
public class Queuer {
    public static final void main(String...args) {
        comparatorer();
    }
    private static void comparatorer() {
        Comparator<Oer> comparator=new Comparator<Oer>() {
            @Override
            public int compare(Oer o1, Oer o2) {
                // TODO Auto-generated method stub
                if(o1.getPriority()>o2.getPriority()) {
                    //o2
                    return -;
                }
                else if(o2.getPriority()>o1.getPriority()) {
                    //o1
                    return ;
                }
                return ;
            }
        };
        Oer o1=new Oer("o1",);
        Oer o2=new Oer("o2",);
        PriorityQueue<Oer> pq=new PriorityQueue<Oer>(,comparator);
        pq.offer(o1);
        pq.offer(o2);
        System.out.println(pq.toString());
    }
}
class Oer{
    private int priority;
    private String name;
    public Oer(String name,int priority) {
        this.priority=priority;
        this.name=name;
    }
    @Override
    public String toString(){
        return name;
    }
    public int getPriority() {
        return priority;
    }
}
           
[o2, o1]

通過繼承AbstractCollection重寫疊代類

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class Collectioner {
    public static final void main(String...args) {
        List<Integer> list=new ArrayList<Integer>();
        list.addAll(Arrays.asList(,,,,));
        Collectioner_child cc=new Collectioner_child(list);
        Iterator<Integer> i=cc.iterator();
        System.out.println(i.next());
    }
}
class Collectioner_child extends AbstractCollection{
    List<Integer> list;
    public Collectioner_child(List<Integer> list) {
        this.list=list;
    }
    @Override
    public Iterator iterator() {
        // TODO Auto-generated method stub
        return new Iterator() {
            private int index;
            @Override
            public boolean hasNext() {
                // TODO Auto-generated method stub
                return index < list.size();
            }
            @Override
            public Object next() {
                // TODO Auto-generated method stub
                return list.get(index++);
            }
        };
    }
    @Override
    public int size() {
        // TODO Auto-generated method stub
        return list.size();
    }
}
           
1

如果直接繼承Collection接口需要實作大量的方法,而繼承實作過Collection方法的AbstrctCollection抽象類隻需要再實作兩個抽象方法即可

通過該執行個體可進一步了解疊代器的使用。

自定義foreach規則

第一種(建立一個繼承于ArrayList的自定義疊代器類)

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Iteratorer {
    public Iteratorer() {

    }
    public static final void main(String...args) {
        List<String> list=new ArrayList<String>(Arrays.asList("12","33","22"));
        MyIterator<String> mi=new MyIterator<String>(list);
        for(String i:mi) {
            System.out.print(i+" ");
        }
        System.out.print("\n");
        for(String i:mi.reversed()) {
            System.out.print(i+" ");
        }
        System.out.println();
        //java 8中的疊代循環
        mi.reversed().forEach(System.out::print);
    }

}
class MyIterator<T> extends ArrayList<T>{
    public MyIterator(List<T> list) {
        super(list);
    }
    public Iterable<T> reversed() {
        return new Iterable<T>() {
            @Override
            public Iterator<T> iterator() {
                // TODO Auto-generated method stub
                return new Iterator<T>() {
                    int current=size()-;
                    @Override
                    public boolean hasNext() {
                        // TODO Auto-generated method stub
                        return current>-;
                    }
                    @Override
                    public T next() {
                        // TODO Auto-generated method stub
                        return get(current--);
                    }
                };
            }
        };
    }   
}
           

12 33 22

22 33 12

223312

第二種(直接在主類實作Iterator和Iterable接口)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Iterator2 implements Iterator<String>,Iterable<String>{
    private List<String> list;
    private int size;
    public static final void main(String...ags) {
        Iterator2 i2=new Iterator2();
        i2.list=new ArrayList<String>();
        i2.list.addAll(Arrays.asList("a","v","c","d"));
        i2.size=i2.list.size();
        for(String s:i2) {
            System.out.print(s+" ");
        }
    }

    @Override
    public Iterator<String> iterator() {
        // TODO Auto-generated method stub
        return this;
    }

    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        return size>;
    }

    @Override
    public String next() {
        // TODO Auto-generated method stub
        return list.get(--size);
    }

}
           
d c v a