最近有一个需求是这样的,

根据键值对存储类型数据,也算是数据缓存块模块功能设计。

一个键对应多个值。每一个键的值类型相同,但是每个不同的键之间类型不一定相同。

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);

添加进数据缓存后,然后读取数据,我们先忽略,缓存集合的线程安全性问题,

{
            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]);
            }
        }

我们发现。使用的时候,每个地方都需要转换。

(String[]) getObj;
(int) getObj
(String) getObj

同样代码需要重复写,那么我们是否可以封装一次呢?

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算是动态类型数据。

并且是伪泛型类型所以不支持泛型类型判定

这点很不爽了,为啥不能泛型类型判定。也许是我知识浅薄~!望前辈指点;

再次查看调用

{
            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();
            objs.Add();
            objs.Add();
            objs.Add();
            tIterator["Key2"] = objs;

            objs = new List<Object>();
            objs.Add(", "" });
            objs.Add(", "" });
            objs.Add(", "" });
            objs.Add(", "" });
            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# 支持 泛型类型的判别。

其实这些都是语法糖的问题。没有什么高明或者不高明之处。但是在面对快速开发和高性能程序的基础上,优势劣势。自己判别了。

以上代码不足之处,还请各位看客之处。

不喜勿碰~!~!~!

初来乍到 Java 和 .Net 迭代器功能的更多相关文章

  1. 自己实现java中Iterator(迭代器功能)

    今天躺在床上忽然想到一个问题,迭代器的代码是如何实现的?于是乎不由自主的爬起来敲两行代码. List<String> list=new ArrayList<>(2); list ...

  2. Java中Iterator(迭代器)的用法及其背后机制的探究

    在Java中遍历List时会用到Java提供的Iterator,Iterator十分好用,原因是: 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结 ...

  3. 深入理解Java中的迭代器

    迭代器模式:就是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节. 概述 Java集合框架的集合类,我们有时候称之为容器.容器的种类有很多种,比如ArrayList.Li ...

  4. Java中Iterator(迭代器)实现原理

    在Java中遍历List时会用到Java提供的Iterator,Iterator十分好用,原因是: 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结 ...

  5. JAVA实现具有迭代器的线性表(单链表)

    一,迭代器的基本知识: 1,为什么要用迭代器?(迭代:即对每一个元素进行一次“问候”) 比如说,我们定义了一个ADT(抽象数据类型),作为ADT的一种实现,如单链表.而单链表的基本操作中,大部分需要用 ...

  6. Java集合Iterator迭代器的实现

    一.迭代器概述 1.什么是迭代器? 在Java中,有很多的数据容器,对于这些的操作有很多的共性.Java采用了迭代器来为各种容器提供了公共的操作接口.这样使得对容器的遍历操作与其具体的底层实现相隔离, ...

  7. Java集合中迭代器的常用用法

    该例子展示了一个Java集合中迭代器的常用用法public class LinkedListTest { public static void main(String[] args) { List&l ...

  8. 折腾Java设计模式之迭代器模式

    迭代器模式 Provide a way to access the elements of an aggregate object sequentially without exposing its ...

  9. JAVA链表中迭代器的实现

    注:本文代码出自<java数据结构和算法>一书. PS:本文中类的名字定义存在问题,Link9应改为Link.LinkList9应该为LinkList.由于在同包下存在该名称,所以在后面接 ...

随机推荐

  1. 一鼓作气 博客--第一篇 note1

    1. 语言的类型 ,编译型(c,c++),解释型(python,php,ruby,java),编译型可移植性差,优点是运行速度快,解释型语言特点:边执行边翻译,速度慢. 2.翻译官就是机器的解释器,跟 ...

  2. .NET面试题系列[11] - IEnumerable<T>的派生类

    “你每次都选择合适的数据结构了吗?” - Jeffery Zhao .NET面试题系列目录 ICollection<T>继承IEnumerable<T>.在其基础上,增加了Ad ...

  3. 我的ORM汇总

    MyOql是我写的ORM,目前仅支持 MSSql2005+ ,从2009年到今天,已使用过不少项目,之后会写 其它关系数据库的解析器: MySql,Sqlite,Oracle 等. 代码地址(最新版) ...

  4. Nova PhoneGap框架 第九章 控件

    我们的框架中也提供了一些常用的控件,这些控件大多都依赖于我们的框架,也正是在我们的框架下才使得实现这些控件的变得更简单.但是我们的框架是不依赖与这些控件的,如果你用不上这些控件,你完全可以把相关的代码 ...

  5. iOS开发系列—Objective-C之内存管理

    概述 我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是由系统自己管理的,放在栈上).如果一个对象创建并使用后没 ...

  6. .NET垃圾回收 – 原理浅析

    在开发.NET程序过程中,由于CLR中的垃圾回收(garbage collection)机制会管理已分配的对象,所以程序员就可以不用关注对象什么时候释放内存空间了.但是,了解垃圾回收机制还是很有必要的 ...

  7. JavaScript算法(冒泡排序、选择排序与插入排序)

    冒泡排序.选择排序与插入排序复杂度都是二次方级别的,放在一起说吧. 介绍一些学习这三个排序方法的比较好的资料.冒泡排序看<学习JavaScript数据结构与算法>介绍的冒泡排序,选择排序看 ...

  8. 每天一个linux命令(26):用SecureCRT来上传和下载

    用SSH管理linux服务器时经常需要远程与本地之间交互文件.而直接用SecureCRT自带的上传下载功能无疑是最方便的,SecureCRT下的文件传输协议有ASCII.Xmodem.Zmodem.文 ...

  9. Android开发学习之路-Android Studio开发小技巧

    上一次发过了一个介绍Studio的,这里再发一个补充下. 我们都知道,Android Studio的功能是非常强大的,也是很智能的.如果有人告诉你学Android开发要用命令行,你可以告诉他Andro ...

  10. PHP扩展-扩展的生成和编译

    首先说明一下,PHP扩展有两种编译方式:方式一:在编译PHP时直接将扩展编译进去方式二:扩展被编译成.so文件,在php.ini里配置加载路径: 以下开始说明创建PHP扩展并编译的步骤:下载PHP源码 ...