详解c++中的trait与policy模板技术

目录
  • 概述
  • trait模板技术
  • 用模板参数来传递多种trait
  • policy模板技术
  • 模板化的policy
  • trait模板与policy模板技术的比较

概述

我们知道,类有属性(即数据)和操作两个方面。同样模板也有自己的属性(特别是模板参数类型的一些具体特征,即trait)和算法策略(policy,即模板内部的操作逻辑)。模板是对有共性的各种类型进行参数化后的一种通用代码,但不同的具体类型又可能会有一些差异,比如不同的类型可能会有自己的不同特征和算法实现策略。

trait模板技术

当在模板代码中需要知道类型参数T的某些特征(比如需要知道T是哪个具体类型,是否有默认构造函数,希望该类型有合理的缺省值,如int型缺省值为0),我们可以声明一个描述T的特征的trait<T>模板,然后对每种具体类型(如int,char,用户定义的类)特化trait<T>,在各特化版本中用typedef为该具体类型(或者想映射成的其他类型)定义统一的别名(比如AliT),根据需要还可指定合理的缺省值等。这样在原来模板文件中#include这个trait<T>模板的文件,就可以在模板代码中使用trait<T>::AliT来获得T的具体特征。

比如我们要计算数组各个元素的累加和,由于数组元素可以是各种类型,我们使用模板来实现它,这时有一个类型参数T。但在算法代码中,某些情况下又必须知道T的具体类型特征,才能作出特殊的处理。例如对char型的数组元素累加如果最终返回的也是char型的话,很可能越界,因为char只占8位,范围很小。我们可以为T的trait创建一个模板AccumulationTraits。具体代码如下:

//accum1.hpp:累加算法模板:实现为函数模板,引入了trait。用数组首部指针及尾部后面的一个指针作参数
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits.hpp"
#include <iostream>
template<typename T>
inline typename AccumulationTraits<T>::AccT accum(T const* beg,T const* end){
    //返回值类型是要操作的元素类型T的trait
    typedef typename AccumulationTraits<T>::AccT AccT;
    AccT total=AccumulationTraits<T>::zero(); //返回具体类型的缺省值
    while(beg!=end){  //作累加运算
        total+=*beg;
        ++beg;
    }
    return total; //返回累加的值
}
#endif  
//accumtraits.hpp:累加算法模板的trait
#ifndef ACCUMTRAITS_HPP
#define ACCUMTRAITS_HPP
template<typename T>
class AccumulationTraits; //只有声明
//各个特化的定义
template<>
class AccumulationTraits<char>{ //把具体类型char映射到int,累加后就返回int
public:
    typedef int AccT;  //统一的类型别名,表示返回类型
    static AccT zero(){ //关联一个缺省值,是累加时的初始缺省值
        return 0;
    }
};
template<>
class AccumulationTraits<short>{ //把具体类型short映射到累加后的返回类型int
public:
    typedef int AccT;
    static AccT zero(){ //没有直接在类内部定义static变量并提供缺省值,而是使用了函数
                        //因为类内部只能对整型和枚举类型的static变量进行初始化
                        //其他类型的必须类内部声明,在外部进行初始化
        return 0;
    }
};
template<>
class AccumulationTraits<int>{
public:
    typedef long AccT;
    static AccT zero(){
        return 0;
    }
};
template<>
class AccumulationTraits<unsigned int>{
public:
    typedef unsigned long AccT;
    static AccT zero(){
        return 0;
    }
};
template<>
class AccumulationTraits<float>{
public:
    typedef double AccT;
    static AccT zero(){
        return 0;
    }
};
//...
#endif  
//accum1test.cpp:使用累加算法的客户端代码
#include "accum1.hpp"
#include <iostream>
int main(){
    int num[]={1,2,3,4,5}; //整型数组
    std::cout<<"the average value of the integer values is "
        <<accum(&num[0],&num[5])/5<<'/n';  //输出平均值
    char name[]="templates"; //创建字符值数组
    int length=sizeof(name)-1;
    //输出平均的字符值,返回的是int型,不会越界
    std::cout<<"the average value of the characters in /""
        <<name<<"/" is "<<accum(&name[0],&name[length])/length<<'/n';
    return 0;
}  

注意trait模板本身只是一个声明,并不提供定义,因为它并不知道参数T具体是什么类型。trait的定义由针对各个具体类型的特化来提供。trait依赖于原来模板的主参数T,因为它表示的是T的特征信息。这里使用函数zero()为每个具体类型还关联了一个缺省值,用来作为累加的初始值。为什么不直接关联为静态变量呢?比如static AccT const zero=0。这主要是因为在类内部只能对整型和枚举类型的static变量进行初始化,其他类型的必须在类内部声明,在外部进行初始化。这里对char型数组元素进行累加时,返回int型,这样就避免了会产生越界的情况。

总结出trait模板技术的核心思想:把模板参数T的具体特征信息抽象成一个独立的模板,通过特化为具体的类型并为该类型关联统一的别名,我们就可以在模板中引用这个别名,以获得T的具体特征信息。注意一个模板参数可能有多种特征,每一个trait都可以抽象成一个trait模板。可见这里特化是获得具体差异行为的关键。由于在模板中类型T是抽象的,不能获得它的具体特征,我们通过对T的特征进行抽离,并特化为具体的类型,才能获得类型的具体特征。从这可以看出我们还有一种实现方案,那就是直接特化模板accum,即针对char型进行一个特化来进行累加。但这样特化版本中又要重写基本模板中那些相同的代码逻辑(比如进行累加的while循环),而实际上我们需要特化的只是类型的特征信息。

在设计层面上,特化与模板的意图正好相反。模板是泛型代码,代表各个类型之间的共性,而特化则表示各个类型之间的差异。我们可以结合多态来深刻地把握这些设计思想。从一般意义上讲,polymorphism是指具有多种形态或行为,它能够根据单一的标记来关联不同的特定行为。可见条件语句if/else也可以看作是一种多态,它根据标记的不同状态值来选择执行不同的分支代码(代表不同的行为)。多态在不同的程序设计范型有不同的表现。

(1)面向过程的程序设计:多态通过条件语句if/else来实现。这样多态其实成了最基本的程序逻辑结构。我们知道顺序语句和条件语句是最基本的逻辑结构,switch语句本身就是if/else的变体,循环语句相当于有一个goto语句的if/else。这种多态可以称为OP多态,它最大优点就是效率高,只有一个跳转语句,不需要额外的开销。最大缺点就难以扩展,很难应对变化。当有新的行为时,就要修改原来的代码,在if/else中再增加一个分支,然后重新编译代码。它只是一种低层次的多态,需要程序员人工增加代码,判断标记的值。

(2)面向对象程序设计:多态通过虚函数机制,用继承的方式来实现。这里的设计思想就是抽离类型之间的共性,把它们放在基类中,而具体的差异性则放到子类中。我们使用基类指针或引用作为单一的标记,它会自动的绑定到子类对象上,以获得不同的行为。函数重载也可以看作是一种多态,函数名作为单一的标记,我们通过不同的参数类型来调用不同的重载版本,从而获得不同的多态行为。这种多态称为OO多态,它的优点就是自动化,易扩展,提高了复用程度。它不需要程序员人工干预,因为动态绑定是自动进行的。当需要新的行为时,从基类继承一个新的子类即可,不需要修改原来的代码,系统易维护,也易扩展。缺点就是降低了效率,当纵向的继承体系比较深时,要创建大量的对象,虚函数一般也很少能够被内联,这会使内存使用量大幅增加。OO多态是一种高层次的多态,耦合性比OP多态低,但纵向的继承体系仍然有一定的耦合性。

(3)泛型程序设计:多态通过模板来实现。这里的设计思想就是不需要抽离类型之间的共性,而是直接对类型进行参数化,把它设计成模板,以表示共性。类型之间的差异通过特化来实现。编译器会根据类型参数(相当于单一的标记)自动决定是从模板产生实例,还是调用特化的实例。这种多态称为GP多态,它是横向的,代表共性的模板与代表差异性的特化在同一层次上,它们之间是相互独立的,因此它的耦合性更低,性能也更好。由于GP本身也支持继承和重载,因此可以看出它是一种更高层次的多态,而用模板来做设计甚至比面向对象设计还强大,因为模板本身也支持面向对象的继承机制,它在面向对象层次上还作了一层更高的抽象(对类进行抽象)。GP多态还具有更好的健壮性,因为它在编译期就进行检查。当然,GP代码比较难调试,这主要由于 编译器支持得不好。

用模板参数来传递多种trait

前面我们在accum中通过组合的方式使用它的trait模板。我们也可直接给accum模板增加一个模板参数用来传递trait类型,并指定一个缺省实参为AccumulationTraits<T>,这样可以适应有多种trait的情况。由于函数模板并不能指定缺省模板实参(其实现在许多编译器都支持这个非标准特性),我们把accum实现为一个类模板。算法作为一个函数来使用时应该会更自然一点,因此可以再用一个函数模板来包装这个类模板,使之变成一个函数模板。如下:

//accum2.hpp:累加算法模板:实现为类模板,用模板参数来传递trait
//可用一个内联函数模板作为包装器来包装这个类模板实现
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits.hpp"
template<typename T,typename AT=AccumulationTraits<T> >
class Accum{ //实现为类模板,模板参数AT代表要使用的trait,并有一个缺省实参
public:
    static typename AT::AccT accum(T const* beg,T const* end){
        typename AT::AccT total=AT::zero(); //获取缺省值
        while(beg != end){ //进行累加
            total+=*beg;
            ++beg;
        }
        return total; //返回累加的值
    }
};
//用内联的函数模板来包装,对默认的trait,使用一个独立的重载版本
template<typename T>
inline typename AccumulationTraits<T>::AccT accum(T const* beg,T const* end){
    return Accum<T>::accum(beg,end);
}
template<typename T,typename Traits>
inline
typename Traits::AccT accum(T const* beg,T const* end){
    return Accum<T,Traits>::accum(beg,end);
}
#endif  

使模板参数来传递trait的一个最大好处是当有多种trait时,我们可以为第2个模板参数指定需要的各种trait。这里还使用了所谓的内联包装函数技术。当我们实现了一个函数(模板),但接口比较难用时,比如这里是类模板,用户即使是使用默认的AccumumationTrait<T>,也要显式指定第一个实参T,不好用。我们可以用一个包装函数来包装它,使其接口变得对用户非常简单友好,为了避免包装带来的性能损失,要把包装函数(模板)声明为内联,编译器通常会直接调用位于内联函数里面的那个函数。这样,使用默认trait时客户端代码accum1test.cpp不需要做任何修改。

policy模板技术

与trait模板技术的思想类似,只不过是对模板代码中的算法策略进行抽离。因为模板代码中对不同的具体类型可能某一部分代码逻辑(即算法策略)会不一样(比如对int是累加,对char则是连接)。policy模板就代表了这些算法策略。它不需要使用特化,policy只需重新实现这个与原模板中的代码不同的具体算法策略即可。

上面是对类型的不同trait产生的差异。实际上对不同的trait,其算法策略(policy)也可能有不同的差异。比如我们对char型元素的数组,不用累加策略,而是用连接的策略。我们还可以把accum看作是一般的数组元素累积性函数,既可以累加,也可以累乘、连接等。一种方法是我们可以直接对accum函数模板的不同具体类型提供特化,重写各自的代码逻辑。但实际上,这时我们需要变化的只有total+=*beg那一条语句,因此我们可以使用policy模板技术,为模板的不同policy创建独立的模板。这里我们把policy实现为具有一个成员函数模板的普通类(当然policy也可以直接实现为模板)。对累加策略为SumPolicy,对累乘策略为MultPolicy等。代码如下:

//policies1.hpp:累加元素模板的不同policy实现:实现为含有成员函数模板的普通类
#ifndef POLICIES_HPP
#define POLICIES_HPP
class SumPolicy{ //累加的policy
public:
    template<typename T1,typename T2>
    static void accumulate(T1& total,T2 const& value){
        total+=value; //作累加
    }
};
class MultPolicy{ //累乘的policy
public:
    template<typename T1,typename T2>
    static void accumulate(T1& total,T2 const& value){
        total*=value;
    }
};
//其他各种policy
//......
#endif  

引入了policy后,把累加算法实现为类模板,如下:

//accum3.hpp:累加算法模板,引入了作为普通类的policy,默认是采用SumPolicy
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits.hpp"
#include "policies1.hpp"
template<typename T,typename Policy=SumPolicy,typename Traits=AccumulationTraits<T> >
class Accum{ //累加算法实现为类模板,默认采用SumPolicy
public:
    typedef typename Traits::AccT AccT;
    static AccT accum(T const* beg,T const* end){
        AccT total=Traits::zero();  //获取缺省值
        while(beg !=end){ //作累积运算
            Policy::accumulate(total,*beg); //使用给定的算法策略来进行累积
            ++beg;
        }
        return total; //返回累积起来的值
    }
};
#endif  

当policy为普通类时,这里用一个类型模板参数来传递不同的policy,缺省的policy为SumPolicy。客户端使用Accum<int>::accum(&num[0],&num[5])这样的形式来对int型数组元素进行累加。注意当trait使用默认的AccummulationTrait<T>时,累乘策略MultPolicy实际上就不能用在这里了。因为初始值为0,那累乘的结果最终总是0,可见policy与trait是有联系的。当然我们也可以换一种方法来实现,即直接让accum函数增加一个形参T val,用val来指定运算的初始值。实际上,C++标准库函数accumulate()就是把这个初值作为第3个实参。

模板化的policy

上面的policy实现为具有一个成员函数模板的普通类,这可以看出,其实policy可以直接实现为一个模板。这时在accum算法中就要用模板模板参数来传递policy了。代码如下:

//policies2.hpp:把各个policy实现为类模板
#ifndef POLICIES_HPP
#define POLICIES_HPP
template<typename T1,typename T2>
class SumPolicy{
public:
    static void accumulate(T1& total,T2 const& value){
        total+=value;
    }
};
//...
#endif  
//accum4.hpp:累加算法模板,引入了作为类模板的policy,默认是采用SumPolicy
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits.hpp"
#include "policies2.hpp"
template<typename T,
    template<typename,typename> class Policy=SumPolicy,
    typename Traits=AccumulationTraits<T> >
class Accum{ //累加算法实现为类模板,默认采用模板SumPolicy
public:
    typedef typename Traits::AccT AccT; //获取返回类型,它是T的trait
    static AccT accum(T const* beg,T const* end){
        AccT total=Traits::zero();  //获取缺省值
        while(beg !=end){ //作累积运算
            Policy<AccT,T>::accumulate(total,*beg); //使用给定的算法策略来进行累积
            ++beg;
        }
        return total; //返回累积起来的值
    }
};
#endif  

trait模板与policy模板技术的比较

(1)trait注重于类型,policy更注重于行为。

(2)trait可以不通过模板参数来传递,它表示的类型通常具有自然的缺省值(如int型为0),它依赖于一个或多个主参数,它 一般用模板来实现。

(3)policy可以用普通类来实现,也可以用类模板来实现,一般通过模板参数来传递。它并不需要类型有缺省值,缺省值通常是在policy中的成员函数中用一个独立的参数来传递。它通常并不直接依赖于模板参数。

一般在模板中指定两个模板参数来传递trait和policy。而policy的种类更多,使用更频繁,因此通常代表policy的模板参数在代表trait的模板参数前面。

标准库中的std::iterator_traits<T>是一个trait,可通过iterator_traits<T>::value_ type来引用T表示的具体类型。其实现也是用特化来获取各个具体的类型,有全局特化也有局部物化,如指针类型,引用类型等就只能通过局部特化为T*,T&来实现。

以上就是详解c++中的trait与policy模板技术的详细内容,更多关于c++中的trait与policy模板技术的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++编程中使用设计模式中的policy策略模式的实例讲解

    在看<C++设计新思维>的时候,发现在一开始就大篇幅的介绍策略模式(policy),策略模式不属于经典设计模式中的一种,但是其实在我们日常的开发中是必不可少的.policy,策略,方针,这里的意思是指把复杂功能的类尽量的拆分为功能单一的简单类的组合,简单的类只负责单纯行为或结构的某一方面.增加程序库的弹性,可复用性,可扩展性.policy是一个虚拟的概念,他定义了某一类class的一些接口规范,并不与C++语法的关键字对应,只是一个抽象的概念. 实例1: //policy模式的常见使用实例sm

  • 深入浅析C++ traits技术

    前言 traits,又被叫做特性萃取技术,说得简单点就是提取"被传进的对象"对应的返回类型,让同一个接口实现对应的功能.因为STL的算法和容器是分离的,两者通过迭代器链接.算法的实现并不知道自己被传进来什么.萃取器相当于在接口和实现之间加一层封装,来隐藏一些细节并协助调用合适的方法,这需要一些技巧(例如,偏特化).最后附带一个小小的例子,应该能更好地理解 特性萃取. 下面大部分来源于<STL源码剖析>,看原书能了解更多细节. Traits编程技法 让我们一点点抛出问题,然后

  • C++模板template用法小结(推荐)

    引言 模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计.C++ 的标准库提供许多有用的函数大多结合了模板的观念,如STL以及IO Stream. 函数模板 在c++入门中,很多人会接触swap(int&, int&)这样的函数类似代码如下: void swap(int&a , int& b) { int temp = a; a = b; b = temp; } 但是如果是要支持long,string,自定义class的swap函

  • 详解C++编程中类模板的相关使用知识

    有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类: class Compare_int { public : Compare(int a,int b) { x=a; y=b; } int max( ) { return (x>y)?x:y; } int min( ) { return (x<y)?x:y; } private : int x,y; }; 其作用是对两个整数作比较,可以通过调用成员函数max和min得到两个整数中的大者和小者. 如果想对两个浮点数(

  • 详解c++11新特性之模板的改进

    C++11关于模板有一些细节的改进: 模板的右尖括号 模板的别名 函数模板的默认模板参数 模板的右尖括号 C++11之前是不允许两个右尖括号出现的,会被认为是右移操作符,所以需要中间加个空格进行分割,避免发生编译错误. int main() { std::vector<std::vector<int>> a; // error std::vector<std::vector<int> > b; // ok } 这个我之前都不知道,我开始学编程的时候就已经是C

  • 解读C++编程中类模板的三种特化

    1.类模板显式特化 为了进行特化,首先需要一个通用的版本,称主模板.主模板使用了标准库堆算法.  堆 是一种线性化的树形结构,将一个值压入一个堆中, 实际上等于将该值插入到一个树形结构中;将一个值从堆中取出就等于移除并返回堆中最大值.但在处理字符的指针时会碰钉子.堆将按照指针的值进行组织. 我们可以提供一个显式特化版本解决此问题(例1)如果希望除了一个针对const char*的Heap外,还希望提供一个针对char *的Heap;(例2) //主模板 template <typename T>

  • C++使用模板类实现链式栈

    本文实例为大家分享了C++使用模板类实现链式栈的具体代码,供大家参考,具体内容如下 一.实现程序: 1.Stack.h #ifndef Stack_h #define Stack_h template <class T> class Stack { public: Stack(){}; // 构造函数 void Push(const T x); // 新元素进栈 bool Pop(); // 栈顶元素出栈 virtual bool getTop(T &x) const = 0; //

  • C++中的模板template小结

    函数模板 我们可以把函数模板当做一种特殊的函数,里面的参数类型可以是任意类型,这样的话我们就可以减少重复定义,从而让这个函数模板自动适应不同的参数类型,也就是说函数可以适应多种类型的参数,例如double.int或者类什么的. C++为了实现上面的功能,引入了template这个概念.我们可以把template当成是一种特殊的类型参数,并且也可以在函数里当做参数传递,心里面把它当做int什么的就行了. 使用类型参数声明函数模板的格式如下所示: template <class identifier

  • C++模板实现顺序栈

    顺序栈:利用一组连续的存储单元依次存放自栈底到栈顶的数据元素:由于栈顶元素是经常变动的,所以附设top指示栈顶元素在顺序表中的位置,同时也需要知道顺序栈存储空间的起始位置,因此还需设定一个base指针用来指示栈空间的起始位置. 一般约定top指针指向栈顶元素的下一个位置,即新数据元素将要插入得位置. 下面我们使用模板简单实现一个顺序栈: SeqStack.h template<typename Type> class SeqStack{ public: SeqStack(int sz):m_n

  • 详解c++中的trait与policy模板技术

    目录 概述 trait模板技术 用模板参数来传递多种trait policy模板技术 模板化的policy trait模板与policy模板技术的比较 概述 我们知道,类有属性(即数据)和操作两个方面.同样模板也有自己的属性(特别是模板参数类型的一些具体特征,即trait)和算法策略(policy,即模板内部的操作逻辑).模板是对有共性的各种类型进行参数化后的一种通用代码,但不同的具体类型又可能会有一些差异,比如不同的类型可能会有自己的不同特征和算法实现策略. trait模板技术 当在模板代码中

  • 详解PHP中的8个魔术常量

    PHP 向它运行的任何脚本提供了大量的预定义常量. 不过很多常量都是由不同的扩展库定义的,只有在加载了这些扩展库时才会出现,或者动态加载后,或者在编译时已经包括进去了. 有八个魔术常量它们的值随着它们在代码中的位置改变而改变. 例如 __LINE__ 的值就依赖于它在脚本中所处的行来决定.这些特殊的常量不区分大小写,如下: __LINE__ 文件中的当前行号. <?php echo '这是第 " ' . __LINE__ . ' " 行'; ?> 以上实例输出结果为: 这是

  • 详解java中各类锁的机制

    目录 前言 1. 乐观锁与悲观锁 2. 公平锁与非公平锁 3. 可重入锁 4. 读写锁(共享锁与独占锁) 6. 自旋锁 7. 无锁 / 偏向锁 / 轻量级锁 / 重量级锁 前言 总结java常见的锁 区分各个锁机制以及如何使用 使用方法 锁名 考察线程是否要锁住同步资源 乐观锁和悲观锁 锁住同步资源后,要不要阻塞 不阻塞可以使用自旋锁 一个线程多个流程获取同一把锁 可重入锁 多个线程公用一把锁 读写锁(写的共享锁) 多个线程竞争要不要排队 公平锁与非公平锁 1. 乐观锁与悲观锁 悲观锁:不能同时

  • 详解IE6中的position:fixed问题与随滚动条滚动的效果

    详解IE6中的position:fixed问题与随滚动条滚动的效果 前言: 在<[jQuery]兼容IE6的滚动监听>(点击打开链接)提及到解决IE6fixed问题,具体是要引入一个js文件,还要声明一条脚本就为这个div声明fixed定位去解决,起始这样很不好啊.引入的Javascript不好管理之余,还要在head声明引入javascript,之后又要给这个div声明一个id,之后又要在脚本出弄一条声明,实在是烦死了. 使用position:fixed无非是想做出如下的效果. 基本上pos

  • 详解Angular中$cacheFactory缓存的使用

    最近在学习使用angular,慢慢从jquery ui转型到用ng开发,发现了很多不同点,继续学习吧: 首先创建一个服务,以便在项目中的controller中引用,服务有几种存在形式,factory();service();constant();value();provider();其中provider是最基础的,其他服务都是基于这个写的,具体区别这里就不展开了,大家可以看看源码:服务是各个controller之间通话的重要形式,在实际项目中会用的很多,下面是代码: angular.module

  • 详解AngularJS中$filter过滤器使用(自定义过滤器)

    1.内置过滤器 * $filter 过滤器,是angularJs中用来处理数据以更好的方式展示给我用户.比如格式化日期,转换大小写等等. * 过滤器即有内置过滤器也支持自定义过滤器.内置过滤器很多,可以百度.关键是如何使用: * 1.在HTML中直接使用内置过滤器 * 2.在js代码中使用内置过滤器 * 3.自定义过滤器 * * (1)常用内置过滤器 * number 数字过滤器,可以设置保留数字小数点后几位等 * date 时间格式化过滤器,可自己设置时间格式 * filter 过滤的数据一般

  • 详解AngularJS中的表单验证(推荐)

    AngularJS自带了很多验证,什么必填,最大长度,最小长度...,这里记录几个有用的正则式验证 1.使用angularjs的表单验证 正则式验证 只需要配置一个正则式,很方便的完成验证,理论上所有的验证都可以用正则式完成 //javascript $scope.mobileRegx = "^1(3[0-9]|4[57]|5[0-35-9]|7[01678]|8[0-9])\\d{8}$"; $scope.emailRegx = "^[a-z]([a-z0-9]*[-_]?

  • 详解Java中@Override的作用

    详解Java中@Override的作用 @Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处: 1.可以当注释用,方便阅读: 2.编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错.例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法. 举例:在重写父类的onCreate时,在方法前面加上@Override 系统可以帮你检查方法的正确性. @Overr

  • 详解Java中多线程异常捕获Runnable的实现

    详解Java中多线程异常捕获Runnable的实现 1.背景: Java 多线程异常不向主线程抛,自己处理,外部捕获不了异常.所以要实现主线程对子线程异常的捕获. 2.工具: 实现Runnable接口的LayerInitTask类,ThreadException类,线程安全的Vector 3.思路: 向LayerInitTask中传入Vector,记录异常情况,外部遍历,判断,抛出异常. 4.代码: package step5.exception; import java.util.Vector

  • 详解Struts2中对未登录jsp页面实现拦截功能

    Struts2中拦截器大家都很经常使用,但是拦截器只能拦截action不能拦截jsp页面.这个时候就有点尴尬了,按道理来说没登录的用户只能看login界面不能够通过输入URL进行界面跳转,这显然是不合理的.这里介绍Struts2中Filter实现jsp页面拦截的功能.(有兴趣的人可以去研究Filter过滤器的其它用法,因为利用过滤器也可以实现action拦截的功能) 下面直接上代码,边看边分析实现步骤和原理. 1.web.xml中的配置信息: <filter> <filter-name&

随机推荐