@@ -296,13 +296,17 @@ name "sec:JDK中的注解"
296296\end_layout
297297
298298\begin_layout Standard
299- 注解既然不是合法的Java关键字,Java编译器是如何识别和处理注解的呢?java编译器中已经内置了以下注解的处理器 :
299+ 注解既然不是合法的Java关键字,Java编译器是如何识别和处理注解的呢?截止到Java 8,Java编译器中已经内置了以下注解的处理逻辑,因此可以直接使用 :
300300\end_layout
301301
302- \begin_layout Description
303- @Override 表示子类覆盖(重写)了父类中的同名方法。考虑一种情形:在父类中的方法名为oneMehtod(),我们的本意是在子类中重写父类的oneMeth
304- od()方法,却无意中写成了one1Method()。如果没有使用@Override注解,编译器会认为子类定义了一个新的方法,而不是覆盖了父类的同名方法。如果使
305- 用了@Override注解了one1Method()方法,编译器会报告一个错误:
302+ \begin_layout Subsection
303+ @Override
304+ \end_layout
305+
306+ \begin_layout Standard
307+ @Override表示子类覆盖(重写)了父类中的同名方法。考虑一种情形:在父类中的方法名为oneMehtod(),我们的本意是在子类中重写父类的oneMetho
308+ d()方法,却无意中写成了one1Method()。如果没有使用@Override注解,编译器会认为子类定义了一个新的方法,而不是覆盖了父类的同名方法。如果使用
309+ 了@Override注解了one1Method()方法,编译器会报告一个错误:
306310\begin_inset Quotes erd
307311\end_inset
308312
@@ -331,12 +335,25 @@ https://github.com/subaochen/java-tutorial/tree/master/advance/code/annotation
331335
332336\end_inset
333337
334- 。可以看出,@Override注解杜绝了我们无意中的疏忽,因此现代的IDE在产生(插入)重写方法时,都会自动在方法上使用@Override注解。
338+ 。可以看出,@Override注解杜绝了我们无意中的疏忽,因此现代的IDE在产生(插入)重写方法时,都会自动在方法上使用@Override注解。在编程实践中,应
339+ 该坚持使用@Override注解
340+ \begin_inset CommandInset citation
341+ LatexCommand cite
342+ after "p152"
343+ key "effective-java"
344+
345+ \end_inset
346+
347+ ,即需要使用@Override注解的地方就一定使用@Override注解。
335348\end_layout
336349
337- \begin_layout Description
338- @Deprecated 表示该元素已经被遗弃,后续版本可能删除此元素,尽量不要使用这些元素。@Deprecated可以用于类、方法和属性,如果在程序中引用了@D
339- eprecated的元素,编译器会给出一条警告信息。一般的,当元素被注解为@Deprecated时,在Javadoc中也相应的使用@deprecated
350+ \begin_layout Subsection
351+ @Deprecated
352+ \end_layout
353+
354+ \begin_layout Standard
355+ @Deprecated表示该元素已经被遗弃,后续版本可能删除此元素,尽量不要使用这些元素。@Deprecated可以用于类、方法和属性,如果在程序中引用了@De
356+ precated的元素,编译器会给出一条警告信息。一般的,当元素被注解为@Deprecated时,在Javadoc中也相应的使用@deprecated
340357\begin_inset Foot
341358status open
342359
@@ -386,26 +403,252 @@ public void method() {...}
386403
387404\end_layout
388405
406+ \begin_layout Subsection
407+ @SupressWarnings
408+ \end_layout
409+
410+ \begin_layout Standard
411+ @SupressWarnings表示忽略某些编译时的警告信息,目前Java编译器定义了两种类型的警告信息可以用于此注解:
412+ \end_layout
413+
389414\begin_layout Description
390- @SupressWarnings 表示忽略某些编译或者运行时的警告信息。
415+ unchecked 使用泛型类时如果没有指定类型,则编译器会报告unchecked警告,即编译器抱怨无法进行类型检查。通常我们应该重视unchecked警告,设
416+ 法消除uncheck警告。但是如果无法消除警告,同时可以证明引起警告的代码类型是安全的,则可以使用@SupressWarnings(
417+ \begin_inset Quotes eld
418+ \end_inset
419+
420+ unchecked
421+ \begin_inset Quotes erd
422+ \end_inset
423+
424+ )通知编译器忽略此警告
425+ \begin_inset CommandInset citation
426+ LatexCommand cite
427+ after "p103"
428+ key "effective-java"
429+
430+ \end_inset
431+
432+ 。
433+ \end_layout
434+
435+ \begin_layout Description
436+ deprecation 忽略调用过时方法的警告。
437+ \end_layout
438+
439+ \begin_layout Subsection
440+ @SafeVarargs
391441\end_layout
392442
393443\begin_layout Standard
394- 也就是说,Java编译器已经内置了这三个注解的处理逻辑,因此我们可以在代码中直接使用这三个注解。除此之外,Java编译器不能识别其他的注解。
444+ @SafeVarargs在JDK 7中引入,主要目的是处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的。可变长参数是使用数组存储的,而
445+ 数组和泛型不能很好的混合使用
446+ \begin_inset CommandInset citation
447+ LatexCommand cite
448+ after "p105,第25条:列表优先于数组"
449+ key "effective-java"
450+
451+ \end_inset
452+
453+ ,因此当在可变长参数中使用泛型时,编译器会给出警告信息。考虑
454+ \begin_inset ERT
455+ status open
456+
457+ \begin_layout Plain Layout
458+
459+
460+ \backslash
461+ lstlistingname
462+ \end_layout
463+
464+ \end_inset
465+
466+
467+ \begin_inset CommandInset ref
468+ LatexCommand ref
469+ reference "SafeVarargsTest.java"
470+
471+ \end_inset
472+
473+
474+ \end_layout
475+
476+ \begin_layout Standard
477+ \begin_inset CommandInset include
478+ LatexCommand lstinputlisting
479+ filename "code/annotation/src/cn/edu/sdut/softlab/safevarargs/SafeVarargsTest.java"
480+ lstparams "caption={可安全忽略的编译警告示例:SafeVarargsTest.java},label={SafeVarargsTest.java}"
481+
482+ \end_inset
483+
484+
485+ \end_layout
486+
487+ \begin_layout Standard
488+ 当我们使用-Xlint:unchecked参数编译此代码时
489+ \begin_inset Foot
490+ status open
491+
492+ \begin_layout Plain Layout
493+ 如果使用IDE进行编译,需要修改编译参数,增加-Xlint:unchecked编译选项。
494+ \end_layout
495+
496+ \end_inset
497+
498+ ,有如下的警告信息:
395499\end_layout
396500
397501\begin_layout Standard
398- 不过,我们可以通过编写注解处理器传入Java编译器扩展编译器识别和处理注解的能力。以@author为例?
502+ \begin_inset Box Shaded
503+ position "t"
504+ hor_pos "c"
505+ has_inner_box 1
506+ inner_pos "t"
507+ use_parbox 0
508+ use_makebox 0
509+ width "100col%"
510+ special "none"
511+ height "1in"
512+ height_special "totalheight"
513+ thickness "0.4pt"
514+ separation "3pt"
515+ shadowsize "4pt"
516+ framecolor "black"
517+ backgroundcolor "none"
518+ status open
519+
520+ \begin_layout Plain Layout
521+ $ javac -Xlint:unchecked cn/edu/sdut/softlab/safevarargs/SafeVarargsTest.java
522+
523+ \end_layout
524+
525+ \begin_layout Plain Layout
526+ cn/edu/sdut/softlab/safevarargs/SafeVarargsTest.java:18: 警告: [unchecked]
527+ 参数化 vararg 类型T的堆可能已受污染
528+ \end_layout
529+
530+ \begin_layout Plain Layout
531+ public static <T> void showArgs(T...
532+ array) {
533+ \end_layout
534+
535+ \begin_layout Plain Layout
536+ ^
537+ \end_layout
538+
539+ \begin_layout Plain Layout
540+ 其中, T是类型变量:
541+ \end_layout
542+
543+ \begin_layout Plain Layout
544+ T扩展已在方法 <T>showArgs(T...)中声明的Object
545+ \end_layout
546+
547+ \begin_layout Plain Layout
548+ 1 个警告
549+ \end_layout
550+
551+ \end_inset
552+
553+
554+ \end_layout
555+
556+ \begin_layout Standard
557+ 但是显然在这个示例中,可变参数的泛型是安全的,因此可以启用
558+ \begin_inset ERT
559+ status open
560+
561+ \begin_layout Plain Layout
562+
563+
564+ \backslash
565+ lstlistingname
566+ \end_layout
567+
568+ \end_inset
569+
570+
571+ \begin_inset CommandInset ref
572+ LatexCommand ref
573+ reference "SafeVarargsTest.java"
574+
575+ \end_inset
576+
577+ 中的@SafeVarargs注解消除这个警告信息。请读者自行验证。
578+ \end_layout
579+
580+ \begin_layout Standard
581+ @SafeVarargs注解只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误
399582\begin_inset Note Note
400583status open
401584
402585\begin_layout Plain Layout
403- 参考《深入了解Java虚拟机》
586+ but why?
587+ \end_layout
588+
589+ \end_inset
590+
591+ 。一个方法使用@SafeVarargs注解的前提是,开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题,否则可能导致运行时的类型转换异常,
592+ 比如
593+ \begin_inset ERT
594+ status open
595+
596+ \begin_layout Plain Layout
597+
598+
599+ \backslash
600+ lstlistingname
601+ \end_layout
602+
603+ \end_inset
604+
605+
606+ \begin_inset CommandInset ref
607+ LatexCommand ref
608+ reference "UnsafeMethodTest.java"
609+
610+ \end_inset
611+
612+ 。
613+ \end_layout
614+
615+ \begin_layout Standard
616+ \begin_inset CommandInset include
617+ LatexCommand lstinputlisting
618+ filename "code/annotation/src/cn/edu/sdut/softlab/safevarargs/UnsafeMethodTest.java"
619+ lstparams "caption={并不安全的@SafeVarargs:UnsafeMethodTest.java},label={UnsafeMethodTest.java}"
620+
621+ \end_inset
622+
623+
624+ \end_layout
625+
626+ \begin_layout Subsection
627+ @FunctionalInterface
628+ \end_layout
629+
630+ \begin_layout Standard
631+ JDK 8中引入了@FunctionalInterface注解,表示所声明的类型为函数接口,详情参见
632+ \begin_inset ERT
633+ status open
634+
635+ \begin_layout Plain Layout
636+
637+
638+ \backslash
639+ sectionname
404640\end_layout
405641
406642\end_inset
407643
408644
645+ \begin_inset CommandInset ref
646+ LatexCommand vref
647+ reference "chap:lambda表达式"
648+
649+ \end_inset
650+
651+ 。
409652\end_layout
410653
411654\begin_layout Section
@@ -432,6 +675,20 @@ name "sec:注解处理器"
432675\end_inset
433676
434677
678+ \end_layout
679+
680+ \begin_layout Standard
681+ 我们可以通过编写注解处理器传入Java编译器扩展编译器识别和处理注解的能力。以@author为例?
682+ \begin_inset Note Note
683+ status open
684+
685+ \begin_layout Plain Layout
686+ 参考《深入了解Java虚拟机》
687+ \end_layout
688+
689+ \end_inset
690+
691+
435692\end_layout
436693
437694\begin_layout Section
0 commit comments