Java中注解&泛型

  • Post author:
  • Post category:java



1.注解(Annotation):

注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,如果没加则没有标记,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无标记,有什么标记,就去干相应的事.标记可以加在包,类,字段,方法,方法的参数以及局部变量上,看java.lang包,可看到JDK中提供的最基本的annotation.

三种基本注解:

@SuppressWarnings(“deprecation”)

@Deprecated

@Override

public class AnnotationTest {

	@SuppressWarnings("deprecation")
	/*
	 * @SuppressWarnings("deprecation")//指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中会
	 * 取消编译器在编译时对方法过时发出的警告(SuppressWarning:抑制警告),即使main方法中用到过时方法也不会发出警告
	 */
	public static void main(String[] args) {
		System.runFinalizersOnExit(true);
		DeprecatedTest.say();
	}

}

class DeprecatedTest {
	@Deprecated // 表明say方法已过时,这样做好处:以前仍使用该代码的开发人员依然程序可以执行成功
	// 后来的开发人员在看到这个标记:爷们,这个方法过时了,尽量别用,你看看有没有别的替代方法,在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告.
	public static void say() {
		System.out.println("say sth...");
	}
}

class Person {
	private String name;
	private int age;

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override // 加上这个说明一定要复写,不复写在编译时期发生:
				// AnnotationTest.java:45: 错误: 方法不会覆盖或实现超类型的方法
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

}

注解的生命周期:

Retention(保留):

注解的生命周期:

RetentionPolicy.SOURCE:

仅仅给编译器看的,编译器检查完丢掉

例如:@Override 强制要求复写掉父类方法->不复写编译时期报错

@SuppressWarnings 抑制警告->编译器:不让我警告我就什么也不报

RetentionPolicy.CLASS:(默认)

从.java保留到.class但是被类加载器加载到虚拟机中时会去掉

例如:通过反射将拿不到注解类的实例

RetentionPolicy.RUNTIME:

直到运行阶段注解依然存在

例如:@Deprecated:不但在编译时期检测方法是否过时,在运行时期依然会检测方法的字节码

自定义注解与为注解添加属性:

元注解:注解上的注解,例如@Retention,@Target

public @interface MetaAnnotation {
	  String value() default "Meta";
}
// 反编译:
public interface Test extends Annotation {
	public abstract String value();
}

package temp;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE }) // TYPE:Type 是 Java
													// 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。													// 在这里TYPE表示:类、接口(包括注释类型)或枚举声明													// Target这个注解指明下面的自定义注解可以使用的位置
public @interface CustomAnnotation {
	// 有一个抽象方法
	public abstract String color() default "black";// 为注解增加了一个属性color													// 指定默认值为black
	String value() default "white";// 增加一个value属性
	int[] arrAttri() default { 1, 2, 3 };// arrAttri属性类型为int[]
	TrafficLamp lamp() default TrafficLamp.RED; // lamp属性类型为枚举
	Class<?> cls() default CustomAnnotation.class;// 属性类型为Class
	// 较为复杂
	MetaAnnotation ma() default @MetaAnnotation("MetaAnnotation");// 属性类型为一个注解类型,																	// 默认值是MetaAnnotation一个实例对象
}

/*
 * ElementType的枚举常量: ANNOTATION_TYPE 注释类型声明 CONSTRUCTOR 构造方法声明 FIELD
 * 字段声明(包括枚举常量) LOCAL_VARIABLE 局部变量声明 METHOD 方法声明 PACKAGE 包声明 PARAMETER 参数声明
 * TYPE 类、接口(包括注释类型)或枚举声明
 */

使用注解中的属性:

@CustomAnnotation
public class AnnotationDemo {

	public static CustomAnnotation getAnnotationOnMethod(String methodName) throws Exception {
		Method method = AnnotationDemo.class.getMethod(methodName);
		return method.getAnnotation(CustomAnnotation.class);
	}
	@CustomAnnotation("black") // 应用注解的属性
								// 如果注解类中有一个属性为String
								// value();(不一定为String,只要属性名为value均可)
								// 可以将value="black"等价于"black"(即其他属性都采用默认值或者你只有一个value属性)
								// 例如:@Retention(RetentionPolicy.RUNTIME)-->内部属性RetentionPolicy
								// value();
	public static void value() throws Exception {
		CustomAnnotation ca = getAnnotationOnMethod("value");
		System.out.println("value: " + ca.value());// black
	}
	@CustomAnnotation(arrAttri = { 4, 5 }) // 如果数组元素只有一个简写为arrAttri=6
	public static void arrAttri() throws Exception {
		CustomAnnotation ca = getAnnotationOnMethod("arrAttri");
		System.out.println("arrAttri: " + ca.arrAttri().length);// 2
	}
	@CustomAnnotation(lamp = TrafficLamp.RED)
	public static void lamp() throws Exception {
		CustomAnnotation ca = getAnnotationOnMethod("lamp");
		System.out.println("lamp: " + ca.lamp().nextLamp());// GREEN
	}
	@CustomAnnotation(ma = @MetaAnnotation("ma"))
	public static void metaAnnotation() throws Exception {
		CustomAnnotation ca = getAnnotationOnMethod("metaAnnotation");
		System.out.println("ma: " + ca.ma().value());
	}
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		CustomAnnotation ca = AnnotationDemo.class.getAnnotation(CustomAnnotation.class);// 将获取类AnnotationDemo上的CustomAnnotation注解的一个实例,没有返回null
		System.out.println(ca + "\n");
		value();
		arrAttri();
		lamp();
		metaAnnotation();
	}
}


2.泛型

泛型&反射:

package temp;
/*
泛型术语:
 ArrayList<E>:泛型类型
             :E称为类型变量/类型参数
 ArrayList<Integer>:参数化的类型
                   :Integer称为实际类型参数              
                    :<>typeof
  ArrayList:原始类型(rawtype)
*/

import java.lang.reflect.Constructor;

public class GenericDemo1 {

	public static void main(String[] args) throws Exception {
		/*
		 * Class<T>: T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是
		 * Class<String>。如果将被建模的类未知,则使用 Class<?>。 Constructor<T> T -在其中声明构造方法的类。
		 * public T newInstance(Object... initargs)//返回值类型为T
		 */
		Constructor<String> con = String.class.getConstructor();
		String str = con.newInstance();
	}

}
/*
 * 未使用泛型前,集合中可以存入任意引用类型的元素(Object)->安全隐患->在取出元素时进行强转->运行时可能发生ClassCastException
 * 使用泛型后,限定集合中的元素类型为一个特定类型,集合中只能存储同一个类型的对象 1.将运行时期的的安全隐患转移到了编译时期 2.避免了强制转换的麻烦
 */

类型参数的类型判断

/*
 类型参数的类型推断总结:
1.
  static <E> void swap(E[] a, int i, int j)
  swap(new String[3],3,4)
  ->推断出E为String

2.
  static <T> void add(T a, T b) 
  add(3,5)
  T->Integer
 
  static <T> void add(T a, T b) 
  add(3.1,5)
  T->Number//取两者最小父类
 
  static <T> T add(T a, T b) 
  Number num=add(3.1,5)
    这时候以返回值的实际参数类型为主:String->T->String,编译器报错,Number num=add(3.1,5)可以

3.
     static <T> void copy(T[] a,T[]  b)
     copy(new Integer[5],new String[5])
     OK,编译器推断出类型变量T为Number
     
     static <T> void copy(Collection<T> a , T[] b)
     copy(new Vector<String>(), new Integer[5])
           编译器报错:根据参数化的Vector类实例将类型变量直接确定为String类型->
                   T就是String,那么第二个形参的类型变量T为String
*/

如何获取泛型中的实际类型参数:

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;

public class GenericReflect {

	public static void main(String[] args) throws Exception {
		// 如何通过反射来获得泛型中的实际类型参数?
		// 必须通过一个方法来获取,因为方法对象提供有获取形参类型的方法,由于泛型的实际类型参数在编译后被擦除,不能直接通过反射获取
		Method method = GenericReflect.class.getMethod("getParas", HashMap.class);
		Type[] type = method.getGenericParameterTypes();// 如果形参类型是参数化类型,则为其返回的对象必须实际反映源代码中使用的实际类型参数如果形参类型是类型变量或参数化类型,则创建它。否则将解析它。
		System.out.println(type[0]);
		// System.out.println(actua	lType[0] + "\n" + actualType[1]);
	}

	/* 通过反射获取泛型中的实际类型参数 */
	public static void getParas(HashMap<Integer, String> hs) {

	}
}