27、注解
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。
内置的注解:
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
作用在代码的注解是:
@Override: 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated: 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(或者说 元注解)是:
@Retention 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented 标记这些注解是否包含在用户文档中。
@Target 标记这个注解应该是哪种 Java 成员。
@Inherited 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
从 Java 7 开始,额外添加了 3 个注解:
@SafeVarargs Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
一、Annotation 架构
- 每1个Annotation对象,都会有唯一的RetentionPolicy属性。
- 对于每 1 个 Annotation 对象,可以有若干个 ElementType 属性。
- Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override 等等。Annotation 的每一个实现类,都 “和 1 个 RetentionPolicy 关联” 并且 " 和 1~n 个 ElementType 关联"。
二、Annotation 组成部分
java Annotation 的组成中,有 3 个非常重要的主干类。它们分别是:
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
package java.lang.annotation;
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE /* 包声明 */
}
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}
三、java 自带的 Annotation
1、Annotation 通用定义
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}
2、常用的 Annotation
- @Deprecated: @Deprecated 所标注内容,不再被建议使用。
- @Override: @Override 只能标注方法,表示该方法覆盖父类中的方法。
- @Documented: @Documented 所标注内容,可以出现在javadoc中。
- @Inherited: @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
- @Retention: @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
- @Target: @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
- @SuppressWarnings: @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
四、Annotation 的作用
Annotation 是一个辅助类,它在 Junit、Struts、Spring 等工具框架中被广泛使用。
我们在编程中经常会使用到的 Annotation 作用有:
1、编译检查
Annotation 具有"让编译器进行编译检查的作用"。
@SuppressWarnings, @Deprecated 和 @Override 都具有编译检查作用。
public class OverrideTest {
/**
* toString() 在java.lang.Object中定义;
* 因此,这里用 @Override 标注是对的。
*/
@Override
public String toString(){
return "Override toString";
}
/**
* getString() 没有在OverrideTest的任何父类中定义;
* 但是,这里却用 @Override 标注,因此会产生编译错误!
*/
@Override
public String getString(){
return "get toString";
}
public static void main(String[] args) {
}
}
2、在反射中使用 Annotation
在反射的 Class, Method, Field 等函数中,有许多于 Annotation 相关的接口。
这也意味着,我们可以在反射中解析并使用 Annotation。
import java.lang.annotation.Annotation;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Inherited;
import java.lang.reflect.Method;
/**
* Annotation在反射函数中的使用示例
*/
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String[] value() default "unknown";
}
/**
* Person类。它会使用MyAnnotation注解。
*/
class Person {
/**
* empty()方法同时被 "@Deprecated" 和 "@MyAnnotation(value={"a","b"})"所标注
* (01) @Deprecated,意味着empty()方法,不再被建议使用
* (02) @MyAnnotation, 意味着empty() 方法对应的MyAnnotation的value值是默认值"unknown"
*/
@MyAnnotation
@Deprecated
public void empty(){
System.out.println("\nempty");
}
/**
* sombody() 被 @MyAnnotation(value={"girl","boy"}) 所标注,
* @MyAnnotation(value={"girl","boy"}), 意味着MyAnnotation的value值是{"girl","boy"}
*/
@MyAnnotation(value={"girl","boy"})
public void somebody(String name, int age){
System.out.println("\nsomebody: "+name+", "+age);
}
}
public class AnnotationTest {
public static void main(String[] args) throws Exception {
// 新建Person
Person person = new Person();
// 获取Person的Class实例
Class<Person> c = Person.class;
// 获取 somebody() 方法的Method实例
Method mSomebody = c.getMethod("somebody", new Class[]{String.class, int.class});
// 执行该方法
mSomebody.invoke(person, new Object[]{"jiuling", 22});
iteratorAnnotations(mSomebody);
// 获取 somebody() 方法的Method实例
Method mEmpty = c.getMethod("empty", new Class[]{});
// 执行该方法
mEmpty.invoke(person, new Object[]{});
iteratorAnnotations(mEmpty);
}
public static void iteratorAnnotations(Method method) {
// 判断 somebody() 方法是否包含MyAnnotation注解
if(method.isAnnotationPresent(MyAnnotation.class)){
// 获取该方法的MyAnnotation注解实例
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
// 获取 myAnnotation的值,并打印出来
String[] values = myAnnotation.value();
for (String str:values)
System.out.printf(str+", ");
System.out.println();
}
// 获取方法上的所有注解,并打印出来
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation);
}
}
}
输出结果:
somebody: jiuling, 22
girl, boy,
@com.skywang.annotation.MyAnnotation(value=[girl, boy])
empty
unknown,
@com.skywang.annotation.MyAnnotation(value=[unknown])
@java.lang.Deprecated()
3、根据 Annotation 生成帮助文档
通过给 Annotation 注解加上 @Documented 标签,能使该 Annotation 标签出现在 javadoc 中。
4、能够帮忙查看查看代码
通过 @Override, @Deprecated 等,能很方便的了解程序的大致结构。也可以通过自定义 Annotation 来实现一些功能。
28、集合【Collection】
一、Collection
集合的结构图:
1、List【有序,可重复】
- ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高 - Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低 - LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高
2、Set【无序,唯一】
-
HashSet
- 底层数据结构是哈希表。(无序,唯一)
- 怎么保证元素唯一性?
1、实现hashCode()方法
2、实现equals()方法
-
LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1、由链表保证元素有序
2、由哈希表保证元素唯一 -
TreeSet
SortedSet是个接口,它里面的(只有TreeSet这一个实现可用)中的元素一定是有序的。底层数据结构是红黑树。(唯一,有序)
1、如何保证元素排序的呢?
自然排序
比较器排序
2、如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
3、Queue
- Queue接口与List、Set同一级别,都是继承了Collection接口。看图你会发现,LinkedList既可以实现Queue接口,也可以实现List接口.只不过呢, LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。
注意事项:
List【不唯一】:
- 线程是否安全:
是:Vector
否:ArrayList或者LinkedList
如果知道是List,但是不知道是哪个List,就用ArrayList。 - 查询多:ArrayList
增删多:LinkedList
Set【唯一】:
- 排序:
是:TreeSet或LinkedHashSet
否:HashSet
如果知道是Set,但是不知道是哪个Set,就用HashSet。
二、Map
1、Map实现类的分类:
- Hashtable
无序的、方法是同步的、线程安全、效率较低、不允许null值、父类是Dictionary - HashMap
无序的、方法不是同步的、线程不安全、效率较高、允许null值(key和value都允许)、父类是AbstractMap - LinkedHashMap
无序的 - TreeMap
有序的
2、TreeSet、LinkedHashSet和HashSet 的区别:
- TreeSet的主要功能用于排序
- LinkedHashSet的主要功能用于保证FIFO即有序的集合(先进先出)
- HashSet只是通用的存储数据的集合
相同点:
- Duplicates elements: 因为三者都实现Set interface,所以三者都不包含duplicate elements
- Thread safety: 三者都不是线程安全的,如果要使用线程安全可以Collections.synchronizedSet()
不同点:
- Performance and Speed: HashSet插入数据最快,其次LinkHashSet,最慢的是TreeSet因为内部实现排序
- Ordering: HashSet不保证有序,LinkHashSet保证FIFO即按插入顺序排序,TreeSet安装内部实现排序,也可以自定义排序规则
- null:HashSet和LinkHashSet允许存在null数据,但是TreeSet中插入null数据时会报NullPointerException
代码比较:
public static void main(String args[]) {
HashSet<String> hashSet = new HashSet<>();
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
TreeSet<String> treeSet = new TreeSet<>();
for (String data : Arrays.asList("B", "E", "D", "C", "A")) {
hashSet.add(data);
linkedHashSet.add(data);
treeSet.add(data);
}
//不保证有序
System.out.println("Ordering in HashSet :" + hashSet);
//FIFO保证安装插入顺序排序
System.out.println("Order of element in LinkedHashSet :" + linkedHashSet);
//内部实现排序
System.out.println("Order of objects in TreeSet :" + treeSet);
}
输出结果:
Ordering in HashSet :[A, B, C, D, E] (无顺序)
Order of element in LinkedHashSet :[B, E, D, C, A] (FIFO插入有序)
Order of objects in TreeSet :[A, B, C, D, E] (排序)
小结:
注解: 注解是很重要的一个部分!尤其是在后面的WEB、框架、以及中间件和微服务中运用的特别的多。可见它的地位有多么的重要了!当学习完注解以后,在未来的道路上会有特别多的收获!
集合: 集合是未来存储各种类型的一种方式,它比数组快,但是底层仍然是靠数组实现的!它的效率更加高!因此,要好好的学习集合!为以后的学习奠定良好的基础!
总结:
这个世界是美好的,生活是多姿多彩的!今天是6月6号,数字很吉利!最近一直在想Java基础的知识点!大部分的知识点基本上已经快更新完了!还有六篇博客就更新结束了!正在想后面的六篇博客写一些什么文案给各位小伙伴!真的有些让人头疼!
今天的博客就先写到这里!或者后面的六篇博客写一些以后的学习方向和一些个人的所见所闻!Java是一个大的生态体系!除了Java,还应该学习底层的C语言和数据结构、设计模式,还有后期的Redis缓存和消息中间件,网络中的Netty框架,以及微服务这些。只能说学无止境,需要多去学习,才能更好的进步!
如果本篇博客对大家有帮助,希望大家能够点赞、关注!在此先谢过各位小伙伴了!
最后,愿我们都能在各行各业中能够取得不同的成就,不负亲人、朋友、老师、长辈和国家的期望!能够用自身的所学知识为国家贡献出自己的一份力量!一起加油!
2021年6月6日夜