一、元数据的作用

如果要对于元数据的作用进行分类,目前还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:

  1. 编写文档:通过代码里标识的元数据生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等
  2. 代码分析:通过代码里标识的元数据对代码进行分析。跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。以后java的程序开发,最多的也将实现注解配置,具有很大用处;
  3. 编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

二、jdk基本内置注释

@Override注释能实现编译时检查,你可以为你的方法添加该注释,以声明该方法是用于覆盖父类中的方法。如果该方法不是覆盖父类的方法,将会在编译时报错。例如我们为某类重写toString()方法却写成了tostring(),并且我们为该方法添加了@Override注释;

@Deprecated的作用是对不应该在使用的方法添加注释,当编程人员使用这些方法时,将会在编译时显示提示信息,它与javadoc里的@deprecated标记有相同的功能,准确的说,它还不如javadoc @deprecated,因为它不支持参数,

注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译。(见《注解中的-Xlint:unchecked和 -Xlint:deprecation》)

@SuppressWarnings与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:

  • deprecation   使用了过时的类或方法时的警告
  • unchecked  执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型
  • fallthrough   当 Switch 程序块直接通往下一种情况而没有 Break 时的警告
  • path   在类路径、源文件路径等中有不存在的路径时的警告
  • serial 当在可序列化的类上缺少 serialVersionUID 定义时的警告
  • finally    任何 finally 子句不能正常完成时的警告
  • all 关于以上所有情况的警告

注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。(见《Annotation之四:注解中的-Xlint:unchecked和 -Xlint:deprecation》)

 

在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。

三、Java5.0中新增的4种元注解:

  元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。

  • 注解方法不能有参数。
  • 注解方法的返回类型局限于原始类型,字符串,枚举,注解,或以上类型构成的数组。
  • 注解方法可以包含默认值。
  • 注解可以包含与其绑定的元注解,元注解为注解提供信息,

Java5.0以后jdk定义了四种元注解有:  

1、@Documented –注解文档提取,注解是否将包含在JavaDoc中。
2、@Retention –注解保留策略,什么时候使用该注解。
3、@Target? –注解修饰目标,注解用于什么地方。
4、@Inherited – 注解继承声明,是否允许子类继承该注解。

3.1、@Documented

@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

示例说明:看下面的示例加强理解下:

package com.dxz.nettydemo.duan;
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType; @Documented
@Target(ElementType.TYPE)
public @interface Table {
/**
* 数据表名称注解,默认值为类名称
* @return
*/
public String tableName() default "className";
}

用javadoc生成doc文档

javadoc -encoding UTF-8 Table.java

打开html文件可以看到java源码中的注释信息,如下:

3.2、@Retention

@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

  作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

  取值(RetentionPoicy)有:

    1.RetentionPolicy.SOURCE:在源文件中有效(-- 注解只存在于源代码中,字节码Class文件中将不存在该注解。)
    2.RetentionPolicy.CLASS:在class文件中有效( -- 标明注解只会被编译器编译后保留在Class字节码文件中,而运行时无法获取。)
    3.RetentionPolicy.RUNTIME:在运行时有效(-- 标明注解会保留在class字节码文件中,且运行时能通过反射机制获取。)

Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。

示例说明:Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理。

package com.dxz.nettydemo.duan;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
public String name() default "fieldName";
public String setFuncName() default "setField";
public String getFuncName() default "getField";
public boolean defaultDBValue() default false;
}

3.3、@Target

  @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

如果不明确指出,该注解可以放在任何地方。以下是一些可用的参数。需要说明的是:属性的注解是兼容的,如果你想给7个属性都添加注解,仅仅排除一个属性,那么你需要在定义target包含所有的属性。

取值(ElementType)有:

  1. ElementType.TYPE:用于描述类、接口或enum声明
  2. ElementType.FIELD:用于描述实例变量
  3. ElementType.METHOD:用于描述方法
  4. ElementType.PARAMETER:用于描述参数
  5. ElementType.CONSTRUCTOR :用于描述构造器
  6. ElementType.LOCAL_VARIABLE:用于描述局部变量
  7. ElementType.ANNOTATION_TYPE:另一个注释
  8. ElementType.PACKAGE :用于记录java文件的package信息

 示例说明,上面示例中的代码表明:注解Table 可以用于注解类、接口(包括注解类型) 或enum声明

@Target(ElementType.TYPE)
public @interface Table {
...

3.4、@Inherited

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

  注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

详细见《Annotation之二:@Inherited注解继承情况

四、自定义注解

  使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

1、定义注解格式:

public @interface 注解名 {定义体}

  注解参数的可支持数据类型:

    1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
    2.String类型
    3.Class类型
    4.enum类型
    5.Annotation类型
    6.以上所有类型的数组

  Annotation类型里面的参数该怎么设定: 
  第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   
  第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
  第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。

2、@interface说明:

  1. @interface用来定义注解标记,实际上该接口继承自java.lang.annotation.Annotation接口
  2. @是写给编译器看,javac一看到就知道这是一个注释

3、根据Annotation是否包含成员变量,可以把Annotation分为两类:

  1. 标记Annotation: 没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息;
  2. 元数据Annotation: 包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据;

简单的自定义注解和使用注解实例:

package com.dxz.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 水果名称注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
String value() default "";
}
package com.dxz.annotation; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 水果颜色注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
/**
* 颜色枚举
*/
public enum Color {
BULE, RED, GREEN
}; /**
* 颜色属性
* @return
*/
Color fruitColor() default Color.GREEN;
}
package com.dxz.annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitProvider { int id() default 0; String user() default "duan"; String address() default "shenzhen futian"; }
package com.dxz.annotation;

import com.dxz.annotation.FruitColor.Color;

public class Apple {

    @FruitName("Apple")
private String appleName; @FruitColor(fruitColor = Color.RED)
private String appleColor; @FruitProvider(id=1,user="Tom",address="China")
private FruitProvider provider;
} package com.dxz.annotation; import java.lang.reflect.Field; public class Test { public static void getFruitInfo(String clas) {
try {
Class<?> cls = Class.forName(clas);
Field[] fields = cls.getDeclaredFields(); for (Field field : fields) {
if (field.isAnnotationPresent(FruitName.class) == true) {
FruitName name = field.getAnnotation(FruitName.class);
System.out.println("Fruit Name:" + name.value());
}
if (field.isAnnotationPresent(FruitColor.class)) {
FruitColor color = field.getAnnotation(FruitColor.class);
System.out.println("Fruit Color:" + color.fruitColor());
}
if (field.isAnnotationPresent(FruitProvider.class)) {
FruitProvider Provider = field
.getAnnotation(FruitProvider.class);
System.out.println("Fruit FruitProvider: ProviderID:"
+ Provider.id() + " Provider:" + Provider.user()
+ " ProviderAddress:" + Provider.address());
}
} } catch (ClassNotFoundException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
getFruitInfo("com.dxz.annotation.Apple");
} }

结果:

Fruit Name:Apple
Fruit Color:RED
Fruit FruitProvider: ProviderID:1 Provider:Tom ProviderAddress:China

注解元素的默认值:

  注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。

五、读取注释信息(Java注解解析)

  当我们想读取某个注释信息时,我们是在运行时通过反射来实现的,如果你对元注释还有点印象,那你应该记得我们需要将保持性策略设置为RUNTIME,也就 是说只有注释标记了@Retention(RetentionPolicy.RUNTIME)的,我们才能通过反射来获得相关信息。

详细见《Annotation之三:自定义注解示例,利用反射进行解析

六、为注解增加高级属性

6.1、数组类型的属性

  • 增加数组类型的属性:int[] arrayAttr() default {1,2,4};
  • 应用数组类型的属性:@MyAnnotation(arrayAttr={2,4,5})
  • 如果数组属性只有一个值,这时候属性值部分可以省略大括号,如:@MyAnnotation(arrayAttr=2),这就表示数组属性只有一个值,值为2

6.2.、枚举类型的属性

  • 增加枚举类型的属性:EumTrafficLamp lamp() default EumTrafficLamp.RED;
  • 应用枚举类型的属性:@MyAnnotation(lamp=EumTrafficLamp.GREEN)

6.3、注解类型的属性

package com.dxz.annotation;

/**
* MetaAnnotation注解类为元注解
*/
public @interface MetaAnnotation {
String value();// 元注解MetaAnnotation设置有一个唯一的属性value
}

为注解添加一个注解类型的属性,并指定注解属性的缺省值:MetaAnnotation annotationAttr() default @MetaAnnotation("xdp");

6.4、示例

package com.dxz.annotation;

public enum EumTrafficLamp {
RED, // 红
YELLOW, // 黄
GREEN// 绿
}
package com.dxz.annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
String color() default "blue";// 为属性指定缺省值 /**
* 为注解添加value属性,这个value属性很特殊,如果一个注解中只有一个value属性要设置,
* 那么在设置注解的属性值时,可以省略属性名和等号不写, 直接写属性值,如@SuppressWarnings("deprecation"),
* 这里的MyAnnotation注解设置了两个String类型的属性,color和value,
* 因为color属性指定有缺省值,value属性又是属于特殊的属性,因此使用MyAnnotation注解时
* 可以这样使用MyAnnotation注解:"@MyAnnotation(color="red",value="xdp")"
* 也可以这样使用:"@MyAnnotation("
* test")",这样写就表示MyAnnotation注解只有一个value属性要设置,color属性采用缺省值
* 当一个注解只有一个value属性要设置时,是可以省略"value="的
*/
String value();// 定义一个名称为value的属性 // 添加一个int类型数组的属性
int[] arrayAttr() default { 1, 2, 4 }; // 添加一个枚举类型的属性,并指定枚举属性的缺省值,缺省值只能从枚举类EumTrafficLamp中定义的枚举对象中取出任意一个作为缺省值
EumTrafficLamp lamp() default EumTrafficLamp.RED; // 为注解添加一个注解类型的属性,并指定注解属性的缺省值
MetaAnnotation annotationAttr() default @MetaAnnotation("xdp"); }
package com.dxz.annotation;

/**
* 这里是将新创建好的注解类MyAnnotation标记到AnnotaionTest类上, 并应用了注解类MyAnnotation中定义各种不同类型的的属性
*/
@MyAnnotation(color = "red", value = "test", arrayAttr = { 3, 5, 6 }, lamp = EumTrafficLamp.GREEN, annotationAttr = @MetaAnnotation("gacl"))
public class MyAnnotationTest {
@MyAnnotation("将MyAnnotation注解标注到main方法上")
public static void main(String[] args) {
/**
* 这里是检查Annotation类是否有注解,这里需要使用反射才能完成对Annotation类的检查
*/
if (MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
/**
* 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
* MyAnnotation是一个类,这个类的实例对象annotation是通过反射得到的,这个实例对象是如何创建的呢?
* 一旦在某个类上使用了@MyAnnotation,那么这个MyAnnotation类的实例对象annotation就会被创建出来了
*/
MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class
.getAnnotation(MyAnnotation.class);
System.out.println("annotation.color():"+annotation.color());// 输出color属性的默认值:red
System.out.println("annotation.value():"+annotation.value());// 输出value属性的默认值:test
System.out.println("annotation.arrayAttr().length:"+annotation.arrayAttr().length);// 这里输出的数组属性的长度的结果为:3,数组属性有三个元素,因此数组的长度为3
System.out.println("annotation.lamp():"+annotation.lamp());// 这里输出的枚举属性值为:GREEN
System.out.println("annotation.annotationAttr().value():"+annotation.annotationAttr().value());// 这里输出的注解属性值:gacl MetaAnnotation ma = annotation.annotationAttr();// annotation是MyAnnotation类的一个实例对象
System.out.println("ma.value():"+ma.value());// 输出的结果为:gacl }
}
}

结果:

annotation.color():red
annotation.value():test
annotation.arrayAttr().length:3
annotation.lamp():GREEN
annotation.annotationAttr().value():gacl
ma.value():gacl

七、Java并发编程中,用到了一些专门为并发编程准备的 Annotation

主要包括三类:
1、类 Annotation(注解)
就像名字一样,这些注解是针对类的。主有要以下三个:

  • @Immutable
  • @ThreadSafe
  • @NotThreadSafe

@Immutable 表示,类是不可变的,包含了 @ThreadSafe 的意思。
@ThreadSafe 是表示这个类是线程安全的。具体是否真安全,那要看实现者怎么实现的了,反正打上这个标签只是表示一下。不线程安全的类打上这个注解也没事儿。
@NotThreadSafe 表示这个类不是线程安全的。如果是线程安全的非要打上这个注解,那也不会报错。

这三个注解,对用户和维护者是有益的,用户可以立即看出来这个类是否是线程安全的,维护者则是可以根据这个注解,重点检查线程安全方面。另外,代码分析工具可能会利用这个注解。

2、域 Annotation(注解)
域注解是对类里面成员变量加的注解。

3、方法 Annotation(注解)
方法注解是对类里面方法加的注解。

域注解和方法注解都是用@GuardedBy( lock )来标识。里面的Lock是告诉维护者:这个状态变量,这个方法被哪个锁保护着。这样可以强烈的提示类的维护者注意这里。

@GuardedBy( lock )有以下几种使用形式:

1、@GuardedBy( "this" ) 受对象内部锁保护
2、@GuardedBy( "fieldName" ) 受 与fieldName引用相关联的锁保护。
3、@GuardedBy( "ClassName.fieldName" ) 受 一个类的静态field的锁保存。
4、@GuardedBy( "methodName()" ) 锁对象是 methodName() 方法的返值,受这个锁保护。
5、@GuardedBy( "ClassName.class" ) 受 ClassName类的直接锁对象保护。而不是这个类的某个实例的锁对象。

八、servlet3.0的注解

在最新的servlet3.0中引入了很多新的注解,尤其是和servlet安全相关的注解。

HandlesTypes –该注解用来表示一组传递给ServletContainerInitializer的应用类。

HttpConstraint – 该注解代表所有HTTP方法的应用请求的安全约束,和ServletSecurity注释中定义的HttpMethodConstraint安全约束不同。

HttpMethodConstraint – 指明不同类型请求的安全约束,和ServletSecurity 注解中描述HTTP协议方法类型的注释不同。

MultipartConfig –该注解标注在Servlet上面,表示该Servlet希望处理的请求的 MIME 类型是 multipart/form-data。

ServletSecurity 该注解标注在Servlet继承类上面,强制该HTTP协议请求遵循安全约束。

WebFilter – 该注解用来声明一个Server过滤器;

WebInitParam – 该注解用来声明Servlet或是过滤器的中的初始化参数,通常配合 @WebServlet 或者 @WebFilter 使用。

WebListener –该注解为Web应用程序上下文中不同类型的事件声明监听器。

WebServlet –该注解用来声明一个Servlet的配置。

Annotation之一:Java Annotation基本功能介绍的更多相关文章

  1. Java 14 新功能介绍

    不做标题党,认认真真写个文章. 文章已经收录在 Github.com/niumoo/JavaNotes 和未读代码博客,点关注,不迷路. Java 14 早在 2019 年 9 月就已经发布,虽然不是 ...

  2. 超详细 Java 15 新功能介绍

    点赞再看,动力无限.微信搜「程序猿阿朗 」,认认真真写文章. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Java 15 在 2 ...

  3. Java 17 新功能介绍(LTS)

    点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Jav ...

  4. Java 19 新功能介绍

    点赞再看,动力无限. 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Java 19 在2022 年 9 ...

  5. Java 16 新功能介绍

    点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 程序猿阿朗博客 已经收录,有很多知识点和系列文章. Ja ...

  6. Java 18 新功能介绍

    文章持续更新,可以关注公众号程序猿阿朗或访问未读代码博客. 本文 Github.com/niumoo/JavaNotes 已经收录,欢迎Star. Java 18 在2022 年 3 月 22 日正式 ...

  7. hutool java工具架包功能介绍

    https://blog.csdn.net/lx1309244704/article/details/76459718

  8. Java Annotation认知(包括框架图、详细介绍、示例说明)

    摘要 Java Annotation是JDK5.0引入的一种注释机制. 网上很多关于Java Annotation的文章,看得人眼花缭乱.Java Annotation本来很简单的,结果说的人没说清楚 ...

  9. Java Annotation认知(包括框架图、详细介绍、示例说明)(转)

    本文转自:http://www.cnblogs.com/skywang12345/p/3344137.html 网上很多关于Java Annotation的文章,看得人眼花缭乱.Java Annota ...

随机推荐

  1. 工作队列work queues 公平分发(fair dispatch) And 消息应答与消息持久化

    生产者 package cn.wh.work; import cn.wh.util.RabbitMqConnectionUtil; import com.rabbitmq.client.Channel ...

  2. virtio guest side implementation: PCI, virtio device, virtio net and virtqueue

    With the publishing of OASIS virtio specification version 1.0, virtio made another big step in becom ...

  3. HTTP Status 500 - Unable to instantiate Action, customerAction, defined for 'customer_toAddPage' i

    使用struts2时碰到这样的错误 HTTP Status 500 - Unable to instantiate Action, customerAction, defined for 'custo ...

  4. spring3:对JDBC的支持 之 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

  5. uva-1449-AC自动机

    题目链接https://vjudge.net/problem/UVA-1449 题目大意:给出N(N<150)个长度不超过L(70)的匹配串和一个长度小于1e6的文本串,在文本串中找出出现次数最 ...

  6. pxcook-高效易用的自动标注工具, 生成前端代码

    1.pxcook.sketch(http://www.fancynode.com.cn/pxcook)

  7. .SourceInsight添加.S文件

    在Option->Document Option添加配置.S然后再去添加文件

  8. 遮罩效果 css3

    CSS3提供了遮罩效果,这是以前CSS2中比较难实现的一个新特性,配合SVG或者canvas同样也可以实现遮罩效果,他的效果就如下图所示: 简单的说就是在一个层上面加一个过滤层,过滤层透明度越低,底层 ...

  9. org.apache.jasper.JasperException: #{...} is not allowed in template

    org.apache.jasper.JasperException: #{...} is not allowed in template   针对jsp页面使用JQueryUI元素,出现org.apa ...

  10. NSSet基本使用

    int main(int argc, const char * argv[]) { @autoreleasepool { //创建一个集合对象 注:如果集合中写了两次或多次同一个对象 打印只能看到一个 ...