集合-泛型-迭代

集合:

1.集合是Java API所提供的一系列类,可以用于动态存放多个对象。(集合只能存放对象)

2.集合与数组的不同在于,集合是大小可变的序列,而且元素类型可以不受限定,只要是引用类型。

(集合中不能放基本数据类型,但可以放基本数据类型的包装类)

3.集合类使用初始容量和加载因子调整自己的大小。

4.集合类全部支持泛型,是一种数据安全的用法。


Java的集合框架从整体上可以分为两大家族。

1、Collection(接口)家族。该接口下的所有子孙均存储的是单一对象。

2、Map(接口)家族。该接口下的所有子孙均存储的是key-value(键值对)形式的数据。

另外还有三个分支,均是为上述两大家族服务的。

1、Iterator(迭代器)家族。主要用于遍历Colleciton接口的及其子类而设计。

2、Comparator(比较器), 在集合中存储对象时候,用于对象之间的比较

3、Collecitons是工具类。注意该类名带个s,一般就表示工具类。里面提供了N多静态方法,来对Colleciton集合进行操作。//迭代器 


在进行集合遍历之前,应先进行判断,是否后面还有数值(如果没数值,且继续运行的话会出错)

Iterator<引用类型> it = (Collection的引用).iterator();

while(it.hesNext())

{        int a = it.next();//遍历过后的数

        it.remove();//删除遍历过后的数

        c.remove();//这个不能用,因为遍历的时候不能使用集合的方法删除元素

}

System.out.println(it.size());//输出集合中的元素个数

集合:

最常用的集合是ArrayList 类和 LinkedList类 以及Stack类,它们都是List的接口的子类,List是Collection接口的子类。

List集合是有序的

set集合是无需的

有序:指存入的顺序和取出的顺序一致

无序:元素取出的顺序和存入的顺序无关!!


TreeSet:可以自动排序,默认为自然排序(升序)


HashSet:无序


Hash:HashSet集合中的元素使用了的对象的Hash值类存储,集合还自动的维护了一个Hash表,Hash表示存储Hash值。


set:存储特点----存储无序,不重复

HashSet集合是如何保证集合中的元素不重复!!!

Hash表中,一个Hash值代表的地址可能存有几个对象

1.先判断对象的Hash值是否相等。每个对象的Hash值时通过调用每个对象的HashCode方法来获得。当存储元素的时候,先获得hash值,

然后拿着这个hash值区hash表中寻找,如果hash表中不存在与这个对象的hash值相等的hash值,则认为这个对象不重复,存储成功。

人后再把这个hash值存入hash表中。如果hash表中已经存在这个hash值,则进行下面的判断。


2.判断与这个hash值相等的那个对象是不是同一个对象。是使用==这个符号来判断是否是(同一个地址)同一个对象。如果是同一个(地址)对象,则认为重复,

存储失败!!!如果不是同一个地址,然后进行下面的操作。


3.调用要添加的这个对象的equals方法把集合中已经存在的那个hash值相等的那个元素作为参数传入。a.equals(obj),如果返回的是true,

则判断为相同的对象,拒绝添加。


LinkedHashSet:这是一个有序的HashSet

ArrayList.add("待添加的数据");

Stack.push("待添加的数据");//入栈---------add是List用的,虽然Stack也可以用,但一般不用

Stack.pop();//出栈--------返回且删除当前栈顶元素,返回的类型时当前栈顶元素的类型

Stack.peek();//偷看-------返回当前栈顶元素,返回的类型时当前栈顶元素的类型


HashMap<key,value>

        map.put(key,value)//其中map里面的key可以看作是一个set集合。

        key不能为空,(会造成空指针异常),value可以为空。

        当map在map里面put一个key-value时,map里面就有相同的key,以前添加的value会和新出现的value交换。当没有put相同的key-value时,如果输出(

System.out.println(String s = map.put(1,"2")))时,会输出null,没有put相同key的key-value,就不会返回值。

        HashMap中,如果要输出里面的key 或value时。通过迭代key,然后调用get(key)获取value.最后输出。

        第二种方法:调用Map.Entry()方法获取整个(key,value)值。(

HashMap<String,String> map = new HahsMap<String,String>();

        map.put("a","b");

        通过Map的实例,将entry()变为set接口对象

        Set<Entry<String,String>> set = map.entrySet();

        这时,可以之间用foreach输出,调用getKey(),getValue()

        for(Entry<String,String> entry : set){

        输出entry.getKey();entry.getValue();}

        也可以使用迭代器输出

        Iterator<Entry<String,String>> it = set.iterator();

        while(it.hasNext())//判断后面是否有数据){

        //现在可以直接输出it.next();因为整个it就是key-value型的

        }

迭代器:

Iterator----Collection接口的迭代器

在类型是Collection的时候Iterator

ListIterator-----List接口的迭代器

在类型时List的时候用ListIterator


比较器:

如果一个类里面定义了一个TreeSet<引用类型>,那么TreeSet里面的引用类型的类里面就必须实现

Comparable接口,并且实现ComparaTo()方法,如果返回正数,则表示刚进来的数大于第一个数,则放在第一个数的右边)

泛型:

在定义一个类,或方法,或参数,或属性时,可以先不申明类型,用一个大写字母T或G代替。当别的类调用它们时,它们需要什么类型就可以写什么类型,然后T或G就被赋值成了那个所需要的类型。

定义一个泛型类型:

public class Generic<T> { //在类名和{之间来声明泛型类型。


定义一个泛型属性:

        private T f;


定义一个泛型方法:

        public Generic(T f){

                this.f = f;

        }

           public void setF(T f) {//setF方法的参数类型为泛型T

                        this.f = f;

           }


权限修饰符 <泛型类型> 返回值类型(可以泛型) 方法名(泛型类型  参数1){

        }

例如:

        public <T>  T   fun(T f)

        {

                return f;

        }

构造方法:

         public Generic(T f){

                this.f = f;

}

实例化泛型类时必须,必须制定泛型的具体类型。

例如:Generic<String> g = new Generic<String>();

List集合变成数组:

一:首先先定义一个数组(当这个数组中的大小比list.size()大时,多余的大小则会被赋予null,所以一般初始化数组大小时,写0,或者list.size(),写0的话,程序就会自动新建一个数组,不用为0的这个。当你的集合是接收什么类型的,你的数组也必须定义为那种类型,例如:集合是接收Integer类型的,那么数组也必须定义为Integer类型。)成为集合要变成的那个数组

二:再定义一个数组用于接收集合,并用集合对象调用toArray(数组名)方法,其中数组名为第一步创建的数组。


TreeSet使用红黑树结构对加入的元素进行排序 存放,输出时也会按照排序后的顺序输出,所以放入TreeSet中的元素必须是“可排序的”。对象可排序,可排序的不是对象本身,而是对象中的属性。对TreeSet集合进行排序的有两个比较器一个是Comparable接口 该接口必须在需要排序的类中实现,否则会报错。实现该接口中的方法中的参数代表的是集合中的元素,this是代表当前需要加入的元素
@Override
    public int compareTo(Person o) {
        if(this.age > o.age){
            return 1;
        }else if(this.age < o.age){
            return -1;
        }else{
            return 0;
        }
    }
Comparable接口也可以实现不同的排序方式(例如:先按年龄在按身高)

@Override
    public int compareTo(Person o) {
        if(this.age > o.age){
            return 1;
        }else if(this.age < o.age){
            return -1;
        }else{
            if(this.height > o.height){
                return 1;
            }else if(this.height < o.height){
                return -1;
            }else{
                return 0;
            }
        }
    }
另一个是Comparator接口(实现该接口时,不能在是被加入TreeSet集合中的类中实现,需要另外新建一个实现类,或者在使用匿名内部类),然后把自定义的实现类的对象或这匿名内部类的对象传入TreeSet的构造方法内

Comparator<Person> pc = new Comparator<Person>(){

            @Override
            public int compare(Person o1, Person o2) 
{
                if(o1.getAge() > o2.getAge()){
                    return 1;
                }else if(o1.getAge() < 
o2.getAge()){
                    return -1;
                }else{
                    return 0;
                }
            }};
        TreeSet<Person> ts = new TreeSet<Person>(pc);

TreeSet判断是不是同一个对象的方法,是看比较器返回的对象,如果是0的话,就表示两者为同一对象,大于0放在集合中已经存在数的后面,小于0放在前面。

HashSet TreeSet 的底层是HashMap 与 TreeMap,所以这两者的共同之处在于,Map中的key的规则与Set中所要求的规则一致

Collections有一个sort方法,支持List集合的排序输出(从大到小等)(Collections.sort(List<T>,Comparator<T>),可以定义一个匿名内部类然后把对象传给这个方法)还有一个仅带一个参数的Collections.sort(List list)方法,该方法根据元素的自然顺序对指定的List列表按升序排序,List列表中的所有元素都必须实现Comparable接口,否则编译出错。(Integer等类型的数据已经实现过该接口,可以直接Collections.sort(list),数值型会按自然循序-升序排列,如果是String类型的则按它的字典循序排列)当用这个排序对象的时候,那么这个对象就必须实现Comparable接口。

无论是对象、字符串、Integer等,都可以用Comparator接口去为它们排序,List调用Collections.sort(List<T>,Comparator<T>),set构造方法中传入该比较器(set具有一个接受比较器参数类型的构造方法)
如果使用HashSet存储对象,就算对象中实现了Comparable方法,HashSet也不能够给它们排序,(HashSet没有接收比较器的构造方法,所以不能使用Comparator比较器)
HashSet 与 TreeSet的区别:
HashSet与TreeSet阻止元素重复的区别:
如果是对象
1.HashSet先判断对象的HashCode值是否相同,不存在直接添加,存在则进行第二步的判断。
2.如果HashSet在集合中存在,则判断HashCode相同的对象,是不是同一个地址,用==判断,如果不是,则进行第3步,是则存储失败
3.调用要添加的这个对象的equals方法,判断值是否相同。

HashMap与TreeMap中key的值不能重复
他们key与HashSet 和 TreeSet 的原理一样,如果HashMap中的key是自己定义的,那么他应该重写hashcode 和 equals方法
TreeMap中的键(key)应该是可排序的
<think>嗯,用户想了解《Modern C++ Design》这本书中关于编程与设计模式的应用。首先,我需要回忆这本书的核心内容,特别是编程和设计模式结合的部分。记得书中提到了Policy-Based Design,这是通过模板将策略分离,提高代码复用和灵活性。例如,通过模板参数来定义不同的策略,这样可以在编译时选择不同的行为,而无需运行时多态。 然后,用户可能想知道具体的应用例子,比如书中提到的列表(TypeList)和Visitor模式。列表用来处理多种的情况,而Visitor模式则允许在不修改结构的情况下添加新操作。这些内容需要结合书中的例子进行说明,比如引用中的NotifyContainer,它根据是否为多态选择不同的复制策略,这里用到了静态分发技术,避免运行时判断的开销。 另外,用户可能对编程如何替代传统设计模式感兴趣。比如,策略模式和模板方法模式在编程中的实现方式。书中提到的Policy Classes和Mixins技术,允许通过组合不同的策略来实现灵活的设计,这比继承更灵活,减少耦合。 还需要注意用户提供的引用内容,特别是引用[4]中提到的设计原则,如“任何可以用多种方式完成的事情都应该被识别并从迁移到策略”。这说明书中强调将可变部分抽象为策略,提升代码的可维护性和扩展性。 用户的问题可能涉及如何将设计模式与C++的特性结合,比如使用模板实现工厂模式或单例模式。书中可能提供了具体的代码示例,如通过模板元编程在编译时生成代码,或者使用traits技术进行分发。 此外,需要解释书中提到的技术如何影响软件设计,比如静态多态和动态多态的对比,编译时决策的优势,以及如何通过策略组合减少虚函数开销。这可能涉及到性能优化和应用场景的选择,比如高性能系统或需要灵活配置的库设计。 最后,用户可能希望了解学习这本书的难点和实际应用中的挑战,比如模板元编程的复杂性,编译错误信息的难以理解,以及如何在实际项目中平衡灵活性和代码可读性。需要结合书中的建议,如分阶段应用和结合具体场景,来给出实用的建议。</think>### 《Modern C++ Design》中编程与设计模式的应用解析 《Modern C++ Design》由Andrei Alexandrescu撰写,是C++领域探讨编程与设计模式融合的经典著作。以下从核心思想、关键技术及应用场景逐步分析: --- #### 1. **核心思想:策略化设计(Policy-Based Design)** 书中提出**“策略化设计”**,通过编程将算法、行为或实现细节抽象为可插拔的**策略**。例如: ```cpp template <class CreationPolicy> class Widget : public CreationPolicy { // 使用CreationPolicy的策略创建对象 }; ``` - **优势**:将功能的可变部分迁移到策略模板参数,避免继承导致的耦合[^4]。 - **应用示例**:对象创建、内存管理、线程安全等场景可通过替换策略实现灵活配置。 --- #### 2. **编程与设计模式的结合** ##### (1) **列表(TypeList)** 通过模板元编程实现集合操作,例如: ```cpp typedef Typelist<int, Typelist<float, NullType>> MyTypes; ``` - **作用**:支持编译时遍历,用于生成代码或实现多分派[^2]。 - **应用场景**:工厂模式中自动注册多个。 ##### (2) **Visitor模式的实现** 传统Visitor模式依赖运行时检查,而书中通过模板和推导实现编译时分发: ```cpp template <typename T> void Visit(T& element) { // 编译时绑定处理逻辑 } ``` - **优势**:消除虚函数调用开销,提升性能[^3]。 --- #### 3. **关键技术:静态分发与策略组合** ##### (1) **静态分发(Static Dispatch)** 通过模板参数在编译时选择行为,例如引用中的`NotifyContainer`: ```cpp template<class T, bool isPolymorphic> class NotifyContainer { void doSomething() { // 根据isPolymorphic选择复制或克隆 } }; ``` - **对比动态多态**:避免运行时判断,提升效率。 ##### (2) **策略组合(Policy Composition)** 通过多重继承或模板参数组合策略: ```cpp template <class ThreadPolicy, class LogPolicy> class Database : public ThreadPolicy, public LogPolicy { ... }; ``` - **设计哲学**:任何可变的实现都应被抽象为策略,而非固化在中[^4]。 --- #### 4. **实际应用场景** 1. **可复用的程序库设计** 如Loki库中的智能指针、对象工厂,通过策略化设计支持高度定制。 2. **高性能系统开发** 静态分发和编译时优化减少运行时开销,适用于游戏引擎、实时系统。 3. **复杂算法扩展** 模式支持算法与数据结构的解耦(如STL迭代器设计)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值