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的,这里很好的诠释了静态函数中如何调用非静态方法——显然静态方法是类相关的,非静态方法是对象相关的,因此非静态方法可以直接调用静态方法,这样并不会产生错误,而静态方法要调用非静态方法必须是对象相关的,而不能直接调用方法。

posted on 2016-04-16 16:51  Matrixin  阅读(373)  评论(0编辑  收藏  举报

导航