注解

我们为什么要学习注解?它可以替代配置文件
注解的使用:
    分如下三步来学习!!!
    一:定义注解类(一般都是框架干的)
    二:使用注解   (开发人员!)
    三:读取注解  (一般都是框架干的:因为注解最终是代替配置文件,而配置文件最终是要被读取的!)
    注:注解也是个类,所有的注解都是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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章