我们为什么要学习注解?它可以替代配置文件
注解的使用:
分如下三步来学习!!!
一:定义注解类(一般都是框架干的)
二:使用注解 (开发人员!)
三:读取注解 (一般都是框架干的:因为注解最终是代替配置文件,而配置文件最终是要被读取的!)
注:注解也是个类,所有的注解都是Annotation的实现类
一:定义注解类
1.1 定义注解类,那么怎么定义呢?
@interface xxx{
}
1.2 定义注解里面的属性
@MyAnno1
interface Test2{
//里面只存在属性,当然这里属性的格式比较特殊,后面又加个()
String name();
int age() default 22;
}
1.3注意:
a.定义属性时还可以指定默认值,就像上面的age属性一样
b.在注解中定义完属性后,那么使用注解的时候必须为注解中的属性赋值,否则会报错!(有默认值的可以除外)
c.名为value属性的特权
public @interface MyAnno {
String value();
int age() default 22;
}
@MyAnno(value = "hello")
class Demo{
}
//如果只写一个属性的话,那么value可以省掉
@MyAnno("hello")
class Demo2{
}
d.注解中属性的类型有限制!!,只能是如下几种!!!
8种基本类型
String
Enum
Class
注解类型
以上类型的一维数组类型【就我说的这几种,没别的了】
注:当给数组类型的属性赋值时,假如数组元素的个数为1时,此时可以不写{}
e.使用注解并为注解里面的属性赋值!
//使用注解,注意点【为注解的属性赋值时,注解类型和数组的写法需要注意一下】
@MyAnno1(
a=22,
b="wzj",
c=MyEnum.APPLE,
d=String.class,
e=@MyAnno2(city = "zhuzhou"),
f= {1,2,3}
)
class Test{
}
//注解中属性的类型可以有哪些!
public @interface MyAnno1 {
int a(); //8种基本数据类型
String b();//Stirng
MyEnum c(); //枚举
Class d(); //Class类型
MyAnno2 e();//注解类型
int[] f(); //以上的一维数组类型!
}
@interface MyAnno2{
String city();
String address() default "youxian";
}
enum MyEnum{
APPLE,PEAR
}
二:使用注解 (开发人员!)
如上注解已经定义好了, 那么我们可以在类的哪些地方使用呢?(也就是注解的作用目标)
注解的作用目标
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
由上可以知道:注解几乎可以在类的任何地方使用【连局部变量上都行!!】
2.1注解的作用目标限定:@Target
只时候就可以请出@Target注解了
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
//这时重写的那个注解的源码,我们可以看到Target里面的属性类型
//既不是8种基本数据类型,也不是Class和String,所以只能是枚举了,
//而且不用写属性名,说明@Target注解里面有value属性,而且可能只有一个
}
那么我现在不想让它在这么多的目标上可以使用,假如我只想让它在类上那么这么办?
@Target(ElementType.TYPE)
public @interface MyAnno {
String value();
int age() default 22;
}
@MyAnno(value = "hello")
class Demo{
@MyAnno(value = "hello")
public void method() {} //这个地方会报错,因为我限定了这个注解只能在类上使用!
}
2.2:保留策略 @Retention(RetentionPolicy.SOURCE/CLASS/RUNTIME)
源代码文件(SOURCE):注解只在源代码中存在,当编译时就被忽略了
字节码文件(CLASS):注解在源代码中存在,然后编译时会把注解信息放到了class文件,但JVM在加载类时,会忽略注解!JVM中(RUNTIME):注解在源代码、字节码文件中存在,并且在JVM加载类时,会把注解加载到JVM内存中(它是唯一可反射注解!)
三:读取注解,也就是使用反射注解,读取注解里面的属性值!
使用反射注解,保留策略必须为@Retention(RetentionPolicy.RUNTIME) 才可以!!!
两个方法:
getAnnotation(); 获取作用目标上指定类型的注解!!
getAnnotations(); 获取作用目标上所有的注解!!
public class Demo1 {
public static void main(String[] args) throws Exception {
//思路:得到作用目标,获取指定类型的注解!
//获取注解上的值!
Class<A> a = A.class;
MyAnno1 anno1 = a.getAnnotation(MyAnno1.class);//注解也是一个类!
System.out.println("name:"+anno1.name()+"\tage:"+anno1.age()+"\tsex:"+anno1.sex());
//获取方法上的注解的值
Method method = a.getMethod("a"); //getMethod(name, parameterTypes); 第二个参数是可变参数直接可以不给!
MyAnno1 annoOnMethod = method.getAnnotation(MyAnno1.class);
System.out.println("name:"+annoOnMethod.name()+"\tage:"+annoOnMethod.age()+"\tsex:"+annoOnMethod.sex());
}
}
@MyAnno1(name = "wzj",age = 22)
class A{
@MyAnno1(name = "tom",age = 10)
public void a() {
}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno1{
String name();
int age();
char sex() default '男';
}
最后:加一个反射泛型的Demo
public class Demo1 {
public static void main(String[] args) {
//需求:在父类中得到子类传过来的类型参数!!
new C();
}
}
class A<T>{
public A() {
//在这里面得到子类的类型参数!,this为什么是子类对象,而不是父类对象!
// Class clazz = this.getClass();
// Type type = clazz.getGenericSuperclass(); //获取传递给父类的参数化类型
// ParameterizedType ptype = (ParameterizedType) type;
// Type[] types = ptype.getActualTypeArguments();
// Class c = (Class) types[0];
// System.out.println(c.getSimpleName());
Class c = (Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];//ParameterizedType:参数化类型
System.out.println(c.getSimpleName());
}
}
//<String>: 就是类型参数
class B extends A<String>{
public B() {
//那么子类继承了父类的构造方法吗
super();
}
}
class C extends A<Integer>{
}
来自一个虽然帅,但是菜的cxy