黑马程序员________Java高新技术之反射机制及枚举注释

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


        枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。首先在枚举内私有他的构造方法,每个元素分别用一个公有的静态成员变量表示变量表示。然后定义若干公有方法或者抽象方法。总体来说,枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象。

         以下是模拟一个红绿灯的情况,红灯四秒,绿灯三秒,黄灯一秒。

public

class Enumer {

    public static void main(String[] args) throws Exception

    {

      

       Lamp lap=Lamp.RED;

       while(true){

           System.out.println(lap);

           Thread.sleep((lap.num)*1000);//停多少秒 继续获得下一个灯

           lap=lap.nextLamp();

       }

    }

}

enum

Lamp

{

    RED(4){//用构造函数传入具体要停几秒

       public  Lamp nextLamp(){//覆写方法来具体定义每一个灯后是什么灯

           return GREEN;

       }

    },

    GREEN(3){

       public  Lamp nextLamp(){

           return YELLOW;

       }

    },

    YELLOW(1){

       public  Lamp nextLamp(){

           return RED;

       }

    };

    private Lamp(int num){this.num=num;}

    public int num;

    public abstract Lamp nextLamp();

}

 

 

 

        Java中的反射,程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。在程序中得到类的字节码有三种方式。1,类名.class(如Person.class)。2,对象.getClass()(如new Person().getClass())。3,Class.forName(类名)(如Class.forName(“java.util.Date”))。Java中有九个预定义的Class实例对象(byte,shot,int,long,float,double,char,Boolean,void)。总之,只要在源程序中出现的类型,都有各自的Class实例对象。而反射就是把Java类中的各种成分映射成相应的Java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息业用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示Java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,他们是Field、Method、Contructor、Package等等。

   

Constructor类是用来获取字节码中的构造函数。

Constructor con=String.class.getConstructor(“StringBuffer.class”);

//这样就获取的String 类中参数为StringBuffer的构造函数

String str=con.newInstance(new StringBuffer(“abc”));

//用得到的构造方法来创建一个String对象其效果就等于String str=new String(new StirngBuffer(“abc”));

 

    Filed类是用来获取字节码中的成员变量。假设我们有一个类A,其中有变量x和y。那么我们获取这个类中的成员变量对象就可以用Field field=A.class.getField(“x”);接着我们用A创建一个对象a,那么我们就可以用刚才获取的成员变量对象field来获取对象a中x的值,即field.get(a)。如果x变量为私有,我们则需要将以上的步骤改为:Field  fidld=A.class.getDeclaredField();field.setAccessble(true);来暴力反射就可以获取到x在a中的值。下面我们看一个例子,一个Person类中有名字,外号和年龄三个属性,要把传入的一个人中所有带三的字符串改为四。

import java.lang.reflect.Field;

 

public class Reflect {

    public static void main(String[] args) throws Exception {

       Person p=new Person("张三","小三",13);

       Field[] fields=p.getClass().getFields();//获取该类字节码中所有成员变量对象并封装成一个数组

       for (Field f:fields)

       {

           if(f.getType()n==String.class)//因为是字节码比较,所以用==

              f.set(p,((f.get(p)).toString().replace("","")));

       }

    }

}

 

class Person{

    public String name;

    public String nickname;

    private int age;

   

    public Person(String name, String nickname, int age) {

       super();

       this.name = name;

       this.nickname = nickname;

       this.age = age;

    }

 

    @Override

    public String toString() {

       return "Person[name=" + name + ",nickname=" + nickname + ",age="

              + age + "]";

    }

}

 

    Method类是用来获取字节码中的方法对象。需要在getMethod的参数中传入要获取的方法的名字和该方法的参数字节码类型。如Methodm=String.class.getMethod(“charAt”,int.class);然后我们就可以调用这个方法对象的invoke方法,m.invoke(str,1);其效果就等于str.charAt(1);这里要注意的一点是如果该方法为静态方法的话,那么invoke方法中的第一个参数就应该为null。

    加入我们要调用一个类的main方法,则可以根据该类的名字获取到main方法,然后通过invoke方法来调用该方法。

String className=”需要调用主函数的类名”;

MethodmainMethod=Class.forName(className).getMethod(“main”,String[].class);

mainMethod.invoke(null,null);

 

    相同元素类型和维度的数组同属一个字节码。数组也是Object对象,那么我们在打印一个Object对象第时候就可以用到反射的技术来判断一下如果是数组就遍历数组打印,如果不是就直接打印。

printObj(Object obj)

{

    classclazz=obj.getClass();

    if(clazz.isArray())

{

    int len=Array.getLength(obj);

    for(int i=0;x<len;x++)

{

    System.out.println(Array.get(obj,i));

}

}

else

{

    System.out.println(obj);

}

}  

 

    我们对反射的一个最基本的应用就是将它应用在框架里,因为框架式在工具程序之前完成的,他不知道工具类的名字,就要用到反射。比如这里我们需要new一个集合,但是new一个什么样的集合我需要以后的程序告诉我。这个时候我去建一个config.properties配置文件,里面的设键className。

InputStream fis= new FileInputStream(“config.properties”);

Properties prop=new Properties();

prop.load(fis);//将流中信息装载进prop对象

String className=prop.getProperty(“className”);//获取键className的值

Collection collections=(Cllection)Class.forName(className).newInstance();//通过获得该类字节码来创建该类空参对象

这时我们把配置文件修改为properties=java.util.ArrayList就创建的是一个ArrayList对象

 

 

        内省IntroSpector是用来操作JavaBean的。JavaBean是一种特殊的Java类。主要用于传递数据信息,这种java类中的方法主要用于反射私有的字段,而且方法名都符合某种命名规则。

       一个符合JavaBean特点的类可以当做普通类一样进行使用,但是把他当做JavaBean用是因为在JavaEE中经常会用到;另外一个就是JDK提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的X,会有一定难度,但是用内省的这套API操作JavaBean比用普通类的方式更方便。

        只需要传入Sting properName要得到的属性名,和 className类名,就可以获得他的get到对应属性名的get方法,就可以通过invoke方法来调用这个方法。

PropertyDescriptor dp=newPropertyDescriptor(propertyName,Class.forName(className));

Method methodGet=pd.getReadMethod();

methodGet.invoke();

可以将以上代码抽取称为一个函数接受一个对象和他要获取的字段,就可返回相应字段。

另外还有一个方法就是通过BeanInfo来获取这个属性的数组,然后通过遍历找到他

public Object getPropertyValue(StringpropertyName,Object p)

{

BeanInfobi=Introspctor.getBeanInfo(p.getClass());//获取BeanInfo对象

PropertyDescriptor[]pds=bi.getPropertyDescriptors();//获取属性的数组

String retVal=null;

for(PropertyDescriptor pd:pds)

{

    if(pd.getName().equals(PropertyName))

{

    retVal=pd.getReadMethod().invoke(p);

    break;

}

return retVal;

}

}

        在实际开发中我们可以用一个工具类BeanUtils来对JavaBean进行操作就显得简单多了。这个工具包是Apache提供的,所以我们需要先下载到BeanUtils资源jar包另和logging包一起导入进Java工程就可以使用了

        取出该对象p1中的x值,就通过一句BeanUtils.getProperty(p1,”x”);就可以实现。BeanUtils.setProperty(p1,”x”,”19”);注意不管get还是set操作的都是字符串,即使x的属性是int,他会自动转换,返回的也是String类型,PropertyUtils工具包则不会发生自动转换,如PropertyUtils.setProperty(p1,”x”,19);注意这里的19是int而不是String了。

 

 

    Java的注解(Annotation)相当于一个标记,加了注解之后,javac编译器开发工具盒其他程序可以用反射来了解你的类及各种元素上有无何种标记,看有什么标记,去看相应的事。标记可以加在包,类,字段,方法和参数以及局部变量上。

    java.lang包中的提供的注解类

@SuppressWarnings(“deprecation”)告诉编译器用到过时方法

@Deprecated告诉编译器此方法已经过时

@override告诉编译器此方法为覆盖方法

 

    元注解是来注解注解类的注解

@Retention生命周期

    注解的生命周期有三种,在源文件阶段,在编译阶段,在字节码阶段,分别对应的是.SOURCE /.CLASS/.RUNTIME三个被final修饰的常量。

@Retention(RetentionPolicy.RUNTIME)此注解即表示该注解生命周期为字节码阶段

 

@Target注解类型可以指定该注解允许注解的类型范围,包、类、方法、构造方法、参数等分别对应PACKAGE\TYPE\METHOD\CONSTUCTOR\PARAMETER等,具体可以查API文档。

@Target(ElementType.METHOD,ElementType.TYPE)此注解可以注解的类型为方法和类

 

 

    注解的属性String str()default “abc”;其中一个属性为str,默认值为abc。使用该注解的时候@Annotation(str=”efg”).如果只有一个value在使用注解的时候,可以直接在括号内输入。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值