java中最重要的部分——反射、注解

反射

类的加载

类的加载时机

  1. 创建类的实例。
  2. 调用类的静态变量,或者为静态变量赋值。
  3. 调用类的静态方法。
  4. 使用反射方式加载某个类,并生成Class对象。
  5. 初始化某个类的子类。
  6. 直接使用java.exe命令来运行某个主类。

类加载器

我们用到的类都是由类加载器负责加载到内存的。
三种类加载器:
启动类加载器(Bootstrap ClassLoader)
扩展类加载器(Extension ClassLoader)
应用程序类加载器(Application ClassLoader)

双亲委派机制

当某个类加载器需要加载一个类时,它并不是直接去加载,而是把加载的需要交给父类加载器,最终到达启动类加载器。

双亲委派机制的优点

双亲委派机制保证类只加载一次

反射概述

学习的各种框架的设计和底层原理:Spring、SpringMVC、Mybatis等

反射的引入

通过反射技术对象类进行了解剖得到了类的所有成员。

反射的概念

反射中,万物皆对象
Class对象:某个字节码文件
Field对象:某个成员变量
Method对象:某个成员方法
Constructor:某个构造方法
newInstance:创建对象
invoke:调用/执行

调用语法:
正常语法是:对象名.成员方法名(参数)
反射语法是:成员对象名.invoke(对象名,参数)

使用反射操作类成员的前提

反射的应用

Class对象的获取方式

三种获取方式

通过类名.class获得。
通过对象名.getClass()方法获得 。
通过Class类的静态方法获得: static Class forName(“类全名”) * 每一个类的Class对象都只有一个。

Class类常用方法

        Class aClass = Dog.class;
        //获得类全名
        String name = aClass.getName();
        //获得类名
        String simpleName = aClass.getSimpleName();
        //创建class对象所代表的那个类的对象,底层实际上使用Dog的无参构造
        Dog o = (Dog) aClass.newInstance();

反射——操作构造方法(4种方式)

  1. Constructor getConstructor(Class… parameterTypes) //获得单个构造【只能获得public修饰的构造方法】
		//获取单个无参构造方法
        Constructor constructor = aClass.getConstructor();
        //获取单个有参构造
        Constructor constructor1 = aClass.getConstructor(int.class, String.class);
  1. Constructor getDeclaredConstructor(Class… parameterTypes) //获取单个构造【可以是public、protected、(默认)、private修饰符的构造方法】
        //获取单个任意修饰符的构造【public、protected、(默认)、private】
        Constructor constructor2 = aClass.getDeclaredConstructor(int.class, String.class);
  1. Constructor[] getConstructors() //获得类中的所有构造方法对象,只能获得public
        //第一步是获取class对象
        Dog dd = new Dog();
        Class aClass = dd.getClass();
        //获取单个无参构造方法
        Constructor constructor = aClass.getConstructor();
        //使用构造创建对象
        Dog dog = (Dog) constructor.newInstance();
        System.out.println(dog);
        //获取单个有参构造
        Constructor constructor1 = aClass.getConstructor(int.class, String.class);
        //使用构造创建对象【如果是私有构造不能直接使用,因为没有权限】
        Dog dog1 = (Dog) constructor1.newInstance(10, "小明");
        System.out.println(dog1);
        //如果是私有的,需要设置暴力权限
        constructor1.setAccessible(true);
        Dog dog2 = (Dog) constructor1.newInstance(10, "小明");
        System.out.println(dog2);
  1. Constructor[] getDeclaredConstructors() //获得类中的所有构造方法对象 ,可以是public、protected、(默认)、private修饰符的构造方法。
        //获取所有【public】构造
        Constructor[] constructors = aClass.getConstructors();
        System.out.println(Arrays.toString(constructors));
        //获取任意修饰符的构造
        Annotation[] declaredAnnotations = aClass.getDeclaredAnnotations();
        for (Annotation declaredAnnotation : declaredAnnotations) {
            System.out.println(declaredAnnotation);
        }

Constructor的类概述

Class类张与Constructor相关的方法

Constructor对象常用方法

反射——操作成员方法与调用

public class GetMemo {
    public static void main(String[] args) throws NoSuchMethodException {
        //1、第一步是获取class对象
        Dog dd = new Dog();
        Class aClass = dd.getClass();
        //2、获取单个成员方法【方法中没有参数】
        aClass.getMethod("eat");
        aClass.getMethod("eat",String.class,String.class);
        //3、获取任意修饰的
        aClass.getDeclaredMethod("eat",String.class);
        //4、获取所有的成员方法【public且包括父类继承的】
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        //5、获取所有的是私有的成员方法【任意修饰符】不包含父类继承的
        Method[] methodss = aClass.getDeclaredMethods();
        for (Method method : methodss) {
            System.out.println(method);
        }
    }
}

成员对象名.invoke(对象名,参数)

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1、第一步是获取class对象
        Dog dd = new Dog();
        Class aClass = dd.getClass();
        //2、获取单个成员方法【方法中没有参数】
        Method eat = aClass.getMethod("eat");
        //【使用成员方法】
        eat.invoke(dd);
        Method eat1 = aClass.getMethod("eat", String.class, String.class);
        //【使用成员方法】
        eat1.invoke(dd, "饭", "水");
      	//3、获取任意修饰的
        Method eat3 = aClass.getDeclaredMethod("eat", String.class);
        //设置暴力访问权限
        eat3.setAccessible(true);
        eat3.invoke("eat", "饭", "水");

反射——操作构造方法与调用

public class ConstructorDemo01 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //第一步是获取class对象
        Dog dd = new Dog();
        Class aClass = dd.getClass();
        //获取单个无参构造方法
        Constructor constructor = aClass.getConstructor();
        //使用构造创建对象
        Dog dog = (Dog) constructor.newInstance();
        System.out.println(dog);
        //获取单个有参构造
        Constructor constructor1 = aClass.getConstructor(int.class, String.class);
        //使用构造创建对象【如果是私有构造不能直接使用,因为没有权限】
        Dog dog1 = (Dog) constructor1.newInstance(10, "小明");
        System.out.println(dog1);
        //如果是私有的,需要设置暴力权限
        constructor1.setAccessible(true);
        Dog dog2 = (Dog) constructor1.newInstance(10, "小明");
        System.out.println(dog2);
        //获取单个任意修饰符的构造【public、protected、(默认)、private】
        Constructor constructor2 = aClass.getDeclaredConstructor(int.class, String.class);
        //获取所有【public】构造
        Constructor[] constructors = aClass.getConstructors();
        System.out.println(Arrays.toString(constructors));
        //获取任意修饰符的构造
        Annotation[] declaredAnnotations = aClass.getDeclaredAnnotations();
        for (Annotation declaredAnnotation : declaredAnnotations) {
            System.out.println(declaredAnnotation);
        }
    }
}

Method类的概述

注解

JDK1.5的新特性。(注解、泛型、增强for、可变参数)
注解相当于是一种标记,是类的组成部分,可以携带一些额外的信息。注解主要是给编译器看或JVM看的,用于完成某些功能。

注解的作用

1、给程序带入一些参数
2、编译检查
3、给框架使用,作为配置文件

常见注解

1、@author:用来标识作者名,eclipse开发工具默认的是系统用户名。
2、 @version:用于标识对象的版本号,适用范围:文件、类、方法。
3、 @Override :用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方
法,则编译失败。
4、@Test:用于单元测试。

自定义注解

public @interface 注解名{ }
如:定义一个名为Student的注解 public @interface Student { }

给自定义注解添加属性

public @interface 注解名{
//注解内部只有属性,没有别的
格式1:数据类型 属性名();
格式2:数据类型 属性名() default 默认值;

}
注意:
只能是三大类型(1、八大基本类型 2、String,class,注解类型,枚举类 3、以上12种具体数据类型的数组)

案例实现

@Retention(RetentionPolicy.RUNTIME)//时间周期
public @interface Book { 
//包含属性:String value() 书名
//​包含属性:double price() 价格,默认值为 100
//包含属性:String[] authors() 多位作者
    String value();

    double price() default 100;

    String[] authors();
}
public class demo {
    @Book(value = "西游记", authors = {"你", "我"})
    public void show() {
    }
}
public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        //获得字节码文件
        Class<demo> demoClass = demo.class;
        Method show = demoClass.getMethod("show");
        if (show.isAnnotationPresent(Book.class)) {
            System.out.println("有该注解");
            Book annotation = show.getAnnotation(Book.class);
            String value = annotation.value();
            double price = annotation.price();
            String[] authors = annotation.authors();
            System.out.println("书名:" + value);
            System.out.println("价钱:" + price);
            System.out.println("作者:" + Arrays.toString(authors));
        }
    }
}

练习

需求:

  1. 定义一个Person类,包含私有属性name、age,getXxx和setXxx方法和有参满参构造方法。
  2. 使用反射的方式创建一个实例、调用构造函数初始化name、age。使用反射方式调用setName方法对姓名进行设置,不使用setAge方法直接使用反射方式对age。

person.java

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = 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;
    }

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

PersonTest.java

public class PersonTest {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取class对象
        Class<Person> aClass = Person.class;
        Constructor<? extends Person> constructor = aClass.getConstructor(String.class, int.class);
        Person person1 = constructor.newInstance(null, 20);
        //使用成员方法
        Method setName = aClass.getMethod("setName", String.class);
        setName.invoke(person1, "张三");
        //Method setAge = personClass.getMethod("setAge", int.class);
        //setAge.invoke(person1,20);
        System.out.println(person1);
    }

}

需求:

  1. 定义一个类,在类中定义一个成员方法 show ,方法功能是:打印一个字符串。
  2. 使用反射机制创建该类的对象,并调用该对象的 show 方法。

demo01 .java

public class demo01 {
    public void print() {
        System.out.println("打印字符串");
    }
}

Test .java

public class Test {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //先获取class对象
        demo01 dd = new demo01();
        Class aClass = demo01.class;
        //获取单个成员方法
        Method print = aClass.getMethod("print");
        //使用成员方法
        print.invoke(dd);
    }
}
发布了34 篇原创文章 · 获赞 9 · 访问量 1278

猜你喜欢

转载自blog.csdn.net/weixin_43616750/article/details/105155419