内省:
在学习内省之前我们先来看javabean的概念:
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法
主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间
传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例
对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段
来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。
如果方法名为setId,中文意思即为设置id,如果方法名为getId,中文意思即为获取id,
去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,
则把剩余部分的首字母改成小的。
setId()的属性名 id
setCPU的属性名是CPU
总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,
它根本看不到java类内部的成员变量。
一个符合JavaBean特点的类可以当作普通类
一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去了
解和应用JavaBean
javabean有什么具体的好处呢:
1、在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进
行操作。
2、JDK中提供了对
JavaBean进行操作的一些API,这套API就称为内省。如果要你自
己去通过getX方法来
访问私有的x,有一定难度,用内省这套api操作JavaBean比用
普通类的方
式更方便。
在具体的开发中常用
Beanutils工具包,他提供了比java中的内省更方便而且强大的功能
现在我们通过一个例子来感受内省:
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.beanutils.BeanUtils;
public class BeansTest {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Person p = new Person();
p.setName("zhangsan");
String propertiesName = "name";
String name = extracted(p, propertiesName);
System.out.println(name);
String propertiesAge = "age";
int age = 23;
SetAge(p, propertiesAge, age);
. String name1 = BeanUtils.getProperty(p, "name");
System.out.println(BeanUtils.getProperty(p, "name").getClass().getName());
System.out.println(name1);
BeanUtils.setProperty(p, "age", 19);
System.out.println(p.getAge());
}
private static void SetAge(Person p, String propertiesAge, int age)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor bp1 = new PropertyDescriptor(propertiesAge, p.getClass());
Method methodSetAge = bp1.getWriteMethod();
methodSetAge.invoke(p,age);
System.out.println(p.getAge());
}
private static String extracted(Object p, String propertiesName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
/*PropertyDescriptor bp = new PropertyDescriptor(propertiesName, p.getClass());
Method methodGetName = bp.getReadMethod();
Object readVal = methodGetName.invoke(p);
System.out.println(readVal);*/
BeanInfo beanInfo = Introspector.getBeanInfo(p.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd : pds){
if(pd.getName().equals(propertiesName))
{
Method methodGetX = pd.getReadMethod();
retVal = (String)methodGetX.invoke(p);
break;
}
}
return (String) retVal;
}
}
注解:
1、注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,
没加,则等于没有某种标记。
以后,javac编译器,开发工具和其他程
序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,
就去干相应的事。
2、标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
3、一个注解相当于一个类。
JDK中提供的最基本的annotation。
1)、@SuppressWarning(”deprecation”)--->压制警告
SupressWarning是告知编译器或开发工具等提示指定的编译器警告;
”deprecation”是告知具体的信息即方法已过时。
2)、@Deprecated(过时的方法,对于不再使用的方法,可能别人或别的
地方有调用这个方法,不能删除完事)
直接在刚才的类中增加一个方法,并加上@Deprecated标注,在另外
一个类中调用这个方法。测试一下。
@SuppressWarnings("deprecation") (用这个可以告诉 程序说,
我知道调用的方法过时了)
3)、@Override--->提示覆盖(父类方法)
public boolean equals(Reflect other)方法与HashSet结合讲解
像person类,覆盖父类的equals 和hashCode方法,人家接收的参数
是Object,人们习惯总是传入自己的对象,造成覆盖失败,变成重载!
现在我么看自定义注解:
@Retention(RetentionPolicy.RUNTIME)//告诉jvm这个注解要保存到运行时期
@Target({ElementType.METHOD,ElementType.TYPE})//告诉编译器,这个注解可以用在方法上,也可以用在类上
public @interface MyAnnotation {
String color() default "yellow";//默认缺省值为yellow
String value() ;//不指定
int [] arrayAttr() default {1,2};//默认为{1,2}
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;//枚举类
为注解增加基本属性
(可以是八种基本数据类型,String ,数组,枚举,注解,Class)
一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,否则,就不是。
如果还想区分出是传智播客哪个班的学生,这时候可以为胸牌在增加一个属性来进行区分。
加了属性的标记效果为:
@MyAnnotation(color="red")
定义基本类型的属性和应用属性:
在注解类中增加String color();
@MyAnnotation(color="red")
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(a.color());
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象
如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默
认值或者你只有一个value属性),那么可以省略value=部分,例如:@MyAnnotation("lhm")。
枚举和注解都是特殊的类,不能用new 创建它们的实例对象,创建枚举的实例对象就是在其中增加元素。
在程序中如何创建出一个注解的实例对象啊?直接用@放上一个标记即可.
import java.lang.reflect.Method;
import javax.jws.soap.InitParam;
@ItcastAnnotation(annotationAttr=@MetaAnnotation("flx"),color="red",value="abc",arrayAttr=1)
public class AnnotationTest {
@SuppressWarnings("deprecation")
@ItcastAnnotation("xyz")
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation = (ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color());
System.out.println(annotation.value());
System.out.println(annotation.arrayAttr().length);
System.out.println(annotation.lamp().nextLamp().name());
System.out.println(annotation.annotationAttr().value());
}
Method mainMethod = AnnotationTest.class.getMethod("main", String[].class); ItcastAnnotation annotation2 =
(ItcastAnnotation)mainMethod.getAnnotation(ItcastAnnotation.class);
//获取String类上main函数上的注解
System.out.println(annotation2.value());
}
@Deprecated//告诉调用者,这个方法过期了。
public static void sayHello()
{
System.out.println("hello,传智播客");
}
}
MetaAnnotation注解的定义:
public @interface MetaAnnotation {