java注解与反射


一、元注解

//元注解
@Target({ElementType.METHOD,ElementType.TYPE})//注解用在哪儿:方法 或 类
@Retention(RetentionPolicy.RUNTIME)//何时有效:runtime>class>sources
@Documented//将注解生成在javadoc中
@Inherited//子类可以继承父类的注解
@Deprecated//废弃的
@SuppressWarnings("all")//镇压警告
@interface MyAnnotation{
    String[] name();//成员变量要加()
    int age() default 18;//default表示默认值
}
@MyAnnotation(name={"张三","张德旺"},age=33)
public class TestAnnotation extends Object{
    @MyAnnotation(name={"张三","张德旺"},age=33)
    public static void main(String[] args) {
        System.out.println();
    }
}

二、反射

获得反射的class

package day27__Annotation;

public class TestReflection {
    public static void main(String[] args) throws ClassNotFoundException {
        TestAnnotation ta = new TestAnnotation();
        //System.out.println(ta);

        Class<? extends TestAnnotation> c1 = ta.getClass();
        System.out.println(c1);

        Class<?> c2 = Class.forName("day27__Annotation.TestAnnotation");
        System.out.println(c2);

        Class c3 = TestAnnotation.class;
        System.out.println(c3);


        //内置基本类型,都会有一个type
        Class it = Integer.TYPE;
        System.out.println(it);

        Class<?> c5 = c1.getSuperclass();
        System.out.println(c5);
    }
}

练习:获取以下类型的class

class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

interface:接口

[]∶数组

enum:枚举

annotation:注解@interface

primitive type:基本数据类型

void

public class TestReflection2 {
    public static void main(String[] args) {
        System.out.println("类:"+Student.class);//类
        System.out.println("数组:"+int[].class);//数组
        System.out.println("二维数组:"+int[][].class);//二维数组
        System.out.println("接口:"+List.class);//接口
        System.out.println("枚举:"+ElementType.class);//枚举
        System.out.println("int:"+int.class);
        System.out.println("Integer:"+Integer.class);
        System.out.println("void:"+void.class);
        System.out.println("Class:"+Class.class);
    }
}

1.获取成员变量:

 练习:对 Student 类,通过反射得到其中的字段,并练习使用 set 和 get 方法

package day27_Reflection;

public class Student {
    public String name;
    protected int age;
    String gender;
    private int id;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        if (id != student.id) return false;
        if (name != null ? !name.equals(student.name) : student.name != null) return false;
        return gender != null ? gender.equals(student.gender) : student.gender == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        result = 31 * result + (gender != null ? gender.hashCode() : 0);
        result = 31 * result + id;
        return result;
    }

    public Student() {
    }

    public Student(String name, int age, String gender, int id) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.id = id;
    }

    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;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", id=" + id +
                '}';
    }
}
package day27_Reflection;

public class Student {
    public String name;
    protected int age;
    String gender;
    private int id;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        if (id != student.id) return false;
        if (name != null ? !name.equals(student.name) : student.name != null) return false;
        return gender != null ? gender.equals(student.gender) : student.gender == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        result = 31 * result + (gender != null ? gender.hashCode() : 0);
        result = 31 * result + id;
        return result;
    }

    public Student() {
    }

    public Student(String name, int age, String gender, int id) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.id = id;
    }

    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;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", id=" + id +
                '}';
    }
}

2. 获取构造器

两种 get 方式的区别:

Class类的getConstructor()方法,无法获取到类的私有构造器.
Class类的getDeclaredConstructor()方法,可获取到类的私有构造器(包括带有其他修饰符的构造器),但必须设置setAccessible(true)

练习:通过反射获取Class的构造器,并分别创建有参和无参的实例。

package day27_Reflection;

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

        Constructor studentConstructor=Student.class.getConstructor(String.class,int.class,String.class,int.class);
        System.out.println(studentConstructor);

        Student zs=studentConstructor.newInstance("张三",23,"男",12121212);
        System.out.println(zs);

        Student stu1 = Student.class.newInstance();//newInstance 继承自class类
        Student stu2 = Student.class.getConstructor().newInstance();
        System.out.println(stu1);
        System.out.println(stu2);
    }
}

 3 获取方法

练习:利用反射获取方法

public class TestReflectionMethod {
    public static void main(String[] args) throws Exception {
        Method eatMethod = Student.class.getMethod("eat");
        Method eatMethod2= Student.class.getMethod("eat",String.class);

        Student stu=Student.class.newInstance();
        eatMethod.invoke(stu);
        eatMethod2.invoke(stu,"noodle");
     System.out.println(eatMethod.getname()); } }

练习:反射案例

需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

解题思路:

1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中

2.在程序中加载读取配置文件

3.使用反射技术来加载类文件进内存

4.创建对象

5.执行方法 method.invoke(Object)

学生类:

public class Student {
    String name;
    int id;
    void eat(){
        System.out.println("eat...");
    }
    void eat(String food){
        System.out.println("eat "+food);
    }
}

教师类:

public class Teacher {
    void sleep(){
        System.out.println("sleep...");
    }
}

反射测试类:

public class TestReflection {
    public static void main(String[] args) throws Exception {
        //1. 创建一个空properties,并加载
        Properties pro = new Properties();
        InputStream is=TestReflection.class.getResourceAsStream("pro.properties");
        pro.load(is);

        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        Class<?> aClass = Class.forName(className);
        Object obj= aClass.newInstance();
        Method method=aClass.getDeclaredMethod(methodName);
        //激发invoke
        method.invoke(obj);
    }
}  

配置文件 pro.properties(与 Student 同一文件夹)

className=day28.Teacher
methodName=sleep

修改配置文件

className=day28.Student
methodName=eat 

输出会发生变化