黑马程序员----java高新技术--内省,注解

时间:2023-02-18 13:55:33

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




java内省机制:
     内省(Introspector)是Java 语言对Bean类属性、事件的一种缺省处理方法。JavaBean是一种特殊的Java类,

主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

      如果一个Java类中的一些方法符合某种命名规则,则可以把它当作JavaBean来使用。例如类 A 中有属性 name, 

那我们可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。


如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,
这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,
如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。
如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?不用
如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?不用
去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
ef:
setId()的属性名
       id
isLast()的属性名
     last
setCPU的属性名
    CPU
getUPS的属性名
    UPS
总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

<span style="font-size:14px;">package com.Super;

public class javaBeanDemo {
private int x;
private int y;

public javaBeanDemo(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public static void main(String[] args) {
javaBeanDemo demo =new javaBeanDemo(3, 10);
System.out.println(demo.getX());
demo.setX(10);
System.out.println(demo.getX());
}

}
</span>

直接通过属性的描述器java.beans.PropertyDescriptor类,来访问属性的getter/setter 方法;
package com.Super;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

public class javaBeanDemo {
private int x;
private int y;

public javaBeanDemo(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public static void main(String[] args) throws Exception{
javaBeanDemo demo =new javaBeanDemo(5, 10);
String xName="x"; //变量x
//创建PropertyDescriptor对象,获取属性对象
PropertyDescriptor pd =new PropertyDescriptor(xName, javaBeanDemo.class);
//获取x的读取方法
Method methodGetX = pd.getReadMethod();
//执行方法返回x的值
Object retVal = methodGetX.invoke(demo);
System.out.println(retVal);

String yName="y";
PropertyDescriptor pd1 =new PropertyDescriptor(yName, javaBeanDemo.class);
//获取y的设置方法
Method methodSetY =pd1.getWriteMethod();
methodSetY.invoke(demo, 1);
System.out.println(demo.getY());
}

}
2  通过类 Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 
   来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的     getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。这是把一个类当成javaBean来看。
public static void main(String[] args) throws Exception{
javaBeanDemo demo =new javaBeanDemo(5, 10);
String xName="x"; //变量x
getx(demo,xName);
}

public static void getx(javaBeanDemo demo, String strName) throws Exception{
//通过Introspector获取BeanInfo对象
BeanInfo beanInfo = Introspector.getBeanInfo(demo.getClass());
//获取方法的数组
PropertyDescriptor [] proDescriptors = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor pd:proDescriptors){
//便利数组找到对应的方法
if(pd.getName().equals(strName)){
Method methodGetx=pd.getReadMethod();
System.out.println(methodGetx.invoke(demo)); //执行get方法获取x的值为5
}
}
}



注解:
自定义注解及其应用:
1.注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则没有某种标记。

2.java编译器、开发工具和其他应用程序就可以用反射来了解自己的类及各种元素上有无何种标记,

有什么标记,就会做出相应的处理。

3.标记可以加在包、类、字段、方法、方法参数,以及局部变量上等等。
4.在java.lang包中提供了最基本的annotation,即注解。
5.格式:@注解类名()。如果有属性,则在括号中加上属性名(可省略)和属性值。public @interface MyAnnotation {}  

常见的注解: 1.@SuppressWarning(”deprecation”)-已过期警告
SupressWarning是告知编译器或开发工具等提示指定的编译器警告;
”deprecation”是告知具体的信息即方法已过时。
2.@Deprecated-提示成员等已经过时,不再推荐使用。
例如:假定之前的某个类升级了,其中的某个方法已经过时了,不能够将过时的方法删除,  因为可能会影响到调用此类的这个方法的某些程序,这是就可以通过在方法上加这个注解。
3.@Override-提示覆盖(父类方法)
加上此注解,,可对自己类中的方法判断是否是要覆盖的父类的方法,
才能被覆盖,若不是,加上此注解就会提示警告。

元注解:(注解的注解) 一个注解有其生命周期(Retetion)和存放的位置(Taget),这就可以通过元注解说明。
(1)Retetion:用于说明注解保留在哪个时期,加载定义的注解之上。
一个注解的声明周期包含:
java源程序--(javac)-->class文件--(类加载器)-->内存中的字节码
第一、当再源程序上加了注解,javac将java源程序编译为class文件,可能会把源程序中的一些注解去掉,
 进行相应的处理操作,当我们拿到源程序的时候,就看不到这些注解了。
第二、假设javac把这些注解留在了源程序中(或者说留在了class文件中),当运行此class文件的时候,
用类加载器将class文件调入内存中,此时有转换的过程,即把class文件中的注解是否保留下来也不一定。
注意:class文件中不是字节码,只有把class文件中的内部加载进内存,
用类加载器加载处理后(进行完整的检查等处理),最终得到的二进制内容才是字节码。
Reteton(枚举类)取值:
Retetion.Policy.SOURSE:java源文件时期,如@Overried和@SuppressWarning
Retetion.Policy.CLASS: class文件时期(默认阶段)
Retetion.Policy.RUNTIME:运行时期,如@Deprecated

(2)Taget:用于说明注解存放在哪些成分上,默认值是任何元素 其值可设置为枚举类ElementType类中的任何一个,包括:包、字段、方法、方法参数、构造器、类等值。取值为:
PACKAGE(包声明)
FIELD(字段声明)
ANNOTATION_TYPE(注释类型声明)
CONSIRUCTOR(构造器声明)
METHOD(方法声明)
PARAMETER(参数声明)
TYPE(类、接口(包含注释类型)或枚举声明)
LOCAL_VARIABLE(局部变量声明)
注意:其中代表类的值是TYPE。因为class、enum、interface和@
interface等都是属于Type的。不可用CLASS表示.

3.通过反射查看其它类中的注释
过程:
第一、创建注解类:@interfaceA{}
第二、为类添加注解:@Aclass B{}
第三、对“应用注释类的类”进行反射操作的类:class{...},操作如下:
B.class.isAnnotionPresent(A.class);//判断是否存在此注解类
A a = B.class.getAnnotation(a.class);//存在的话则得到这个注释类的对象
@Retention(RetentionPolicy.RUNTIME)   //运行时期
@Target({ElementType.TYPE,ElementType.METHOD}) //在方法上申明
public @interface AnnotionDemo {}


@AnnotionDemo()
public class AnnotionTest {
@AnnotionDemo()
public static void main(String[] args) {
//反射方式查看注解
//检查类上是否有注解
if(AnnotionTest.class.isAnnotationPresent(AnnotionDemo.class)){
//通过反射获取到注解
AnnotionDemo annotation = AnnotionTest.class.getAnnotation(AnnotionDemo.class);
System.out.println(annotation);
}
}
}

为注解增加基本属性:
1.属性:一个注解相当于一个标签,但仅通过标签还不足以区别带标签的两个人,这时就需要给标签增加一个属性来区分,如颜色等。
2.定义格式:同接口中的方法一样:String color();定义缺省格式:Stringvalue() default ”ignal”;
3.应用:直接在注解的括号中添加自身的属性,如:
@ItcastAnnotation(color=”red”)
这个和上面的@SuppressWarnings("deprecation")是一样的,其中的"deprecation"就是属性值
1)当只有一个属性时,可直接传入属性值。如”red”
2)当含有其他属性值的时候,如果那个属性值是缺省的(default),也可以直接传入这个属性值。
高级属性: 1.可以为注解增加的高级属性的返回值类型有:
1)八种基本数据类型   2)String类型  3)Class类型
4)枚举类型   5)注解类型   6)前五种类型的数组
2.数组类型的属性:
定义:int[]arrayArr() default {1,2,3};     -->可不定义默认值
应用:@MyAnnotation(arrayArr={2,3,4})  --> 可重新赋值
注:若数组属性中只有一个元素(或重新赋值为一个元素),这时属性值部分可省略大括号。
3.枚举类型的属性:
  假设定义了一个枚举类TraffLamp,它是EnumTest的内部类,其值是交通灯的三色。
定义:EnumTest.TrafficLamplamp();
应用:@MyAnnotation(lamp=EnumTestTrafficLamp.GREEN)
4.Class类型的属性:
定义:Class cls();
应用:@MyAnnotation(cls=ItcastAnnotion.class)
注:这里的.class必须是已定义的类,或是已有的字节码对象
5.基本数据类型的属性(以int为例):
定义:int val()default 3;     -->可不定义默认值
应用:@MyAnnotation(val=7)  --> 可重新赋值

<span style="font-size:14px;">package com.zhy; 

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

//运行期间
@Retention(RetentionPolicy.RUNTIME)
//方法中
@Target({ElementType.TYPE,ElementType.METHOD})
@interface ItcastAnnotation1 {
//定义属性
String str();
int val() default 1;
int[] arr() default {2,3,4};
Class cls() default a1.class;
}



@ItcastAnnotation1( arr=7,val=5,str="hello", cls=ItcastAnnotation1.class)
public class a1 {
@ItcastAnnotation1(str = "java ") //有缺省值可不用写缺省部分
public static void main(String[] args) {
//反射方式查看注解
//检查类上是否有注解
if(a1.class.isAnnotationPresent(ItcastAnnotation1.class)){
//通过反射获取到注解
ItcastAnnotation1 annotation = a1.class.getAnnotation(ItcastAnnotation1.class);
//打印查看属性值
System.out.println(annotation);
System.out.println(annotation.str());
System.out.println(annotation.val());
System.out.println(annotation.arr().length);
System.out.println(annotation.cls().getName());
System.out.println(annotation.lamp().nextLamp());
}
}
}
</span>