黑马程序员----java基础加强 注解与泛型

                                   ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


================第6单元:java5的注解===================
33.了解和入门注解的应用
常用的注解方式:
1.@SuppressWarnings("deprectaion");//使用已经过时的方法,并且去除javac的编译警告
2.@Deprecated
在方法的开始位置添加,表示该方法已经过时,这对于程序的升级很有帮助
3.@Override
当要覆盖接口中的方法或者是父类的方法时,会在方法的开始位置加上该注释,
表示的覆盖,如果不是覆盖,该方法就是报错.


总结:
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,
则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来
了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。
标记可以加在包,类,字段,方法,方法的参数以及局部变量上。



34.注解的定义与反射调用
什么是注解类:
注解就相当于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,
得先准备好了这个注解类。就像你要调用某个类,得先有开发好这个类

定义一个注解类:
public @interface MyAnnotation {

}
//使用该注解到某个类上
@MyAnnotation
public class AnnotationTest()
{
//...可以通过反射的方式得到MyAnnotation的Class,
}


35.为注解增加各种属性

定义基本类型的属性和应用属性:
在注解类中增加String color();
@MyAnnotation(color="red")

用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(a.color());

可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象
为属性指定缺省值:
String color() default "yellow";
value属性:
String value() default "zxx"; 

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




================第7单元:java5的泛型===================
36.入门泛型的基本应用
泛型是为了解决安全问题的一种机制,通过使用泛型,可是时程序从运行时的问题转移到编译时期,
这样可以增强程序的安全性.

未使用泛型时
//添加时都是成功的
ArrayList collection = new ArrayList();
collection.add(1);
collection.add(1L);
collection.add("abc");


int i = (Integer) collection.get(1);//编译要强制类型转换且运行时出错!


//编译的时候程序没有问题,但运行的时候可能就会出现问题,当使用泛型的时候,就可以把运行
//时的问题提前到编译时期.


37.泛型的内部原理及更深应用
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非
法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,
对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字
节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的
数据,例如,用反射得到集合,再调用其add方法即可


38.泛型的通配符扩展应用
错误方式:
public static void printCollection(Collection<Object> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
/* cols.add("string");//没错
cols = new HashSet<Date>();//会报告错误!*/
}
正确方式:
public static void printCollection(Collection<?> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
//cols.add("string");//错误,因为它不知自己未来匹配就一定是String
cols.size();//没错,此方法与类型参数没有关系
cols = new HashSet<Date>();
}
总结:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,
可以调用与参数化无关的方法,不能调用与参数化有关的方法。


39.泛型集合的综合应用案例


public static void main(String[] args) {
HashMap<String,Integer> hm = new HashMap<String,Integer>();
hm.put("zxx",19);
hm.put("lis",18);
 
Set<Map.Entry<String,Integer>> mes= hm.entrySet();
for(Map.Entry<String,Integer> me : mes) {
   System.out.println(me.getKey() + ":" + me.getValue());
}
40.自定义泛型方法及其应用
//对引用数据类型交换
public static <E> void swap(E[] a, int i, int j) {
E t = a[i];
a[i] = a[j];
a[j] = t;
}
41.自定义泛型方法的练习与类型推断总结
1.定义一个方法,把任意参数类型的集合中的数据安全地复制到相应类型的数组中。
public static <T> T[] fill(T[] a, T v) {
for (int i=0; i<a.length; i++)
{
a[i] = v;
}
return a;
}


根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:
当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,
那么根据调用方法时该处的实际应用类型来确定,这很容易凭着感觉推断出来,
即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:
swap(new String[3],3,4)       static <E> void swap(E[] a, int i, int j)

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

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

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

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

42.自定义泛型类的应用
如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持
同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,
语法格式如下:
//简单可以说是对一类函数的简化,也类似于模版
public class GenericDao<T> {
private T field1;
public void save(T obj){}
public T getById(int id){}
}


类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种
方式都可以:
GenericDao<String> dao = null;//当使用类泛型时,传入的类确定后,方法上的类型也就确定了
new genericDao<String>();


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

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


43.通过反射获得泛型的实际类型参数
1.泛型是编译时期存在的,编译后,编译器就会将类型去掉,所有直接想通过反射的
方式得到类型是不可能的,但是可以通过函数转化为类型参数传入,这个才靠谱

class GenericTest
{
	private static void applyGeneric(Vector<String> v){

	}
	public static void main(String[] args) {
		Method methodApply = GenericTest.class.getDeclaredMethod("applyGeneric", Vector.class);
		Type[] paramTypes = methodApply.getGenericParameterTypes();

		ParameterizedType param = (ParameterizedType)(paramTypes[0]);
		System.out.println(param.getRawType());
		System.out.println(param.getActualTypeArguments()[0]);
		System.out.println(((Class)param.getRawType()).getName() + "<" 
		+ ((Class)param.getActualTypeArguments()[0]).getName()
		+ ">");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值