http://blog.csdn.net/softwave/article/details/6991913

一、什么是注释

说起注释,得先提一提什么是元数据(metadata)。所谓元数据就是数据的数据。也就是说,元数据是描述数据的。就象数据表中的字段一样,每个字段描述了这个字段下的数据的含义。而J2SE5.0中提供的注释就是java源代码的元数据,也就是说注释是描述java源代码的。在J2SE5.0中可以自定义注释。使用时在@后面跟注释的名字。 
                                                                                    
二、J2SE5.0中预定义的注释

在J2SE5.0的java.lang包中预定义了三个注释。它们是Override、Deprecated和SuppressWarnings。下面分别解释它们的含义。

Override

这个注释的作用是标识某一个方法是否覆盖了它的父类的方法。那么为什么要标识呢?让我们来看看如果不用Override标识会发生什么事情。

    假设有两个类Class1和ParentClass1,用Class1中的myMethod1方法覆盖ParentClass1中的myMethod1方法。

            
class ParentClass1{public void myMethod1() {...}}class Class1 extends ParentClass1{public void myMethod2() {...}}

建立Class1的实例,并且调用myMethod1方法

            
ParentClass1 c1 = new Class1();c1.myMethod1();

以上的代码可以正常编译通过和运行。但是在写Class1的代码时,误将myMethod1写成了myMethod2,然而在调用时,myMethod1并未被覆盖。因此,c1.myMethod1()调用的还是ParentClass1的myMethod1方法。更不幸的是,程序员并未意识到这一点。因此,这可能会产生bug。

如果我们使用Override来修饰Class1中的myMethod1方法,当myMethod1被误写成别的方法时,编译器就会报错。因此,就可以避免这类错误。

            
class Class1 extends ParentClass1{@Override // 编译器产生一个错误public void myMethod2(){...}}

以上代码编译不能通过,被Override注释的方法必须在父类中存在同样的方法程序才能编译通过。也就是说只有下面的代码才能正确编译。

            
class Class1 extends ParentClass1{@Overridepublic void myMethod1() {...}}

Deprecated

这个注释是一个标记注释。所谓标记注释,就是在源程序中加入这个标记后,并不影响程序的编译,但有时编译器会显示一些警告信息。 
    
    那么Deprecated注释是什么意思呢?如果你经常使用eclipse等IDE编写java程序时,可能会经常在属性或方法提示中看到这个词。如果某个类成员的提示中出现了个词,就表示这个并不建议使用这个类成员。因为这个类成员在未来的JDK版本中可能被删除。之所以在现在还保留,是因为给那些已经使用了这些类成员的程序一个缓冲期。如果现在就去了,那么这些程序就无法在新的编译器中编译了。

说到这,可能你已经猜出来了。Deprecated注释一定和这些类成员有关。说得对!使用Deprecated标注一个类成员后,这个类成员在显示上就会有一些变化。在eclipse中非常明显。让我们看看图1有哪些变化。

图1 加上@Deprecated后的类成员在eclipse中的变化

从上图可以看出,有三个地方发生的变化。红色框里面的是变化的部分。 
    1. 方法定义处 
    2. 方法引用处 
    3. 显示的成员列表中

发生这些变化并不会影响编译,只是提醒一下程序员,这个方法以后是要被删除的,最好别用。

Deprecated注释还有一个作用。就是如果一个类从另外一个类继承,并且override被继承类的Deprecated方法,在编译时将会出现一个警告。如test.java的内容如下:

            
class Class1{@Deprecatedpublic void myMethod(){}}class Class2 extends Class1{public void myMethod(){}}

运行javac test.java 出现如下警告:

注意:test.java 使用或覆盖了已过时的 API。 
    注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译 
    使用-Xlint:deprecation显示更详细的警告信息:

test.java:4: 警告:[deprecation] Class1 中的 myMethod() 已过时

public void myMethod() 
    ^ 
    1 警告

这些警告并不会影响编译,只是提醒你一下尽量不要用myMethod方法。

SuppressWarnings 

这个世界的事物总是成对出现。即然有使编译器产生警告信息的,那么就有抑制编译器产生警告信息的。 
    SuppressWarnings注释就是为了这样一个目的而存在的。让我们先看一看如下的代码。

            
public void myMethod(){List wordList = new ArrayList();wordList.add("foo");}

这是一个类中的方法。编译它,将会得到如下的警告。

注意:Testannotation.java 使用了未经检查或不安全的操作。 
    注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。

这两行警告信息表示List类必须使用范型才是安全的,才可以进行类型检查。如果想不显示这个警告信息有两种方法。一个是将这个方法进行如下改写:

public void myMethod()
{
  List<String> wordList = new ArrayList<String>();
  wordList.add("foo");
}

另外一种方法就是使用@SuppressWarnings。
@SuppressWarnings (value={"unchecked"})
public void myMethod()
{
  List wordList = new ArrayList();
  wordList.add("foo");
}
要注意的是SuppressWarnings和前两个注释不一样。这个注释有一个属性。当然,还可以抑制其它警告,如:
@SuppressWarnings (value={"unchecked", "fallthrough"})

三、如何自定义注释 

    注释的强大之处是它不仅可以使java程序变成自描述的,而且允许程序员自定义注释。注释的定义和接口差不多,只是在interface前面多了一个“@”。

            
public @interface MyAnnotation{}

上面的代码是一个最简单的注释。这个注释没有属性。也可以理解为是一个标记注释。就象Serializable接口一样是一个标记接口,里面未定义任何方法。

当然,也可以定义有属性的注释。

            
public @interface MyAnnotation{String value();}

可以按如下格式使用MyAnnotation

            
@MyAnnotation("abc")public void myMethod(){}

看了上面的代码,大家可能有一个疑问。怎么没有使用value,而直接就写”abc”了。那么”abc”到底传给谁了。其实这里有一个约定。如果没有写属性名的值,而这个注释又有value属性,就将这个值赋给value属性,如果没有,就出现编译错误。

除了可以省略属性名,还可以省略属性值。这就是默认值。

            
public @interface MyAnnotation{  public String myMethod(){} default “xyz”;}

可以直接使用MyAnnotation

            
@MyAnnotation // 使用默认值xyzpublic void myMethod(){}

也可以这样使用

            
@MyAnnotation(myMethod=”abc”)public void myMethod(){}

如果要使用多个属性的话。可以参考如下代码。

            
public @interface MyAnnotation{public enum MyEnum{A, B, C}public MyEnum.value1() {}public String value2() {}}@MyAnnotation(value1=MyAnnotation.MyEnum.A, value2 = “xyz”)public void myMethod(){}

这一节讨论了如何自定义注释。那么定义注释有什么用呢?有什么方法对注释进行限制呢?我们能从程序中得到注释吗?这些疑问都可以从下面的内容找到答案。


四、如何对注释进行注释

这一节的题目读起来虽然有些绕口,但它所蕴涵的知识却对设计更强大的java程序有很大帮助。 
在上一节讨论了自定义注释,由此我们可知注释在J2SE5.0中也和类、接口一样。是程序中的一个基本的组成部分。既然可以对类、接口进行注释,那么当然也可以对注释进行注释。 
    使用普通注释对注释进行注释的方法和对类、接口进行注释的方法一样。所不同的是,J2SE5.0为注释单独提供了4种注释。它们是Target、Retention、Documented和Inherited。下面就分别介绍这4种注释。

Target 
   这个注释理解起来非常简单。由于target的中文意思是“目标”,因此,我们可能已经猜到这个注释和某一些目标相关。那么这些目标是指什么呢?大家可以先看看下面的代码。

            
@Target(ElementType.METHOD)@interface MyAnnotation {}@MyAnnotation // 错误的使用public class Class1{@MyAnnotation // 正确的使用public void myMethod1() {}}

以上代码定义了一个注释MyAnnotation和一个类Class1,并且使用MyAnnotation分别对Class1和myMethod1进行注释。如果编译这段代码是无法通过的。也许有些人感到惊讶,没错啊!但问题就出在@Target(ElementType.METHOD)上,由于Target使用了一个枚举类型属性,它的值是ElementType.METHOD。这就表明MyAnnotation只能为方法注释。而不能为其它的任何语言元素进行注释。因此,MyAnnotation自然也不能为Class1进行注释了。 
   
说到这,大家可能已经基本明白了。原来target所指的目标就是java的语言元素。如类、接口、方法等。当然,Target还可以对其它的语言元素进行限制,如构造函数、字段、参数等。如只允许对方法和构造函数进行注释可以写成:

            
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})@interface MyAnnotation {}

Retention 
     既然可以自定义注释,当然也可以读取程序中的注释(如何读取注释将在下一节中讨论)。但是注释只有被保存在class文件中才可以被读出来。而Retention就是为设置注释是否保存在class文件中而存在的。下面的代码是Retention的详细用法。

            
@Retention(RetentionPolicy.SOURCE)@interface MyAnnotation1 { }@Retention(RetentionPolicy.CLASS)@interface MyAnnotation2 {}@Retention(RetentionPolicy.RUNTIME)@interface MyAnnotation3 {}

其中第一段代码的作用是不将注释保存在class文件中,也就是说象“//”一样在编译时被过滤掉了。第二段代码的作用是只将注释保存在class文件中,而使用反射读取注释时忽略这些注释。第三段代码的作用是即将注释保存在class文件中,也可以通过反射读取注释。

Documented 

    这个注释和它的名子一样和文档有关。在默认的情况下在使用javadoc自动生成文档时,注释将被忽略掉。如果想在文档中也包含注释,必须使用Documented为文档注释。

            
@interface MyAnnotation{ }@MyAnnotationclass Class1{public void myMethod() { }}

使用javadoc为这段代码生成文档时并不将@MyAnnotation包含进去。生成的文档对Class1的描述如下:

            
class Class1extends java.lang.Object而如果这样定义MyAnnotation将会出现另一个结果。@Documented@interface MyAnnotation {}生成的文档:@MyAnnotation // 这行是在加上@Documented后被加上的class Class1extends java.lang.Object

Inherited

继承是java主要的特性之一。在类中的protected和public成员都将会被子类继承,但是父类的注释会不会被子类继承呢?很遗憾的告诉大家,在默认的情况下,父类的注释并不会被子类继承。如果要继承,就必须加上Inherited注释。

            
@Inherited@interface MyAnnotation { }@MyAnnotationpublic class ParentClass {}public class ChildClass extends ParentClass { }在以上代码中ChildClass和ParentClass一样都已被MyAnnotation注释了。

五、如何使用反射读取注释

前面讨论了如何自定义注释。但是自定义了注释又有什么用呢?这个问题才是J2SE5.0提供注释的关键。自定义注释当然是要用的。那么如何用呢?解决这个问题就需要使用java最令人兴奋的功能之一:反射(reflect)。 
在以前的JDK版本中,我们可以使用反射得到类的方法、方法的参数以及其它的类成员等信息。那么在J2SE5.0中同样也可以象方法一样得到注释的各种信息。

在使用反射之前必须使用import java.lang.reflect.* 来导入和反射相关的类。 
    如果要得到某一个类或接口的注释信息,可以使用如下代码:

Annotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);

如果要得到全部的注释信息可使用如下语句:
Annotation[] annotations = TestAnnotation.class.getAnnotations();

Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();

getDeclaredAnnotations与getAnnotations类似,但它们不同的是getDeclaredAnnotations得到的是当前成员所有的注释,不包括继承的。而getAnnotations得到的是包括继承的所有注释。

如果要得到其它成员的注释,可先得到这个成员,然后再得到相应的注释。如得到myMethod的注释。

            
Method method = TestAnnotation.class.getMethod("myMethod", null);Annotation annotation = method.getAnnotation(MyAnnotation.class);注:要想使用反射得到注释信息,这个注释必须使用@Retention(RetentionPolicy.RUNTIME)进行注释。

总结 
    注释是J2SE5.0提供的一项非常有趣的功能。它不但有趣,而且还非常有用。EJB3规范就是借助于注释实现的。这样将使EJB3在实现起来更简单,更人性化。还有Hibernate3除了使用传统的方法生成hibernate映射外,也可以使用注释来生成hibernate映射。总之,如果能将注释灵活应用到程序中,将会使你的程序更加简洁和强大。

Annotation在java的世界正铺天盖地展开,有空写这一篇简单的annotations的文章,算是关于Annotation入门的文章吧,希望能各位们能抛砖,共同学习...... 
   不讲废话了,实践才是硬道理.

第一部分:了解一下java1.5起默认的三个annotation类型: 
   一个是@Override:只能用在方法之上的,用来告诉别人这一个方法是改写父类的。 
   一个是@Deprecated:建议别人不要使用旧的API的时候用的,编译的时候会用产生警告信息,可以设定在程序里的所有的元素上. 
   一个是@SuppressWarnings:这一个类型可以来暂时把一些警告信息消息关闭. 
   如果不清楚上面三个类型的具体用法,各位可以baidu或google一下的,很简单的。

第二部分:讲一下annotation的概念先,再来讲一下怎样设计自己的annotation. 
   首先在jdk自带的java.lang.annotation包里,打开如下几个源文件: 
   
   1、源文件Target.java

Java代码  
  1. @Documented
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.ANNOTATION_TYPE)
  4. public @interface Target {
  5. ElementType[] value();
  6. }

其中的@interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字(会不会觉得sun有点吝啬,偏偏搞得与interface这么像). 
   
   2、源文件Retention.java

Java代码  
  1. @Documented
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.ANNOTATION_TYPE)
  4. public @interface Retention {
  5. RetentionPolicy value();
  6. }

看到这里,大家可能都模糊了,都不知道在说什么,别急,往下看一下. 
   在上面的文件都用到了RetentionPolicy,ElementType这两个字段,你可能就会猜到这是两个java文件.的确,这两个文件的源代码如下: 
   
   3、源文件RetentionPolicy.java

Java代码  
  1. public enum RetentionPolicy {
  2. SOURCE,
  3. CLASS,
  4. RUNTIME
  5. }

这是一个enum类型,共有三个值,分别是SOURCE,CLASS 和 RUNTIME. 
   SOURCE代表的是这个Annotation类型的信息只会保留在程序源码里,源码如果经过了编译之后,Annotation的数据就会消失,并不会保留在编译好的.class文件里面。 
   ClASS的意思是这个Annotation类型的信息保留在程序源码里,同时也会保留在编译好的.class文件里面,在执行的时候,并不会把这一些信息加载到虚拟机(JVM)中去.注意一下,当你没有设定一个Annotation类型的Retention值时,系统默认值是CLASS. 
   第三个,是RUNTIME,表示在源码、编译好的.class文件中保留信息,在执行的时候会把这一些信息加载到JVM中去的. 
  举一个例子,如@Override里面的Retention设为SOURCE,编译成功了就不要这一些检查的信息;相反,@Deprecated里面的Retention设为RUNTIME,表示除了在编译时会警告我们使用了哪个被Deprecated的方法,在执行的时候也可以查出该方法是否被Deprecated.

4、源文件ElementType.java

Java代码  
  1. public enum ElementType {
  2. TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,
  3. LOCAL_VARIABLE, ANNOTATION_TYPE,PACKAGE
  4. }

@Target里面的ElementType是用来指定Annotation类型可以用在哪一些元素上的.说明一下:TYPE(类型), FIELD(属性), METHOD(方法), PARAMETER(参数), CONSTRUCTOR(构造函数),LOCAL_VARIABLE(局部变量), ANNOTATION_TYPE,PACKAGE(包),其中的TYPE(类型)是指可以用在Class,Interface,Enum和Annotation类型上. 
   另外,从1的源代码可以看出,@Target自己也用了自己来声明自己,只能用在ANNOTATION_TYPE之上. 
   如果一个Annotation类型没有指明@Target使用在哪些元素上,那么它可以使用在任何元素之上,这里的元素指的是上面的八种类型. 
   举几个正确的例子: 
   @Target(ElementType.METHOD) 
   @Target(value=ElementType.METHOD) 
   @Target(ElementType.METHOD,ElementType.CONSTRUCTOR)   
   具体参考一下javadoc文档 
   
   上面一下1和2的源文件,它们都使用了@Documented,@Documented的目的就是让这一个Annotation类型的信息能够显示在javaAPI说明文档上;没有添加的话,使用javadoc生成API文档的时候就会找不到这一个类型生成的信息. 
   另外一点,如果需要把Annotation的数据继承给子类,那么就会用到@Inherited这一个Annotation类型. 
   
   第三部分:下面讲的设计一个最简单的Annotation例子,这一例子共用四个文件; 
   1、Description.java

Java代码  
  1. package lighter.iteye.com;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Target(ElementType.TYPE)
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Documented
  10. public @interface Description {
  11. String value();
  12. }

说明:所有的Annotation会自动继承java.lang.annotation这一个接口,所以不能再去继承别的类或是接口. 
   最重要的一点,Annotation类型里面的参数该怎么设定: 
   第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型. 
   第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String. 
   第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:上面的例子就只有一个参数成员.

2、Name.java

Java代码  
  1. package lighter.iteye.com;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. //注意这里的@Target与@Description里的不同,参数成员也不同
  8. @Target(ElementType.METHOD)
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @Documented
  11. public @interface Name {
  12. String originate();
  13. String community();
  14. }

3、JavaEyer.java

Java代码  
  1. package lighter.iteye.com;
  2. @Description("javaeye,做最棒的软件开发交流社区")
  3. public class JavaEyer {
  4. @Name(originate="创始人:robbin",community="javaEye")
  5. public String getName()
  6. {
  7. return null;
  8. }
  9. @Name(originate="创始人:江南白衣",community="springside")
  10. public String getName2()
  11. {
  12. return "借用两位的id一用,写这一个例子,请见谅!";
  13. }
  14. }

4、最后,写一个可以运行提取JavaEyer信息的类TestAnnotation

Java代码  
  1. package lighter.iteye.com;
  2. import java.lang.reflect.Method;
  3. import java.util.HashSet;
  4. import java.util.Set;
  5. public class TestAnnotation {
  6. /**
  7. * author lighter
  8. * 说明:具体关天Annotation的API的用法请参见javaDoc文档
  9. */
  10. public static void main(String[] args) throws Exception {
  11. String  CLASS_NAME = "lighter.iteye.com.JavaEyer";
  12. Class  test = Class.forName(CLASS_NAME);
  13. Method[] method = test.getMethods();
  14. boolean flag = test.isAnnotationPresent(Description.class);
  15. if(flag)
  16. {
  17. Description des = (Description)test.getAnnotation(Description.class);
  18. System.out.println("描述:"+des.value());
  19. System.out.println("-----------------");
  20. }
  21. //把JavaEyer这一类有利用到@Name的全部方法保存到Set中去
  22. Set<Method> set = new HashSet<Method>();
  23. for(int i=0;i<method.length;i++)
  24. {
  25. boolean otherFlag = method[i].isAnnotationPresent(Name.class);
  26. if(otherFlag) set.add(method[i]);
  27. }
  28. for(Method m: set)
  29. {
  30. Name name = m.getAnnotation(Name.class);
  31. System.out.println(name.originate());
  32. System.out.println("创建的社区:"+name.community());
  33. }
  34. }
  35. }

5、运行结果: 
     描述:javaeye,做最棒的软件开发交流社区 
     ----------------- 
    创始人:robbin 
    创建的社区:javaEye 
    创始人:江南白衣 
     创建的社区:springside

Java注释Override、Deprecated、SuppressWarnings详解相关推荐

  1. Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3

    Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3 总览 问题 详解 String.intern()的作用 link LeetCode的Two Sum题 ...

  2. 忽略警告注解@SuppressWarnings详解

    忽略警告注解@SuppressWarnings详解 简介:java.lang.SuppressWarnings是J2SE 5.0中标准的Annotation之一.可以标注在类.字段.方法.参数.构造方 ...

  3. Java并发编程最佳实例详解系列

    Java并发编程最佳实例详解系列: Java并发编程(一)线程定义.状态和属性 Java并发编程(一)线程定义.状态和属性 线程是指程序在执行过程中,能够执行程序代码的一个执行单元.在java语言中, ...

  4. 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...

  5. Java中的Runtime类详解

    Java中的Runtime类详解 1.类注释 /**Every Java application has a single instance of class Runtime that allows ...

  6. 转:Java 7 种阻塞队列详解

    转自: Java 7 种阻塞队列详解 - 云+社区 - 腾讯云队列(Queue)是一种经常使用的集合.Queue 实际上是实现了一个先进先出(FIFO:First In First Out)的有序表. ...

  7. tcp网络通信教程 java_基于java TCP网络通信的实例详解

    JAVA中设计网络编程模式的主要有TCP和UDP两种,TCP是属于即时通信,UDP是通过数据包来进行通信,UDP当中就会牵扯到数据的解析和传送.在安全性能方面,TCP要略胜一筹,通信过程中不容易出现数 ...

  8. java 配置文件的路径_详解java配置文件的路径问题

    详解java配置文件的路径问题 详解java配置文件的路径问题 各种语言都有自己所支持的配置文件,配置文件中有很多变量是经常改变的.不将程序中的各种变量写死,这样能更方便地脱离程序本身去修改相关变量设 ...

  9. Java包(package)详解

    Java包(package)详解 在编写Java程序时,随着程序架构越来越大,类的个数越来越多,这时候会发现管理程序中维护类名称也是一件很麻烦的事情,尤其是一些同名问题的发生.有时候,开发人员还可能需 ...

  10. Java开发常见面试题详解(JVM)_2

    Java开发常见面试题详解(JVM)_2 JVM 问题 详解 JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots link 你说你做过JVM调优和参数配置,请问如何盘点查看JVM系统默认 ...

最新文章

  1. 链表问题12——将单链表的每K个节点之间逆序
  2. java与scala的区别 个位数以内的 就喜欢作者这么言简意赅的
  3. 【Vista中系统准备工具存在隐患,自动清除用户资料】
  4. scala的多种集合的使用(8)之队列和栈的操作方法
  5. ASA 9.21 in Vmware Workstation 10
  6. Storm和Kafka集成的重要生产错误和修复
  7. Workbench has not been created yet
  8. 谷歌在华遭遇首例关键词官司
  9. postgresql编译安装
  10. 下标 获取字符_互联网人工智能编程语言Python的下标与切片详解
  11. python 递归函数_Python教程系列之递归函数与匿名函数调用
  12. 《用户网络行为画像》读书笔记(二)
  13. Selector提取数据1:XPath选择器
  14. Backdooring a OS VM
  15. 4.Mongodb之js脚本
  16. 2022年CISP报名考试详情
  17. N1刷入Armbian(Debian11 bullseye)笔记
  18. L1-5 试试手气(c++、数组)
  19. 了解操作系统,什么是操作系统Operation System?
  20. 神经网络重建治疗仪原理,神经网络修复视频教程

热门文章

  1. addroutes刷新_vue解决addRoutes多次添加路由重复的操作方法
  2. 【小白学习Keras教程】四、Keras基于数字数据集建立基础的CNN模型
  3. 在PPT的时候,发现用Python十几行代码就可以实现Logo换色
  4. 十二、深入Python列表和元组
  5. 你可能不需要固定词表:一种与词表无关的组合式词向量方法
  6. 基于深度学习的多目标跟踪算法——ReID与MOT的联系
  7. ACL 2020 | 基于稠密段落检索的开放域问答系统技术
  8. 实录分享 | 计算未来轻沙龙:“法律+AI”前沿研讨会(PPT下载)
  9. Face++ 论文解读:一种新的行人重识别度量学习方法 | PaperDaily #20
  10. Java软件开发:自定义MyBatis持久层框架