一、内省:
IntroSpector-->JavaBean-->特殊的类
比如
int getAge() //get方法的返回值是属性的类型,且没有参数
void setAge(int age) //set方法的返回值是void,且要有参数
JavaBean根据set和get方法名,得到相应的属性名规则:
如果第二个字母是小写,则把第一个字母变成小写,即Age-->age
gettime()-->time
setTime()-->time
getCPU()-->CPU
二、注解
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器、开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包、类、字段、方法、方法的参数以及局部变量上。
1、
1)@SuppressWarnings
比如,调用System.runFinalizersOnExit(true)方法,会提示该方法已过时,这时,在方法前面加上@SuppressWarnings
("deprecation")即可告诉编译器
2)@Deprecated
在方法前加上这个,来说明该方法已过时,不建议使用
3)@Override
覆盖
2、
注解就相当于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,得先准备好这个注解类。就像你要调用某个类,得先要
开发好这个类。
1)注解类:
@interface A
{
}
2)应用了“注解类”的类
@A
Class B
{
}
3)对“应用了注解类的类”进行反射操作的类
Class C {
B.class.isAnnotationPresent(A.class);
A a = B.class.getAnnotation(A.class);
}
@Retention元注解,三种取值:
(RetetionPolicy是个枚举类,有三种取值)
RetetionPolicy.SOURCE
RetetionPolicy.CLASS
RetetionPolicy.RUNTIME
分别对应:java源文件-->class文件(默认阶段)-->内存中的字节码。
@Override:保留在SOURCE阶段
@SuppressWarning:保留在SOURCE阶段
@Deprecated:保留在RUNTIME阶段
@Target元注解
Target的默认值为任何元素,设置Target等于ElementType.METHOD,原来加在类上的注解就报错了,改为用数组方式设
{ElementType.METHOD,ElementType.TYPE}就可以了。
注解类的方法可以像属性一样赋值,调用的时候是正常调用。
3、为注解增加基本属性(8个基本属性均可)
1)什么是注解的属性
一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是xx学校的学生,否则就不是。如果再想区分出是xx学校哪个班的学生,这时候可以为胸牌再增加一个属性来进行区分。加了属性的标记效果为:@MyAnnotation(color="red")
2)定义基本类型的属性和应用属性:
在注解类中增加String color();
赋值:@MyAnnotation(color="red")
3)用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(a.color());
可以认为上面这个@MyAnnotation是MyAnnotation类的一个实例对象。
4)为属性指定缺省值:
String color() default "yellow";
5)value属性:
String value() default "abc";
如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值),则可在定义时指定初始值。
4、为注解增加高级属性(String,Class,Enum类,或这些类型的数组)
1)数组类型的属性
int[] arrayAttr() default {1,2,3};
@MyAnnotation(arrayAttr={2,2,3});
如果数组属性中只有一个元素(一个值),这时属性值部分可以省略大括号
2)枚举类型的属性
EnumTest.TrafficLamp lamp();
@MyAnnotation(lamp=EnumTest.Traffic.GREEN);
3)注解类型的属性
MetaAnnotation annotationAttr() default @MetaAnnotation("xxx");
@MyAnnotation(annotationAttr=@MetaAnnotation("yyy"))
可以认为上面这个@MetaAnnotation是MyAnnotation类的一个实例对象,同样的道理,可以认为上面这个@MetaAnnotation("xxx")
是MetaAnnotation类的一个实例对象,调用代码如下:
MetaAnnotation ma = myAnnotation.annotationAttr();
System.out.println(ma.value());
注解的详细语法可以通过看java语言规范了解,即看java的language specification。
三、泛型
jdk1.5以前的集合类中如此定义:
ArrayList collection1 = new ArrayList();
collection1.add(1);
collection1.add(1L);
collection1.add("abc");
int i = (Integer)collection1.get(1); //编译要强制转换类型且运行时出错
jdk1.5的集合类希望在定义集合时,明确表示你要向集合中装哪种类型的数据,编译时不允许加入指定类型以外的数据
如:
ArrayList<String> collection2 = new ArrayList<String>();
collection2.add(1); //编译出错
collection2.add(1L); //编译出错
collection2.add("abc");
String ele = collection2.get(0);
System.out.println(ele);
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据,例如,用反射得到集合,再调用add方法即可。
比如:
ArrayList<Integer> collection3 = new ArrayList<Integer>();
collection3.add(1);
collection3.add(1);
//既然编译过后,泛型变量就会去类型化,那么,collection3用反射的方式,跳过编译,add一个String变量,是可行的。
collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
System.out.println(collection3);
1)ArrayList<E>类定义和ArrayList<Integer>类引用中设计如下术语:
整个成为ArrayList<E>泛型类型
ArrayList<E>中的E成为类型变量或类型参数
整个ArrayList<Integer>成为参数化的类型
ArrayList<Integer>中的Integer成为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念:typeof
ArrayList成为原始类型
2)参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译报告警告,例如:
Collection<String> c = new Vector();//也可以
原始类型可以引用一个参数化类型的对象,编译报告警告,例如:
Collection c = new Vector<String>();
3)参数化类型不考虑类型参数的继承关系:
Vector<String> v = new Vector<Object>();//错误
Vector<Object> v = new Vector<String>();//也错误
4)在创建数组实例时,数组的元素不能使用参数化的类型,例如,下面语句有错误:
Vector<Integer> v[] = new Vector<Integer>[10];
5)思考下面两句会不会报错:
Vector v1 = new Vector<String>();
Vector v = v1;
由于上面提到过,参数化类型和原始类型互相兼容,因此上面两句分开赋值,编译时是不会报错的。