Thinking in Java 中闪耀的星星(三)

5 篇文章 0 订阅
5 篇文章 0 订阅

41.容器集合的选择
List容器无非分为两大种,基于数组和基于链表:数组有索引,所以查找快,链表插入删除不需要移动全部元素,插入删除快。
ArrayList/Vector查找快,LinkedList插入删除元素快。而Queue什么都快,但是队列先入先出,没有其他集合灵活。
Set也是大体分为两种,基于红黑树的Tree和基于hash算法的Hash(Set的元素是不能重复的,List可以重复)。
HashSet各方面的速度稍微比TreeSet快。但TreeSet元素的排列是经过排序的。
Map的情况与set类似(HashMap和TreeMap),一般来讲,程序选择基于Hash的多。
42.回收容器元素的引用
如果遇到容器过于庞大或者硬件配置太低而需要回收元素的地址,可以选择使用更加利于回收机制的容器。SoftReference,weakReference,PhantomReference。
具体用法看下面的例子:

import java.lang.ref.*;
import java.util.*;
class VeryBig{
    private static final int SIZE=10000;
    private long[] la=new long[SIZE];
    private String ident;
    public VeryBig(String id){ident=id;}
    public String toString(){return ident;}
    protected void finalize(){System.out.println("Finalizing"+ident);}
}
public class References{
    private static ReferenceQueue<VeryBig> rq=new ReferenceQueue<VeryBig>();
    public static void checkQueue(){
        Reference<? extends VeryBig> inq=rq.poll();
        if(inq!=null)
            System.out.println("In queue:"+ inq.get());
    }
    public static void main(String[] args){
        int size=10;
        if(args.length>0)
            size=new Integer(args[0]);
        LinkedList<SoftReference<VeryBig>> sa=new LinkedList<SoftReference<VeryBig>>();
        for(int i=0;i<size;i++){
            sa.add(new SoftReference<VeryBig>(new VeryBig("Soft "+i),rq));
            System.out.println("Just created:"+sa.getLast());
            checkQueue();
        }
        LinkedList<WeakReference<VeryBig>> wa=new LinkedList<WeakReference<VeryBig>>();
        for(int i=0;i<size;i++){
            wa.add(new WeakReference<VeryBig>(new VeryBig("weak "+i),rq));
            System.out.println("Just created:"+wa.getLast());
            checkQueue();
        }
        SoftReference<VeryBig> s=new SoftReference<VeryBig>(new VeryBig("Soft"));
        WeakReference<VeryBig> w=new WeakReference<VeryBig>(new VeryBig("Weak"));
        System.gc();
        LinkedList<PhantomReference<VeryBig>> pa=new LinkedList<PhantomReference<VeryBig>>();
        for(int i=0;i<size;i++){
            pa.add(new PhantomReference<VeryBig>(new VeryBig("Phantom "+i),rq));
            System.out.println("Just created:"+pa.getLast());
            checkQueue();
        }
    }
}/*Output
Just created:java.lang.ref.SoftReference@76ea7776
Just created:java.lang.ref.SoftReference@1b4920f8
Just created:java.lang.ref.SoftReference@5e1387c6
Just created:java.lang.ref.SoftReference@5437086a
Just created:java.lang.ref.SoftReference@69099257
Just created:java.lang.ref.SoftReference@7366c3a0
Just created:java.lang.ref.SoftReference@5fb57890
Just created:java.lang.ref.SoftReference@2fe6707
Just created:java.lang.ref.SoftReference@c1dfe1a
Just created:java.lang.ref.SoftReference@515632d
Just created:java.lang.ref.WeakReference@3f2221f6
Just created:java.lang.ref.WeakReference@59e3bddb
Just created:java.lang.ref.WeakReference@76c5a2f7
Just created:java.lang.ref.WeakReference@294e430c
Just created:java.lang.ref.WeakReference@5113de03
Just created:java.lang.ref.WeakReference@6f54c08a
Just created:java.lang.ref.WeakReference@252cdd20
Just created:java.lang.ref.WeakReference@246972f1
Just created:java.lang.ref.WeakReference@6f93ee4
Just created:java.lang.ref.WeakReference@558fee4f
Just created:java.lang.ref.PhantomReference@2f995c9a
In queue:null
FinalizingWeak
Just created:java.lang.ref.PhantomReference@7d8e9adf
In queue:null
Finalizingweak 9
Finalizingweak 8
Finalizingweak 7
Finalizingweak 6
Finalizingweak 5
Finalizingweak 4
Finalizingweak 3
Finalizingweak 2
Finalizingweak 1
Finalizingweak 0
Just created:java.lang.ref.PhantomReference@1d59e6df
In queue:null
Just created:java.lang.ref.PhantomReference@79444986
In queue:null
Just created:java.lang.ref.PhantomReference@72373a9c
In queue:null
Just created:java.lang.ref.PhantomReference@7e91259
In queue:null
Just created:java.lang.ref.PhantomReference@56b3951d
In queue:null
Just created:java.lang.ref.PhantomReference@2802cf63
In queue:null
Just created:java.lang.ref.PhantomReference@507d811a
In queue:null
Just created:java.lang.ref.PhantomReference@5fa6fb3e
In queue:null
*///~

43.Collection的特性
Collection为List,Set,Queue的始祖,有一些不错的特性,比如翻转元素,替换元素,移动元素…
看例子吧:

import java.util.*;
public class Utilities{
    static List<String> list=Arrays.asList("one two three Four five six one".split(" "));
    public static void main(String[] args){
        System.out.println(list);
        System.out.println("'list' disjoint (Four)?:"+Collections.disjoint(list,Collections.singletonList("Four")));
        System.out.println("max: "+Collections.max(list));
        System.out.println("min: "+Collections.min(list));
        System.out.println("max a/ comparator: "+Collections.max(list,String.CASE_INSENSITIVE_ORDER));
        System.out.println("min a/ comparator: "+Collections.min(list,String.CASE_INSENSITIVE_ORDER));
        List<String> sublist=Arrays.asList("Four five six".split(" "));
        System.out.println("indexOfSubList: "+Collections.indexOfSubList(list,sublist));
        System.out.println("lastIndexofList: "+Collections.lastIndexOfSubList(list,sublist));
        Collections.replaceAll(list,"one","Yo");
        System.out.println("replaceAll: "+list);
        Collections.reverse(list);
        System.out.println("reverse: "+list);
        Collections.rotate(list,3);
        System.out.println("rotate: "+list);
        List<String> source=Arrays.asList("in the matrix".split(" "));
        Collections.copy(list,source);
        System.out.println("copy: "+list);
        Collections.swap(list,0,list.size()-1);
        System.out.println("swap: "+list);
        Collections.shuffle(list,new Random(47));
        System.out.println("shuffled: "+list);
        Collections.fill(list,"pop");
        System.out.println("fill: "+list);
        System.out.println("frequency of 'pop': "+Collections.frequency(list,"pop"));
        List<String> dups=Collections.nCopies(3,"snap");
        System.out.println("dups: "+dups);
        System.out.println("'list' disjoint 'dups'?: "+Collections.disjoint(list,dups));
        Enumeration<String> e=Collections.enumeration(dups);
        Vector<String> v=new Vector<String>();
        while(e.hasMoreElements())
            v.addElement(e.nextElement());
        ArrayList<String> arrayList=Collections.list(v.elements());
        System.out.println("arrayList: "+arrayList);
    }
}/*Output
[one, two, three, Four, five, six, one]
'list' disjoint (Four)?:false
max: two
min: Four
max a/ comparator: two
min a/ comparator: five
indexOfSubList: 3
lastIndexofList: 3
replaceAll: [Yo, two, three, Four, five, six, Yo]
reverse: [Yo, six, five, Four, three, two, Yo]
rotate: [three, two, Yo, Yo, six, five, Four]
copy: [in, the, matrix, Yo, six, five, Four]
swap: [Four, the, matrix, Yo, six, five, in]
shuffled: [six, matrix, the, Four, Yo, five, in]
fill: [pop, pop, pop, pop, pop, pop, pop]
frequency of 'pop': 7
dups: [snap, snap, snap]
'list' disjoint 'dups'?: true
arrayList: [snap, snap, snap]
*///~

43.重写hashCode()方法
为什么要重写hashCode():如果现有的集合满足不了你,想自己写一个或者修改现有集合,就必须要重写hashCode(),因为像Map的key都要有一个hashCode()。
看代码,理解思路就好:

import java.util.*;
public class CountedString{
    private static List<String> created=new ArrayList<String>();
    private String s;
    private int id=0;
    public CountedString(String str){
        s=str;
        created.add(s);
        for(String s2 : created)
            if(s2.equals(s))
                id++;
    }
    public String toString(){
        return "String:"+s+"id:"+id+"hasCode():"+hashCode();
    }
    public int hashCode(){
        int result=17;
        result=37*result+s.hashCode();
        result=37*result+id;
        return result;
    }
    public boolean equals(Object o){
        return o instanceof CountedString && s.equals(((CountedString)o).s)&&id==((CountedString)o).id;
    }
    public static void main(String[] args){
        Map<CountedString,Integer> map=new HashMap<CountedString,Integer>();
        CountedString[] cs=new CountedString[5];
        for(int i=0;i<cs.length;i++){
            cs[i]=new CountedString("hi");
            map.put(cs[i],i);
        }
        System.out.println(map);
        for(CountedString cstring:cs){
            System.out.println("Looking up"+cstring);
            System.out.println(map.get(cstring));
        }
    }
}/*Output
{String:hiid:1hasCode():146447=0, String:hiid:2hasCode():146448=1, String:hiid:3hasCode():146449=2, String:hiid:4hasCode():146450=3, String:hiid:5hasCode():146451=4}
Looking upString:hiid:1hasCode():146447
0
Looking upString:hiid:2hasCode():146448
1
Looking upString:hiid:3hasCode():146449
2
Looking upString:hiid:4hasCode():146450
3
Looking upString:hiid:5hasCode():146451
4
*///~

44.如何把类写成只读形式
final关键字:

public class Pair<K,V>{
       public final K key;
       public final V value;
       public Pair(K k,V v){
            key=k;
            value=v;
       }
}

45.Map的底层实现
Map其实是基于List的,看代码吧:

import java.util.*;
public class SlowMap<K,V> extends AbstractMap<K,V>{
    private List<K> keys=new ArrayList<K>();
    private List<V> values=new ArrayList<V>();
    public V put(K key,V value){
        V oldValue=get(key);
        if(!key.contains(key)){
            keys.add(key);
            values.add(value);
        }else{
            values.set(keys.indexOf(key).value);
        }
        return oldValue;
    }
    public V get(Object key){
        if(!keys.contains(key))
           return null;
        return values.get(keys.indexOf(key));
    }
    public Set<Map.Entry<K,V>> entrySet(){
        Set<Map.Entry<K,V>> set=new HashSet<Map.Entry<K,V>>();
        Iterator<K> ki=keys.iterator();
        iterator<V> vi=values.iterator();
        while(ki.hasNext())
           set.add(new MapEntry<K,V>(ki.next(),vi.next()));
        return set;
    }
    public static void main(String[] args){
        SlowMap<String,String> m=new SlowMap<String,String>();
        m.putAll(Countries.capitals(15));
        System.out.println(m);
        System.out.println(m.get('BULGARIA')); 
        System.out.println(m.entrySet()); 
    }
}/*Output
*///~

46.io流反映基本类型的长度
在书上有个蛮有趣的demo,io流把byte转化为其他基本类型的:

import java.nio.*;
public class ViewBuffers{
    public static void main(String[] args){
        ByteBuffer bb=ByteBuffer.wrap(
            new byte[]{0,0,0,0,0,0,0,'a'});
        bb.rewind();
        System.out.println("Byte Buffer");
        while(bb.hasRemaining())
            System.out.print(bb.position()+" ->"+bb.get()+", ");
        System.out.println();
        CharBuffer cb=((ByteBuffer)bb.rewind()).asCharBuffer();
        System.out.println("Char Buffer");
        while(cb.hasRemaining())
            System.out.print(cb.position()+" ->"+cb.get()+", ");
        System.out.println();
        FloatBuffer fb=((ByteBuffer)bb.rewind()).asFloatBuffer();
        System.out.println("Float Buffer");
        while(fb.hasRemaining())
            System.out.print(fb.position()+" ->"+fb.get()+", ");
        System.out.println();
        IntBuffer ib=((ByteBuffer)bb.rewind()).asIntBuffer();
        System.out.println("Int Buffer");
        while(ib.hasRemaining())
            System.out.print(ib.position()+" ->"+ib.get()+", ");
        System.out.println();
        LongBuffer lb=((ByteBuffer)bb.rewind()).asLongBuffer();
        System.out.println("Long Buffer");
        while(lb.hasRemaining())
            System.out.print(lb.position()+" ->"+lb.get()+", ");
        System.out.println();
        ShortBuffer sb=((ByteBuffer)bb.rewind()).asShortBuffer();
        System.out.println("Short Buffer");
        while(sb.hasRemaining())
            System.out.print(sb.position()+" ->"+sb.get()+", ");
        System.out.println();
        DoubleBuffer db=((ByteBuffer)bb.rewind()).asDoubleBuffer();
        System.out.println("Double Buffer");
        while(db.hasRemaining())
            System.out.print(db.position()+" ->"+db.get()+", ");
        System.out.println();
    }
}/*Output
har Buffer
0 ->, 1 ->, 2 ->, 3 ->a, 
Float Buffer
0 ->0.0, 1 ->1.36E-43, 
Int Buffer
0 ->0, 1 ->97, 
Long Buffer
0 ->97, 
Short Buffer
0 ->0, 1 ->0, 2 ->0, 3 ->97, 
Double Buffer
0 ->4.8E-322,
*///~ 

47.io流不同类型读写文件的速度
io流采用装饰者模式,层层装饰。java发展到现在,有”old” io 和”new” io。书里有个测试平台,基于模板方法模式写的,用来测试MappedIO和边准io流DataInputStream/DataOutputStream的速度,结果的比例是差不多的,但是时间根据硬件和操作系统会有所不同:

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class MappedIO{
    private static int numOfInts=4000000;
    private static int numOfUbuffInts=200000;
    private abstract static class Tester{
        private String name;
        public Tester(String name){this.name=name;}
        public void runTest(){
            System.out.println(name+": ");
            try{
                long start=System.nanoTime();
                test();
                double duration=System.nanoTime()-start;
                System.out.format("%.2f\n",duration/1.0e9);
            }catch(IOException e){
                throw new RuntimeException(e);
            }
        }
        public abstract void test() throws IOException;
    }
    private static Tester[] tests={
        new Tester("Stream Write"){
            public void test() throws IOException{
                DataOutputStream dos=new DataOutputStream(
                    new BufferedOutputStream(
                        new FileOutputStream(new File("temp.tmp"))));
                for(int i=0;i<numOfInts;i++)
                    dos.writeInt(i);
                dos.close();
            }
        },
        new Tester("Mapped Write"){
             public void test() throws IOException{
                 FileChannel fc=new RandomAccessFile("temp.tmp","rw").getChannel();
                 IntBuffer ib=fc.map(FileChannel.MapMode.READ_WRITE,0,fc.size()).asIntBuffer(); 
                 for(int i=0;i<numOfInts;i++)
                     ib.put(i);
                 fc.close();        
             }
        },
        new Tester("Stream Read"){
             public void test() throws IOException{
                 DataInputStream dis=new DataInputStream(
                     new BufferedInputStream(
                         new FileInputStream("temp.tmp"))); 
             for(int i=0;i<numOfInts;i++)
                 dis.readInt();
             dis.close();  
             }
        },
        new Tester("Mapped Read"){
             public void test() throws IOException{
                 FileChannel fc=new FileInputStream(
                     new File("temp.tmp")).getChannel();
                 IntBuffer ib=fc.map(FileChannel.MapMode.READ_ONLY,0,fc.size()).asIntBuffer();
                 while(ib.hasRemaining())
                     ib.get();
                 fc.close();
             }
        },
        new Tester("Stream Read/Write"){
             public void test() throws IOException{
                 RandomAccessFile raf=new RandomAccessFile(
                     new File("temp.tmp"),"rw");
                 raf.writeInt(1);
                 for(int i=0;i<numOfUbuffInts;i++){
                     raf.seek(raf.length()-4);
                     raf.writeInt(raf.readInt());
                 }
                 raf.close();
             }
        },
        new Tester("Mapped Read/Write"){
             public void test() throws IOException{
                 FileChannel fc=new RandomAccessFile(
                     new File("temp.tmp"),"rw").getChannel();
                 IntBuffer ib=fc.map(FileChannel.MapMode.READ_WRITE,0,fc.size()).asIntBuffer();
                 ib.put(0);
                 for(int i=1;i<numOfUbuffInts;i++)
                     ib.put(ib.get(i-1));
                 fc.close();
             }
        }
    };
    public static void main(String[] args){
        for(Tester test:tests)
            test.runTest();
    }
}/*Output
Stream Write: 
0.92
Mapped Write: 
0.05
Stream Read: 
0.83
Mapped Read: 
0.02
Stream Read/Write: 
2.70
Mapped Read/Write: 
0.03
*///~

48.文件锁
对于一些共享文件,在多线程中需要保证一致性(类似与jdbc事务)或者不想文件被其他人访问,就需要对文件上锁。下面的例子是锁住部分文件内容的:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;
public class LockingMappedFiles{
    static final int LENGTH =0x8FFFFFF;//128M
    static FileChannel fc;
    public static void main(String[] args) throws IOException{
        fc=new RandomAccessFile("test.dat","rw").getChannel();
        MappedByteBuffer out=fc.map(FileChannel.MapMode.READ_WRITE,0,LENGTH);
        for(int i=0;i<LENGTH;i++)
            out.put((byte)'x');
        new LockAndModify(out,0,0+LENGTH/3);
        new LockAndModify(out,LENGTH/2,LENGTH/2+LENGTH/4); 
    }
    private static class LockAndModify extends Thread{
        private ByteBuffer buff;
        private int start,end;
        LockAndModify(ByteBuffer mbb,int start,int end){
            this.start=start;
            this.end=end;
            mbb.limit(end);
            mbb.position(start);
            buff=mbb.slice();
            start();
        }
        public void run(){
            try{
                FileLock fl=fc.lock(start,end,false);
                System.out.println("Locked: "+start+" to "+end);
                while(buff.position()<buff.limit()-1)
                    buff.put((byte)(buff.get()+1));
                fl.release();
                System.out.println("Release: "+start+" to "+end);
            }catch(IOException e){
                throw new RuntimeException(e);
            }
        }
    }
}/*Output
Locked: 0 to 50331647
Locked: 75497471 to 113246206
Release: 75497471 to 113246206
Release: 0 to 50331647
*///~

49.文件压缩
io流可以将文件压缩,在网络传输中尤为重要,io流可以将文件压缩为GZIP,ZIP,Jar…
1).压缩为jar:
jar cf myJarFile.jar *.class //把该目录下所有的.class文件打包压缩进一个叫myJarFile.jar的jar包里面
jar tf myJarFile.jar //打印出myJarFile.jar文件的所有子文件(.class)
jar tvf myJarFile.jar //与上一句一样,多打印出 myJarFile.jar所有子文件的详细信息(日期,大小,用户等信息)
2).压缩为GZIP/ZIP,下面以GZIP为例

import java.util.zip.*;
import java.io.*;
public class GZIPcompress{
    public static void main(String[] args) throws IOException{
        if(args.length==0){
            System.out.println(
                "Usage:\nGZIPcompress file\n"+
                "\tUses GZIP compression to compress"+
                "the file to test.gz");
        System.exit(1);
        }
        BufferedReader in=new BufferedReader(
            new FileReader(args[0]));
        BufferedOutputStream out=new BufferedOutputStream(
            new GZIPOutputStream(new FileOutputStream("test.gz")));
        System.out.println("Writing file");
        int c;
        while((c=in.read())!=-1)
            out.write(c);
        in.close();
        out.close();
        System.out.println("Reading file");
        BufferedReader in2=new BufferedReader(
            new InputStreamReader(new GZIPInputStream(
                new FileInputStream("test.gz"))));
        String s;
        while((s=in2.readLine())!=null)
            System.out.println(s);
    }
}

50.序列化
io流在网络传输中的作用很重要,有些时候,为了减少创建类的开销加快传输速度,需要将对象转化为持久态(类似与J2EE中Hibernate的持久态session)。下面的例子是读取文件时将对象序列化,往后的对文件对该对象就可以直接操作:

import java.util.*;
import java.io.*;
class Data implements Serializable{
    private int n;
    public Data(int n){this.n=n;}
    public String toString(){return Integer.toString(n);}
}
public class Worm implements Serializable{
    private static Random rand=new Random(47);
    private Data[] d={
        new Data(rand.nextInt(10)),
        new Data(rand.nextInt(10)),
        new Data(rand.nextInt(10))
    };
    private Worm next;
    private char c;
    public Worm(int i,char x){
        System.out.println("Worm constructor: "+i);
        c=x;
        if(--i>0)
           next=new Worm(i,(char)(x+1));
    }
    public Worm(){
        System.out.println("Default constructor");
    }
    public String toString(){
        StringBuilder result=new StringBuilder(":");
        result.append(c);
        result.append("(");
        for(Data dat : d)
           result.append(dat);
        result.append(")");
        if(next!=null)
        result.append(next);
        return result.toString();
    } 
    public static void main(String[] args) throws ClassNotFoundException,IOException{
        Worm w=new Worm(6,'a');
        System.out.println("w= "+w);
        ObjectOutputStream out=new ObjectOutputStream(
            new FileOutputStream("worm.out"));
        out.writeObject("Worm storage\n");
        out.writeObject(w);
        out.close();
        ObjectInputStream in=new ObjectInputStream(
            new FileInputStream("worm.out"));
        String s=(String)in.readObject();
        Worm w2=(Worm)in.readObject();
        System.out.println(s+" w2= "+w2);
        ByteArrayOutputStream bout=new ByteArrayOutputStream();
        ObjectOutputStream out2=new ObjectOutputStream(bout);
        out2.writeObject("Worm storage\n");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2=new ObjectInputStream(
            new ByteArrayInputStream(bout.toByteArray()));
        s=(String)in2.readObject();
        Worm w3=(Worm)in2.readObject();
        System.out.println(s+" w3= "+w3);
    }   
}/*Output
Worm constructor: 6
Worm constructor: 5
Worm constructor: 4
Worm constructor: 3
Worm constructor: 2
Worm constructor: 1
w= :a(853):b(119):c(802):d(788):e(199):f(881)
Worm storage
 w2= :a(853):b(119):c(802):d(788):e(199):f(881)
Worm storage
 w3= :a(853):b(119):c(802):d(788):e(199):f(881)
*///~
但是一些时候,有些机密信息不想轻易被其他文件读取修改,可以通过transient关键字指明不被序列化,比如登录中的密码:
import java.util.concurrent.*;
import java.io.*;
import java.util.*;
public class Logon implements Serializable{
    private Date date=new Date();
    private String username;
    private transient String password;
    public Logon(String name,String pwd){
        username=name;
        password=pwd;
    }
    public String toString(){
        return "logon info: \n username: "+username+
            "\n date: "+date+"\n password: "+password;
    }
    public static void main(String[] args) throws Exception{
        Logon a=new Logon("Hulk","myLittlePony");
        System.out.println("Logon a="+a);
        ObjectOutputStream o=new ObjectOutputStream(
            new FileOutputStream("Logon.out"));
        o.writeObject(a);
        o.close();
        TimeUnit.SECONDS.sleep(1);
        ObjectInputStream in=new ObjectInputStream(
            new FileInputStream("Logon.out"));
        a=(Logon)in.readObject();
        System.out.println("Logon a="+a);
    }
}/*Output
Logon a=logon info: 
 username: Hulk
 date: Mon Aug 08 17:14:34 CST 2016
 password: myLittlePony
Logon a=logon info: 
 username: Hulk
 date: Mon Aug 08 17:14:34 CST 2016
 password: null
*///~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值