最近有一個需求是這樣的,java
根據鍵值對存儲類型數據,也算是數據緩存塊模塊功能設計。編程
一個鍵對應多個值。每個鍵的值類型相同,可是每一個不一樣的鍵之間類型不必定相同。緩存
Java 設計以下安全
HashMap<String, ArrayList<Object>>
java把數據添加到集合中性能
TestIterator tIterator = new TestIterator(); ArrayList<Object> objs = new ArrayList<>(); objs.add("sdfsfdsfdsf"); objs.add("sdfsfdsfdsf"); objs.add("sdfsfdsfdsf"); objs.add("sdfsfdsfdsf"); tIterator.getList().put("Key1", objs); objs = new ArrayList<>(); objs.add(1); objs.add(2); objs.add(3); objs.add(4); tIterator.getList().put("Key2", objs); objs = new ArrayList<>(); objs.add(new String[]{"1", ""}); objs.add(new String[]{"2", ""}); objs.add(new String[]{"3", ""}); objs.add(new String[]{"4", ""}); tIterator.getList().put("Key3", objs);
添加進數據緩存後,而後讀取數據,咱們先忽略,緩存集合的線程安全性問題,ui
{ ArrayList<Object> getObjs = tIterator.getList().get("Key1"); for (Object getObj : getObjs) { System.out.println("My is String:" + (String) getObj); } } { ArrayList<Object> getObjs = tIterator.getList().get("Key2"); for (Object getObj : getObjs) { System.out.println("My is int:" + (int) getObj); } } { ArrayList<Object> getObjs = tIterator.getList().get("Key3"); for (Object getObj : getObjs) { String[] strs = (String[]) getObj; System.out.println("My is String[]:" + strs[0] + " : " + strs[1]); } }
咱們發現。使用的時候,每一個地方都須要轉換。this
(String[]) getObj; (int) getObj (String) getObj
一樣代碼須要重複寫,那麼咱們是否能夠封裝一次呢?spa
public <T> ArrayList<T> getValue(String keyString, Class<T> t) { ArrayList<T> rets = new ArrayList<>(); ArrayList<Object> getObjs = _List.get(keyString); if (getObjs != null) { for (Object getObj : getObjs) { //if (getObj instanceof T) { rets.add((T) getObj); //} } } return rets; }
這裏我發現一個問題,不支持泛型檢查,據我很淺的知識瞭解到,java算是動態類型數據。.net
而且是僞泛型類型因此不支持泛型類型斷定線程
這點很不爽了,爲啥不能泛型類型斷定。也許是我知識淺薄~!望前輩指點;
再次查看調用
{ ArrayList<String> value = tIterator.getValue("Key1", String.class); for (String value1 : value) { } } { ArrayList<Integer> value = tIterator.getValue("Key1", Integer.class); for (Integer value1 : value) { } } { ArrayList<String[]> value = tIterator.getValue("Key1", String[].class); for (String[] value1 : value) { } }
稍稍以爲清爽了一點吧。固然,我這裏都是用到基礎類型,若是用到複雜類型,和滿篇調用的時候才能體現出這段代碼的優越性。
更加的符合面向對象編程的重構行和複用性;
但是上面代碼,不曉得你們注意沒,出現一個問題,那就是每一次調用都再一次的聲明瞭
ArrayList<T> rets = new ArrayList<>();
對象,若是是須要考慮性能問題的時候,咱們確定不能不能這樣。每次調用都須要從新分配ArrayList的內存空間。而且在 ArrayList.add() 的時候每一次都在檢查ArrayList的空間夠不夠,不夠,再次開闢新空間。重組。
雖然這個動做很快,但是若是咱們緩存的數據過多。那麼狀況可就不同了。且伴隨着每一次的調用都是一個消耗。訪問次數過多的話。那麼程序的的性能勢必會變的低下。
再次考慮,是否能夠用迭代器實現功能呢?
查看了一下迭代器實現方式,我沒法完成我需求的迭代器功能。只能依葫蘆畫瓢,實現了一個自定義的迭代器功能。
class TestIterator { HashMap<String, ArrayList<Object>> _List = new HashMap<>(); public TestIterator() { } public <T> ArrayList<T> getValue(String keyString, Class<T> t) { ArrayList<T> rets = new ArrayList<>(); ArrayList<Object> getObjs = _List.get(keyString); if (getObjs != null) { for (Object getObj : getObjs) { //if (getObj instanceof T) { rets.add((T) getObj); //} } } return rets; } public HashMap<String, ArrayList<Object>> getList() { return _List; } public void setList(HashMap<String, ArrayList<Object>> _List) { this._List = _List; } public <T> TestIterator.ArrayIterator<T> iterator(String keyString, Class<T> t) { return new ArrayIterator<T>(keyString); } public class ArrayIterator<T> { private String key; int index = -1; private T content; public ArrayIterator(String key) { this.key = key; } public void reset() { index = -1; } public T getContent() { //忽略是否存在鍵的問題 Object get = TestIterator.this._List.get(key).get(index); return (T) get; } public boolean next() { //忽略是否存在鍵的問題 if (index >= TestIterator.this._List.get(key).size()) { reset(); return false; } index++; return true; } } }
調用方式
{ TestIterator.ArrayIterator<String> iterator1 = tIterator.iterator("Key1", String.class); while (iterator1.next()) { String content = iterator1.getContent(); } } { TestIterator.ArrayIterator<Integer> iterator1 = tIterator.iterator("Key2", Integer.class); while (iterator1.next()) { Integer content = iterator1.getContent(); } } { TestIterator.ArrayIterator<String[]> iterator = tIterator.iterator("Key3", String[].class); while (iterator.next()) { String[] content = iterator.getContent(); } }
總結了一些問題,
Java的泛型是僞泛型,底層其實都是經過object對象,裝箱拆箱完成的。
/** * Shared empty array instance used for empty instances. */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access
這個從我目前代碼設計思路我能理解。若是讓我本身設計。也行也會設計如此。
可是沒法理解爲何使用泛型沒法類型斷定;
我這個自定義的迭代器沒法使用 for each 功能;
說了這麼多。接下來咱們看看.net;
C# 設計以下
Dictionary<String, List<Object>>
TestIterator tIterator = new TestIterator(); List<Object> objs = new List<Object>(); objs.Add("sdfsfdsfdsf"); objs.Add("sdfsfdsfdsf"); objs.Add("sdfsfdsfdsf"); objs.Add("sdfsfdsfdsf"); tIterator["Key1"] = objs; objs = new List<Object>(); objs.Add(1); objs.Add(2); objs.Add(3); objs.Add(4); tIterator["Key2"] = objs; objs = new List<Object>(); objs.Add(new String[] { "1", "" }); objs.Add(new String[] { "2", "" }); objs.Add(new String[] { "3", "" }); objs.Add(new String[] { "4", "" }); tIterator["Key3"] = objs;
因爲有了以上 Java 部分的代碼和思路,那麼咱們直接建立自定義迭代器就能夠了;
public class TestIterator : Dictionary<String, List<Object>> { public IEnumerable<T> CreateEnumerator<T>(String name) { if (this.ContainsKey(name)) { List<Object> items = this[name]; foreach (var item in items) { if (item is T) { Console.WriteLine(item); yield return (T)item; } } } } }
查看調用方式
foreach (var item in tIterator.CreateEnumerator<String>("tt1")) { Console.WriteLine(item + "艹艹艹艹"); }
輸出結果:
yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf
查看對比一下調用方式
foreach (var item in tIterator.CreateEnumerator<String>("Key1")) { Console.WriteLine("foreach : " + item); } Console.WriteLine("===============分割線=============="); IEnumerable<String> getObjs = tIterator.CreateEnumerator<String>("Key1").ToList(); foreach (var item in getObjs) { Console.WriteLine("foreach : " + item); }
主要上面的兩張調用方式。輸出結果徹底不一樣
yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf ===============分割線============== yield return : sdfsfdsfdsf yield return : sdfsfdsfdsf yield return : sdfsfdsfdsf yield return : sdfsfdsfdsf foreach : sdfsfdsfdsf foreach : sdfsfdsfdsf foreach : sdfsfdsfdsf foreach : sdfsfdsfdsf
能夠看出第二種調用方式是所有返回了數據,那麼就和以前java的設計一模一樣了.
public <T> ArrayList<T> getValue(String keyString, Class<T> t) { ArrayList<T> rets = new ArrayList<>(); ArrayList<Object> getObjs = _List.get(keyString); if (getObjs != null) { for (Object getObj : getObjs) { //if (getObj instanceof T) { rets.add((T) getObj); //} } } return rets; }
雖然表面看上去沒有聲明List對象,可實際底層依然作好了底層對象的分配對性能也是有所消耗;
C# 迭代器實現了泛型類型斷定檢測;
且沒有多餘的開銷,
總結。
Java的自定義迭代。多出了一下定義
private String key; int index = -1; private T content;
不支持泛型的類型判別;
C# 的自定義迭代器 沒什麼多餘的代碼開銷,但其實底層依然作了咱們類使用Java的自定義代碼段。只是咱們無需再定義而已。
C# 支持 泛型類型的判別。
其實這些都是語法糖的問題。沒有什麼高明或者不高明之處。可是在面對快速開發和高性能程序的基礎上,優點劣勢。本身判別了。
以上代碼不足之處,還請各位看客之處。
不喜勿碰~!~!~!