zoukankan      html  css  js  c++  java
  • Java项目源码学习笔记(二):Path

    import java.lang.ref.WeakReference;
    import java.util.ArrayList;
    
    public class Path{
    	private static Path sRoot = new Path(null, "ROOT");
    
    	private final Path mParent;
    	private final String mSegment;
    	private WeakReference<Object> mObject;
    	private IdentityCache<String, Path> mChildren;
    
    	private Path(Path parent, String segment){
    		mParent = parent;
    		mSegment = segment;
    	}
    
    	public Path getChild(String segment){
    		synchronized(Path.class){
    			if(mChildren == null){
    				mChildren = new IdentityCache<String, Path>();	
    			}else{
    				Path p = mChildren.get(segment);
    				if(p != null)return p;
    			}	
    
    			Path p = new Path(this, segment);
    			mChildren.put(segment, p);
    			return p;
    		}	
    	}
    
    	public Path getParent(){
    		synchronized(Path.class){
    			return mParent;	
    		}	
    	}
    
    	public void setObject(Object object){
    		synchronized(Path.class){
    			mObject = new WeakReference<Object>(object);	
    		}	
    	}
    
    	public Object getObject(){
    		synchronized(Path.class){
    			return (mObject == null) ? null : mObject.get();	
    		}	
    	}
    
    	@Override
    	public String toString(){
    		synchronized(Path.class){
    			StringBuilder sb = new StringBuilder();
    			String[] segments = split();
    			for(int i = 0; i < segments.length; i++){
    				sb.append("/");
    				sb.append(segments[i]);
    			}
    			return sb.toString();
    		}	
    	}
    
    	public static Path fromString(String s){
    		synchronized(Path.class){
    			String[] segments = split(s);
    			Path current = sRoot;
    			for(int i =0; i < segments.length; i++){
    				current = current.getChild(segments[i]);	
    			}
    			return current;
    		}	
    	}
    
    	public String[] split(){
    		synchronized(Path.class){
    			int n = 0;
    			for(Path p = this; p != sRoot; p = p.mParent){
    				n++;	
    			}
    			String[] segments = new String[n];
    			int i = n - 1;
    			for(Path p = this; p != sRoot; p = p.mParent){
    				segments[i--] = p.mSegment;	
    			}
    			return segments;
    		}	
    	}
    
    	public static String[] split(String s){
    		int n = s.length();
    		if(n == 0)return new String[0];
    		if(s.charAt(0) != '/'){
    			throw new RuntimeException("malformed pa");	
    		}
    		ArrayList<String> segments = new ArrayList<String>();
    		int i = 1;
    		while(i < n){
    			int brace = 0;
    			int j;
    			for(j = i; j < n; j++){
    				char c = s.charAt(j);
    				if(c == '{')++brace;
    				else if(c == '}')--brace;
    				else if(brace == 0 && c == '/')break;
    			}
    			if(brace != 0){
    			 throw new RuntimeException("un");	
    			}
    			segments.add(s.substring(i,j));
    			i = j + 1;
    		}
    		String[] result = new String[segments.size()];
    		segments.toArray(result);
    		return result;
    	}
    }
    

     细节说明:

    1. 构造函数是private的,这是因为Path要构建的是一个数据链表,而不仅仅是构造函数本身构建的对象。

        Path对象节点结构如图:它包括一个引用指向mParent,同时包含一个容器对象mChildren,这个容器对象中保存着指向子节点的引用,这个引用与mSegment构成容器的键值对。

    如上可知这是一个双向链表数据结构

    2.

    public Path getChild(String segment){
    	synchronized(Path.class){
    		if(mChildren == null){
    			mChildren = new IdentityCache<String, Path>();	
    		}else{
    			Path p = mChildren.get(segment);
    			if(p != null)return p;
    		}	
    
    		Path p = new Path(this, segment);
    		mChildren.put(segment, p);
    		return p;
    	}	
    }
    

    分析一个函数,可以把它代入到实际的应用场景中去:

    结合下一个将要说明的public static Path fromString(String s),我们知道Path链表数据对象是由getChild函数构建起来的,所以在构建对象的时候mChildren肯定是null的。例如String s = "/aaa/bbb/123"构建的path数据对象如下

    path1, path2, path3三个对象便是通过getChild()生成的。

    看看上面的链表,这是String s = "/aaa/bbb/123"对应的Path对象的样子。

     之所以用双向链表替代String,则是因为需要利用双向链表的结构优势:假设Path p = Path.fromString(“/aaa/bbb”)表示一个集合,那么Path child = p.getChild("123")则可以表示这个集合对应的一个子集

    3.

    public static Path fromString(String s){
    	synchronized(Path.class){
    		String[] segments = split(s);
    		Path current = sRoot;
    		for(int i =0; i < segments.length; i++){
    			current = current.getChild(segments[i]);	
    		}
    		return current;
    	}	
    }
    

    需要说明的是如2中的表格,通过这个静态类生成的path是最后一个child:path3,但是这里要再次申明这是一个链表结构数据,而不是单纯的只看当前对象。

    细节说明:(a)、synchronzied(Path.class),这是类中静态函数是并发函数时的保护方式;(b)、fromString是static的,getChild是非static的,这里很好的诠释了静态函数中如何调用非静态方法——显然静态方法是类相关的,非静态方法是对象相关的,因此非静态方法可以直接调用静态方法,这样并不会产生错误,而静态方法要调用非静态方法必须是对象相关的,而不能直接调用方法。

  • 相关阅读:
    从Go语言编码角度解释实现简易区块链——打造公链
    CSAPP:位操作实现基本运算
    虚拟机Ubuntu系统无法连接网络解决方案
    CSAPP:逆向工程【二进制炸弹】
    分析一套源代码的代码规范和风格并讨论如何改进优化代码
    【Recorder.js+百度语音识别】全栈方案技术细节
    webpack4.0各个击破(5)—— Module篇
    webpack4.0各个击破(4)—— Javascript & splitChunk
    webpack4.0各个击破(3)—— Assets篇
    javascript基础修炼(4)——UMD规范的代码推演
  • 原文地址:https://www.cnblogs.com/fordreamxin/p/5398742.html
Copyright © 2011-2022 走看看