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

时间: 2024-10-17 08:06:09

Java项目源码学习笔记(二):Path的相关文章

Java项目源码学习笔记(三):PathMatcher

先来看看内部类Node节点: private static class Node{ private HashMap<String, Node> mMap; private int mKind = NOT_FOUND; Node addChild(String segment){ if(null == mMap){ mMap = new HashMap<String, Node>(); }else{ Node node = mMap.get(segment); if(node !=

Java项目源码学习笔记(一):IdentityCache

import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; public class IdentityCache<K, V>{ private final HashMap<K, Entry<K,V>> mWeakMap = new Ha

Java集合源码学习笔记(二)ArrayList分析

Java集合源码学习笔记(二)ArrayList分析 >>关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫"ArrayList",因为ArrayList内部是用一个数组存储元素值,相当于一个可变大小的数组,也就是动态数组. (1)继承和实现继承了AbstractList,实现了List:ArrayList是一个数组队列,提供了相关的添加.删除.修

Java集合源码学习笔记(三)LinkedList分析

前面学习了ArrayList的源码,数组是顺序存储结构,存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O(1),数组的特点是寻址容易,插入和删除困难.今天学习另外的一种常用数据结构LinkedList的实现,LinkedList使用链表作为存储结构,链表是线性存储结构,在内存上不是连续的一段空间,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N),链表的特点是寻址困难,插入和删除容易.所有的代码都基于JDK 1.6. >>关于LinkedLis

Java集合源码学习笔记(四)HashMap分析

ArrayList.LinkedList和HashMap的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据的存储,这两者有不同的应用场景,数组的特点是:寻址容易,插入和删除困难:链表的特点是:寻址困难,插入和删除容易:哈希表的实现结合了这两点,哈希表的实现方式有多种,在HashMap中使用的是链地址法,也就是拉链法.看下面这张流传很广的图, 拉链法实际上是一种链表数组的结构,由数组加链表组成,在这个长度为16的数

yii2源码学习笔记(二十)

Widget类是所有部件的基类.yii2\base\Widget.php 1 <?php 2 /** 3 * @link http://www.yiiframework.com/ 4 * @copyright Copyright (c) 2008 Yii Software LLC 5 * @license http://www.yiiframework.com/license/ 6 */ 7 8 namespace yii\base; 9 10 use Yii; 11 use Reflectio

yii2源码学习笔记(二)

yii\base\Component代码详解 <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace yii\base; use Yii; /** * Object is the base class that implements the

Java多线程之JUC包:ReentrantLock源码学习笔记

若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5627539.html ReentrantLock是JUC包提供的一种可重入独占锁,它实现了Lock接口.与Semaphore类似,ReentrantLock也提供了两种工作模式:公平模式&非公平模式,也是通过自定义两种同步器FairSync&NonfairSync来实现的. 源代码: /* * ORACLE PROPRIETARY/CONF

Java多线程之JUC包:ReentrantReadWriteLock源码学习笔记

若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5634701.html ReentrantLock提供了标准的互斥操作,但在应用中,我们对一个资源的访问有两种方式:读和写,读操作一般不会影响数据的一致性问题.但如果我们使用ReentrantLock,则在需要在读操作的时候也独占锁,这会导致并发效率大大降低.JUC包提供了读写锁ReentrantReadWriteLock,使得读写锁分离,在上述情