20150804-反射及注解

一、反射

一)基本概念

1.使用的包:
java.lang.reflect
2. 定义:
3.Object类中定义了getClass方法,返回一个类型为Class的对象。例:
法1:Class clazz = Student.class;//将student类抽象出一个类对象
法2:Class clazz = 对象.getClass();

二)通过反射可以返回的主要信息:

  • getName() ;//获得该类的名称
  • getMethods();//以数组形式获得所有权限为public的方法
  • getMethod(String name,–);//获得权限为public的指定方法
  • getDeclaredMethods();//以数组形式获得所有方法,按声明顺序返回
  • getDeclaredMethod(String name);//获得指定方法

  • getFields();//以数组形式获得所有权限为public的成员变量

  • getField(String name,–);//获得指定成员变量
  • getDeclaredFields();//以数组形式获得所有成员变量,按声明顺序返回
  • getDeclaredField(String name);//获得指定成员变量
  • getClasses();//获得权限为public的内部类
  • getDeclaredClasses();//获得所有内部类

三)范例1:

/*要求:
1.利用反射获取一个类中的成员属性,并输出属性名称,以及类型。
2.实现一种情况的解决办法:
当类中的某一个封装好的属性,没有set方法,通过反射的方法,实现对此属性的赋值。
*/

/*Student 类,利用反射对其中的属性age赋值*/
public class Student {
    private int age;
    public String field1;
    public int field2;

    public int getage(){
         return age;
    }


}
import java.lang.reflect.Field;

public class TestFeild {
/*
 * Class是个抽象所有类的类
 * Feild有属性和名称。
 * */
    public static void main(String[] args) {
        Class<Student> clazz = Student.class; //此clazz是Class对象
        Field[] fields = clazz.getFields(); //以数组形式返回的是Student类中所有的公共属性
        Field[] fields2 = clazz.getDeclaredFields();//以数组形式返回所有属性
        for(Field field:fields2){
            System.out.println(field.getName());//属性名
            System.out.println(field.getType().getName());//属性类型的名称
            System.out.println(field.getModifiers());//返回属性修饰符额整数表示形式


        }

        Student zhangsan = new Student();
        //由于age没有set方法,这里通过下面方法来写入age值
        //先取消java访问修饰符检查,改好值后,在设回false
        try {
            Field age = clazz.getDeclaredField("age");//得到指定名称的属性age
            age.setAccessible(true);//取消java访问修饰符检查(这里取消private的访问)
            age.set(zhangsan, 19);  //设值,(IllegalArgumentException异常)
                  age.setAccessible(false);//取消原来的检查
            System.out.println(zhangsan.getage());
        } catch (NoSuchFieldException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

结果演示:
这里写图片描述

四)范例2:

/*
* 功能:利用反射来构造函数
* 步骤:创建一个工厂:
* 1.在里面放入一个造人方法。
* 2.建对象Properties对象
* 3.加载config文件
* 4.获得属性getProperty()方法
* 5.获得类的对象forName()
* 通过newInstance方法创建这个类的一个对象。
*
* */

//工厂类
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class Factory {
        public static Person creatPerson(){//创建一个造人的方法
        Person person = null;
        Properties p = new Properties(); //建对象Properties

        try {
            p.load(new FileInputStream("config.properties"));//
            String clazzName = p.getProperty("person");//获得person
            Class clazz = Class.forName(clazzName);
            person = (Person) clazz.newInstance(); //通过反射来构造函数
        } catch (ClassNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return person;

    }

}
//Person 类。
public class Person {
    public void run(){
        System.out.println("人在跑步!");
    }

}
//Student 类
public class Student extends Person{
    public void run(){
        System.out.println("学生在跑跑!");
    }

}
//Teacher 类
public class Teacher extends Person{
    public void run(){
        System.out.println("老师在跑步!");
    }

}
//所添加的普通文件
person = com.day0804_1.Student
//测试类
/*优点:通过使用Properties,建立config文件,将使用的类在此定义,方便以后的扩展,因为它不需要编译。*/
public class TestFactory {

    public static void main(String[] args) {
        // 反射,工厂设计模式
        Person person = Factory.creatPerson();
        person.run();


    }

}

演示:
这里写图片描述

二、注解 Annotation类(这里介绍自定义注解)

一)定义:

该功能建立在反射的基础上,
1.在定义Annotation类时,通过@Target来设置Annotation类型适用的程序元素类型,参数为枚举类型ElementType中的枚举常量:
这里介绍的是:ElementType.FIELD //表示成员变量和枚举常量,
其他常量通过API查找。
2.在定义Annotation类时,通过@Retention来设置Annotation类型的有效范围,参数类型为枚举类型RetentionPolicy中的枚举常量:
1)RetentionPolicy.SOURCE :表示不编译Annotation到类文件中,范围最小
2)RetentionPolicy.RUNTIME:表示编译到类文件,但运行时不加载到jvm中。
3)RetentionPolicy.RUNTIME:表示运行时将Annotation加载到jvm中,有效范围最大
3.int age() default 19;//设默认值
使用时用自定义注释名称(name=–)

二)范例1:

/*功能:1.自定义注释;2.利用注释注解某个类中的属性,并使此类初始化时就将注解传入的值传入该属性。
*/

import java.lang.annotation.ElementType;
/*
 * 功能:自定义注解
 * */
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) //@Retention可以设置Anotation的范围,三种参数,RUNTIME范围最大
@Target(ElementType.FIELD) //表示此注解只能用于成员变量和枚举常量
public @interface StudentAnotation {
    int value();//表示此注解可以注解第一个int

}
//使用注释的类
import java.lang.reflect.Field;

public class Student {
    @StudentAnotation(18)  //测试了可以来注解student中的变量,注:是变量,不能注释方法
    private int age;
    @StudentAnotation(7)
    private int j ;

    public Student(){
        Class clazz = Student.class;//得到student类的Class类或写成:Class clazz = this.getClass();
        try {
            Field field = clazz.getDeclaredField("age");//得到age属性
            StudentAnotation sa = field.getAnnotation(StudentAnotation.class);
            if(sa!=null){
                int i = sa.value();//得到属性默认值
                field.setAccessible(true);
                field.set(this, i);//this指的是student对象,将i值赋给了这个对象。
                field.setAccessible(false);
            }

        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }//得到age值
 catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public int getAge() {
        return age;
    }


}
//测试
public class TestAnnoration {

    public static void main(String[] args) {
        Student zhangsan = new Student();
        System.out.println(zhangsan.getAge());

    }

}
/*
结果:
19
*/

三、范例2:

/*要求:范例1的升级版,利用反射传入的值传入一个类的引用型对象中。

*/

/*自定义一个注解类:
 * 控制它的注解范围和注解位置
 * 定义几个注解值注:此处定义的name和age名字都不是唯一的,如果写成value(),在用时直接用: 自定义类名(值)即可。
 * 注意,注解的格式@----()后面没有任何符号
 * */
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TeacherAnnotation {
    String name();
    int age() default 19;//如果age没有设定值就默认为19

}
//clazz中需要用的引用类型
public class Teacher {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }


}
/*Clazz类中:使用注释的类
 * 1.此类中定义了很多成员变量,其中包括几个Teacher变量,并加了注解
 * 2.为使Clazz对象建立时就赋值,将代码写到构造器中。
 * 3.获得Clazz类的Class类对象;获得所有属性;判断哪些属性有注解,并获得注解
 * 4.由于注解的成员变量是一个引用类,这里建立teacher对象,将获得的注解值传入,
 * 5.最后将teacher对象赋给该clazz。由于是该属性去调用set方法,参数是(该clazz对象,teacher对象)
 * */
import java.lang.reflect.Field;

public class Clazz {
    @TeacherAnnotation(age = 20,name = "张三")
    private Teacher javaTeacher;
    @TeacherAnnotation(age = 23,name = "王五")
    private Teacher englishTeacher;
    @TeacherAnnotation(age = 10,name = "李四")
    private Teacher mathTeacher;

    private int clazzTeaher;
    private String name;

    //为使对象初始化就赋值进注解,则将代码写到构造器中
    public Clazz(){
        Class<Clazz> clazz = Clazz.class;
        Field[] fields = clazz.getDeclaredFields();//getDeclaredFields是获得总属性数组
        for(Field field:fields){
            //得到TeacherAnnotation注解,如果没有注解就返回null
            TeacherAnnotation ta = field.getAnnotation(TeacherAnnotation.class);
            if(ta==null){
                continue;
            }else{
                int age = ta.age();
                String name = ta.name();
                //建立teacher对象
                Teacher teacher = new Teacher();
                teacher.setAge(age);
                teacher.setName(name);//根据注解的值创建对象
                field.setAccessible(true);
                try {
                    field.set(this, teacher);//将这个teacher对象赋值给此对象的该属性
                } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                field.setAccessible(false);

            }

        }
    }

    public Teacher getJavaTeacher() {
        return javaTeacher;
    }

    public void setJavaTeacher(Teacher javaTeacher) {
        this.javaTeacher = javaTeacher;
    }

    public Teacher getEnglishTeacher() {
        return englishTeacher;
    }

    public void setEnglishTeacher(Teacher englishTeacher) {
        this.englishTeacher = englishTeacher;
    }

    public Teacher getMathTeacher() {
        return mathTeacher;
    }

    public void setMathTeacher(Teacher mathTeacher) {
        this.mathTeacher = mathTeacher;
    }



}
//测试:
/*
 * 功能:利用反射方法,获取到注解的值。
 * */
public class Test {

    public static void main(String[] args) {
        Clazz clazz = new Clazz();
        System.out.println(clazz.getEnglishTeacher().getName());
        System.out.println(clazz.getJavaTeacher().getAge());


    }

}

注:
范例一和范例二的区别:
在于前者直接获取到注解,直接传给该对象中的该属性。
后者获得属性值传到它的对象,将这个对象传到该对象的这个类属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值