黑马程序员 高新技术 注解和泛型

时间:2022-03-06 11:30:59

 ----------android培训 java培训 期待与您交流! ----------

第一节 了解和入门注解的应用

一.概述:

注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于

没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上

有无任何标记。看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。

注解的作用:

用于告诉编译器,向它传递一种信息。

注解可以加载类上,方法上,包上,成员变量上,方法的参数上,局部变量上。

二.Java提供的三种基本注解:

1.@SuppressWarnings : 压制警告(Retetion值为source

2.@Deprecated:提示该成员变量已经过时了,不再推荐使用。(Retetion值为Runtime

3.@Override表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。(Retetion值为source)

三.注解的应用

注解相当于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,得先准备好这个注解类。就像你要调用某个类,得先开发好这个类。

元注解:在注解上再加注解

一个注解有它的生命周期(Retetion)和存放位置(Target)

@Retention元注解的三种取值:

RetetionPolicy.source,RetetionPolicy.Class,RetetionPolicy.runtime分别对应:java源文件,Class文件,内存中的字节码

@Target表示该注解可以放在上面位置:

取值范围:

ANNOTATION_TYPE注解类型

CONSTRUCTOR构造方法

FIELD字段

LOCAL_VARIABLE局部变量

METHOD方法

PACKAGE

PARAMETER方法参数

TYPE类、接口(包括注释类型)或枚举声明

四.注解的属性

一.什么是注解的属性:

1.一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,否则,就不是。如果还想区分出事传智播客哪个班的学生,这时候可以为胸牌在增加一个属性来进行区分。加了属性的标记效果为:@MyAnnotation(color=”red”)

2.定义基本类型的属性和应用属性。

在注解类中增加String color();

@MyAnnotation(color=”red”)

3.用反射方式获得注解对应的实力对象后,再通过该对象调用属性对应的方法4

4.为属性指定缺省值:

String color() default “yellow”

Value属性:

String Value default “zxx”

如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你只有一个value属性),那么可以省略value=部分。例如:@MyAnnotation(“hm”);

示例代码:

package javaenhance;

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

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface ItcastAnnotation {
	String color() default  "red";

	String value();
	

}

package javaenhance;

@ItcastAnnotation(color="YELLOW",value="wxk")
public class AnnotationTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
           if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class))
           {
        	   ItcastAnnotation annotation= AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
        	   System.out.println(annotation.color());
        	   System.out.println(annotation.value());
           }
	}

}

第二节 泛型

一.概述:

1.泛型是JDK1.5出现的新特性,泛型的出现主要是解决安全问题,它是一种安全机制。

最典型的应为为:再没有泛型的时候集合存储对象时,什么对象都可以往里面存,而取得时候需要强制类型转换。一转换出错,程序就挂了。有了泛型后只要在集合后加<>尖括号内加上限制的类型就能解决上述问题。

2.泛型是提供给javac编译器使用的,可以限定集合中的输入类型

让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时

会除掉“类型“信息,使程序运行效率不受影响,对于参数化的泛型类型,

getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息

只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用

反射得到集合,再调用其add方法即可

二.了解泛型

1.ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语。

(1)整个称为ArrayList<E>泛型类型.

(2)ArrayList<E>中的E称为类型变量或类型参数。

(3)整个ArrayList<Integer>称为参数化的类型

(4)ArrayList<Integer>中德Integer称为类型参数的实例或实际类型参数

(5)ArrayList<Integer>中德<>念typeof

(6)ArrayList称为原始类型

2.参数化类型与原始类型的兼容性:

  (1)参数化类型可以引用一个原始类型的对象,编译报告警告,例如,

Collection<String> c = new Vector();

  (2)原始类型可以引用一个参数化类型的对象,编译报告警告,例如。

Collection c = new Vector<String>();

3.参数化类型不考虑类型参数的继承关系:

  (1) Vector<String> v = new Vector<Object>(); //报错

  (2) Vector<Object> v = new Vector<String>; //也//报错

4.在创建数组实例时,数组的元素不能使用参数化的类型,例如,

  Vector<Integer> vectorList[] = new Vector<Integer>[10] //错误

 

第三节 泛型的通配符扩展应用

1.当传入的类型不确定时,可以使用通配符?

总结:使用?通配符可以引用其他各种类型化的类型,?通配符定义的便利主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。

2.泛型中的?通配符的扩展

 (1)限定通配符的上边界:

  Vector<? Extends Number> x = new Vector<Integer>()  //这是正确的

  Vector<? Extends Number> x = new Vector<String>() //这是错误的

  (2)限定通配符的下边届:

  Vector<? Super Integer> x = new Vector<Number>()   正确

  Vector<? Extends Integer> x = new Vector<Byte>()   错误

提示:

限定通配符总是包括自己。

总结:通配符方案要比泛型方法更有效,当一个类型变量用来表达两个参数之间或者参数和返回值之间的关系时,即同一个类型变量在方法签名的两处被使用,或者类型变量在方法体代码中也被使用而不是仅在签名的时候使用,才需要使用泛型方法。

第四节 自定义泛型方法及其应用

1.放置位置:

  用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和方法的返回类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。

注意:只有引用类型才能作为泛型方法的实际参数

2.除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符。例如,Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,如<V extends Serializable &cloneable> void method();

3.普通方法,构造方法和静态方法都可以使用泛型。编译器也不允许创建类型变量的数组。

4.也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch字句中。

5.在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分,例如:

 Public static <K,V> V getValue(K key){return map.get(key);}

6.泛型方法的练习:

 (1)编写一个泛型方法,自动将Object类型的对象转换成其他类型。

 (2)定义一个方法,可以将任意类型的数组中德所有元素填充为相应类型的某个对象。

 (3)采用自定义泛型方法的方式打印出任意参数化类型的集合中德所有内容

 (4)定义一个方法,把任意参数类型的集合中德数据安全的复制到相应类型的数组中。

 (5)定义一个方法,把任意参数类型的一个数组中德数据安全地复制到相应类型的另一个数组中。

第五节 类型参数的类型推断

1.编译器判断泛型方法的实际类型参数的过程称为类型判断,类型判断是相当于知觉推断的,其实现方法是一种非常复杂的过程。

2.根据调用泛型方法时时间传递的参数类型或返回值的类型来推断,具体规则如下:

  (1)当某个类型变量只在整个参数列表中德所有参数和返回值中德一处被应用了,呢么根据调用方法时该处来决定泛型参数来确定,这很容器凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:

  Swap(new String[3],3,4) ---->static <E>void swap(E[]a ,int i ,int j)

  (2)当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方啊时这多出的实际应用类型都对应同一种类型来确定,这很容易凭着感觉推断出来,例如:

Add(3,5)---->static <T> add(T a , T b)

   (3)当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方啊时这多出的实际应用类型都对应不同的类型,且没有使用返回值,这时候取多个参数的最大交集类型,例如,下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题: fill(new Integer[3],3,5f) ---->static <T> void fill(T[] a,T v)

  (4)当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方啊时这多出的实际应用类型都对应不同的类型,并且使用了返回值,这时候有限考虑返回值类型,例如,下面语句时间对应的类型就是Integer了,编译将报告错误,将变量X的类型改为float,对比eclipse报告的错误提示,int x =(3,3.5f)---->static <T> T add(T a ,T b)

   (5)参数类型的类型推断具有传递性,下面第一种情况推荐实际参数类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题:copy(new Integer[5], new String[5])---->static <T> void copy(T[] a ,T[] b)

 

第五节 自定义泛型类的应用

1.如果类的实例对象中多出都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,就是类级别的泛型,语法格式如下:

 Public class GenericDao<E>{

Private E field1;

Public void save(E obj){}

Public T getById(int id){}

}

2.类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以:

 GenericDao<String> dao = null;

 New GenericDao<String>();

注意:在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。

当一个被变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类共享的,所以静态成员不应该有类级别的类型参数。

3.通过反射获得泛型的实际类型参数:

返回集合,有一个方法返回一个集合,要是我们不知道集合的具体的类型,那我就不知道要把集合转换成什么对象。要是指定了就能转换成相应的类型。

思路:

(1).先定义一个applyVector方法,上面指定集合的类型参数。

(2).通过反射获得类上的这个方法

(3).再通过Method上的getGenericParameterTypes()方法获得此Method对象所表示的方法的形参类型。

(4)最后根据ParameterizedType上的两个方法getRawType()获得原始类型和getActualTypeArguments()方法获得此类型实际类型参数的Type对象的数组。


示例代码:

package javaenhance;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.Vector;

public class GenericTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		 ArrayList list = new ArrayList();
		 list.add(1);
		 list.add(1L);
		 list.add("abc");
		 
		 ArrayList<Integer> list2 = new ArrayList<Integer>();
		 ArrayList<String> list3 = new ArrayList<String>();
		 System.out.println(list2.getClass()==list3.getClass());
		 
		 list2.getClass().getMethod("add", Object.class).invoke(list2, "abc");
		 System.out.println(list2.get(0));
		 Method method =GenericTest.class.getMethod("applyVector", Vector.class);
		 Type[] types = method.getGenericParameterTypes();
		 ParameterizedType type=(ParameterizedType)types[0];
		 System.out.println(type.getRawType());
		 System.out.println(type.getActualTypeArguments()[0]);
	}
	
	public static void applyVector(Vector<Date> vector){
		
	}

}