day22 反射(Reflect)

day22 反射(Reflect)

1 类加载

类在内存中的生命周期:加载–>使用–>卸载

1.1 类的加载过程

当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化,如果没有意外,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载。

类的加载又分为三个阶段:

(1)加载:load

就是指将类型的clas字节码数据读入内存。

  • 通过类的全名,获取类的二进制数据流。
  • 解析类的二进制数据流为方法区内的数据结构(Java类模型)
(2)连接:link
①验证:校验合法性等
1.格式验证:是否以0XCAFEBABE开头,数据中每一个项是否都拥有正确的长度等。

2.语义检查:Java虚拟机会进行字节码的语义检查,但凡在语义上不符合规范的,虚拟机也不会给予验证通过。比如:
	是否所有的类都有父类的存在(在Java里,除了Object外,其他类都应该有父类)
	是否一些被定义为final的方法或者类被重写或继承了
	非抽象类是否实现了所有抽象方法或者接口方法
	
3.字节码验证:Java虚拟机还会进行字节码验证,字节码验证也是验证过程中最为复杂的一个过程。它试图通过对字节码流   的分析,判断字节码是否可以被正确地执行。比如:
	函数的调用是否传递了正确类型的实参
	变量的赋值是不是给了正确的数据类型等
②准备:准备对应的内存

准备对应的内存(方法区),创建Class对象,为类变量赋默认值,为静态常量赋初始值。

为类变量赋默认值,为静态常量赋初始值。
class A{
 	static int age = 10;//类变量 静态变量 age = 0
	final static String name = "张三"; //静态常量

}
③解析:将类、接口、字段和方法的符号引用转为直接引用

符号引用就是一些字面量的引用,和虚拟机的内部数据结构和和内存布局无关。比较容易理解的就是在Class类文件中,通过常量池进行了大量的符号引用。但是在程序实际运行时,只有符号引用是不够的,系统需要明确知道数据的位置。

System.out.println("ABC");
(3)初始化:initialize

initialize(类初始化)即执行类初始化方法,大多数情况下,类的加载就完成了类的初始化,有些情况下,会延迟类的初始化。
在这里插入图片描述

1.2 类初始化

1、哪些操作会导致类的初始化?

(1)运行主方法所在的类,要先完成类初始化,再执行main方法

(2)第一次使用某个类型就是在new它的对象,此时这个类没有初始化的话,先完成类初始化再做实例初始化

(3)调用某个类的静态成员(类变量和类方法),此时这个类没有初始化的话,先完成类初始化

(4)子类初始化时,发现它的父类还没有初始化的话,那么先初始化父类

(5)通过反射操作某个类时,如果这个类没有初始化,也会导致该类先初始化

类初始化执行的是(),该方法由(1)类变量的显式赋值代码(2)静态代码块中的代码构成

Person代码:
package com.atguigu.reflect.load;

public class Person {

    static String name = "张三";
    static final int age = 90;

    static {
        System.out.println("Person 静态代码块一");
    }

    public static void show(){
        System.out.println("show--------------");
    }
}


class Son extends Person{

    static {
        System.out.println("------Son static Code-----");
    }

    public static void s1(){
        System.out.println("this is Son s1()");
    }
}
BaseTest代码:
package com.atguigu.reflect.load;

import org.junit.Test;

/**
 * 类的生命周期:
 *      加载 ---> 使用 ---> 卸载
 * 类的加载过程:
 *      1.加载
 *          将字节码文件加载到内存
 *      2.连接
 *          2.1 验证
 *              验证字节码文件的合法性
 *          2.2 准备 对静态变量开辟对应的内存
 *              如果是静态常量 会赋初始值
 *              如果是静态变量 会赋默认值
 *          2.3 解析
 *              将符号引用替换为直接地址引用
 *      3.类的初始化
 *          给静态变量赋值
 *          <clinit>
 *              静态成员变量显示赋值语句
 *              静态代码块内容
     *      触发类初始化的操作:
     *          1.使用了类中的静态资源(属性和方法)
     *          2.创建对象
     *          3.反射操作也会导致类的初始化
     *          4.存在继承关系 使用子类的静态资源会进行父类初始化再进行子类初始化
 *          类的初始化滞后:
 *              1.子类使用了从父类继承的静态资源(属性和方法) 只会触发父类初始化不会触发子类初始化
 *              2.使用了类中的静态常量 不会触发类的初始化 在类加载的连接的准备阶段已经完成赋值
 *              3.使用类型创建数组不会导致类的初始化
 *
 * 类的加载器:
 *      java中有很多的类 按需加载 通过类的加载器进行加载
 *      引导类加载器:加载核心类库 java安装包下 /jre/lib/ rt.jar
 *      扩展类加载器
 *      应用/系统程序加载器
 * */
public class BaseTest {

    public static int age = 20;
    public final static String name = "张三";

    @Test
    public void test06(){
        // 使用类型创建数组不会导致类的初始化
        Son[] sons = new Son[3];
    }

    @Test
    public void test05(){
        // 使用了类中的静态常量 不会触发类的初始化 在类加载的连接的准备阶段已经完成赋值
        System.out.println("Person.age = " + Person.age);

    }

    @Test
    public void test04(){
        // 子类使用了从父类继承的静态属性 只会触发父类初始化不会触发子类初始化
        System.out.println("Son.name = " + Son.name);
    }

    @Test
    public void test03(){
        // 使用了子类的静态方法会进行父类初始化再进行子类初始化
        Son.s1();
    }

    @Test
    public void test02() throws ClassNotFoundException {
        // 会触发类初始化
        Class aClass = Class.forName("com.atguigu.reflect.load.Person");  // Person 静态代码块一
    }

    @Test
    public void test01(){
        Person.show();
        System.out.println("-----");
        Person.show();
    }

    public static void show(String s){
        System.out.println("s = " + s);
    }
}

1.3 类加载器

很多开发人员都遇到过java.lang.ClassNotFoundException或java.lang.NoClassDefError,想要更好的解决这类问题,或者在一些特殊的应用场景,比如需要支持类的动态加载或需要对编译后的字节码文件进行加密解密操作,那么需要你自定义类加载器,因此了解类加载器及其类加载机制也就成了每一个Java开发人员的必备技能之一。

1、类加载器分为:

(1)引导类加载器(Bootstrap Classloader)又称为根类加载器

它负责加载jre/rt.jar核心库
它本身不是Java代码实现的,也不是ClassLoader的子类,获取它的对象时往往返回null

(2)扩展类加载器(Extension ClassLoader)

它负责加载jre/lib/ext扩展库
它是ClassLoader的子类

(3)应用程序类加载器(Application Classloader)

它负责加载项目的classpath路径下的类

它是ClassLoader的子类

(4)自定义类加载器

当你的程序需要加载“特定”目录下的类,可以自定义类加载器;
当你的程序的字节码文件需要加密时,那么往往会提供一个自定义类加载器对其进行解码
后面会见到的自定义类加载器:tomcat中
类加载代码:
package com.atguigu.reflect.load;

import org.junit.Test;

/**
 * 二。类的加载器:
 *      java中有很多的类 按需加载 通过类的加载器进行加载
 *
 *      引导类加载器:null
 *          加载核心类库  java安装包下/jre/lib/ rt.jar
 *
 *      扩展类加载器  ExtClassLoader
 *                      jdk1.8\jre\lib\ext
 *
 *      应用/系统程序加载器  AppClassLoader
 *              自定义类 Person Cat
 *
 *         AppClassLoader  ---> ExtClassLoader ---> null 引导类加载器
 * */


class A{}

public class ClassLoaderTest {

    @Test
    public void test04(){
        String s;
        // 类的加载器之间的关系
        Class<A> aClass = A.class;
        ClassLoader classLoader = aClass.getClassLoader();
        System.out.println("classLoader = " + classLoader);  // classLoader = sun.misc.Launcher$AppClassLoader@18b4aac2

        // 应用程序加载器的父类 扩展类加载器
        ClassLoader classLoaderParent = classLoader.getParent();
        System.out.println("classLoaderParent = " + classLoaderParent);  // classLoaderParent = sun.misc.Launcher$ExtClassLoader@27716f4

        ClassLoader classLoaderParentParent = classLoaderParent.getParent();
        // 扩展类加载器的父类 引导类加载器
        System.out.println("classLoaderParentParent = " + classLoaderParentParent);  // classLoaderParentParent = null


    }

    @Test
    public void test03(){
        // 获取系统加载器
        Class<A> aClass = A.class;

        ClassLoader classLoader = aClass.getClassLoader();

        System.out.println("classLoader = " + classLoader);  // classLoader = sun.misc.Launcher$AppClassLoader@18b4aac2
    }

    @Test
    public void test02() throws ClassNotFoundException {
        // 获取扩展类加载器
        // 1.获取class对象
        Class<?> aClass = Class.forName("com.sun.nio.zipfs.ZipCoder");

        // 2.通过class对象获取类的加载器
        ClassLoader classLoader = aClass.getClassLoader();

        System.out.println("classLoader = " + classLoader);  // classLoader = sun.misc.Launcher$ExtClassLoader@27716f4
    }

    @Test
    public void test01(){
        // 获取引导类加载器
        // 1.获取Class对象
        Class<String> stringClass = String.class;

        // 2.Class对象 获取加载器
        ClassLoader classLoader = stringClass.getClassLoader();

        System.out.println("classLoader = " + classLoader);  // classLoader = null
    }
}

2、Java系统类加载器的双亲委托模式(parents delegate)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-07tIX0QL-1665815980070)(imgs\双亲委托1.jpg)]

简单描述:

下一级的类加载器,如果接到任务时,会先搜索是否加载过,如果没有,会先把任务往上传,如果都没有加载过,一直到根加载器,如果根加载器在它负责的路径下没有找到,会往回传,如果一路回传到最后一级都没有找到,那么会报ClassNotFoundExceptionNoClassDefError,如果在某一级找到了,就直接返回Class对象。

优势

1.采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。
2.安全,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

应用程序类加载器 把 扩展类加载器视为父加载器,

扩展类加载器 把 引导类加载器视为父加载器。

1.4类的卸载

在这里插入图片描述

2 javalang.Class类

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API(1)java.lang.Class(2)java.lang.reflect.*。所以,Class对象是反射的根源。

1、哪些类型可以获取Class对象

所有Java类型

用代码示例

//(1)基本数据类型和void
例如:int.class
	 void.class
//(2)类和接口
例如:String.class
	Comparable.class
//(3)枚举
例如:ElementType.class
//(4)注解
例如:Override.class
//(5)数组
例如:int[].class

2、获取Class对象的四种方式

(1)类型名.class

要求编译期间已知类型

(2)对象.getClass()

获取对象的运行时类型

(3)Class.forName(类型全名称)

可以获取编译期间未知的类型

(4)ClassLoader的类加载器对象.loadClass(类型全名称)

可以用系统类加载对象或自定义加载器对象加载指定路径下的类型

Animal代码:
package com.atguigu.reflect.clazz;

public class Animal {

    public void eat(){
        System.out.println("动物吃饭");
    }

}

class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("小猫爱吃鱼....");
    }
}


class Dog extends Animal implements A, B{
    @Override
    public void eat() {
        System.out.println("小狗爱吃骨头....");
    }
}

interface A{}

interface B{}

GetClass代码:
package com.atguigu.reflect.clazz;

import org.junit.Test;
/*
获取Class对象四种方式:
    1.对象名.getClass();

    2.类名.class *****

    3.Class.forName("全类名/全路径名") *****

    4.类的加载器.loadClass("全类名/全路径名");
 */
public class GetClass {

    @Test
    public void test04() throws ClassNotFoundException {
        Class<Cat> catClass = Cat.class;
        ClassLoader classLoader = catClass.getClassLoader();

        Class<?> aClass = classLoader.loadClass("com.atguigu.reflect.clazz.Animal");

        System.out.println("aClass = " + aClass);  // aClass = class com.atguigu.reflect.clazz.Animal
    }

    @Test
    public void test03() throws ClassNotFoundException {
        Class<?> aClass = Class.forName("com.atguigu.reflect.clazz.Cat");
        System.out.println("aClass = " + aClass);  // aClass = class com.atguigu.reflect.clazz.Cat
    }

    @Test
    public void test02(){
        Class<Cat> catClass = Cat.class;
        System.out.println("catClass = " + catClass);  // catClass = class com.atguigu.reflect.clazz.Cat
    }

    @Test
    public void test01(){
        Animal a = new Cat();
        a.eat();  // 小猫爱吃鱼....
        Class aClass = a.getClass();
        System.out.println("aClass = " + aClass);  // aClass = class com.atguigu.reflect.clazz.Cat
    }
}

3 反射的应用

3.1 获取类型的详细信息

可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)

示例代码获取常规信息:

package com.atguigu.reflect.clazz;

public final class C {
}

package com.atguigu.reflect.clazz;

import org.junit.Test;

import java.lang.reflect.Modifier;
import java.util.Scanner;

public class ReflectTest {

    @Test
    public void test05(){
        Class<C> cClass = C.class;

        int modifiers = cClass.getModifiers();
        System.out.println("modifiers = " + modifiers);  // modifiers = 17

        String s = Modifier.toString(modifiers);
        System.out.println("s = " + s);  // s = public final
    }

    @Test
    public void test04(){
        Class<Animal> animalClass = Animal.class;

        Package aPackage = animalClass.getPackage();  // 获取包信息
        System.out.println("aPackage = " + aPackage);  // aPackage = package com.atguigu.reflect.clazz

        // 获取修饰符 int
        int modifiers = animalClass.getModifiers();
        System.out.println("modifiers = " + modifiers);  // modifiers = 1

        // 将int转换为修饰符名
        String s = Modifier.toString(modifiers);
        System.out.println("s = " + s);  // s = public

    }

    @Test
    public void test03(){
        Class<Dog> dogClass = Dog.class;

        // 获取继承的父类
        Class<? super Dog> superclass = dogClass.getSuperclass();
        System.out.println("superclass = " + superclass);  // superclass = class com.atguigu.reflect.clazz.Animal

        // 获取继承的接口 数组类型
        Class<?>[] interfaces = dogClass.getInterfaces();

        for (Class<?> anInterface : interfaces) {
            System.out.println("anInterface = " + anInterface);

        }
    }

    @Test
    public void test02() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        Scanner scan = new Scanner(System.in);
        System.out.println("请问您想要什么动物");

        String info = scan.next();  // 输入 com.atguigu.reflect.clazz.Animal

        Class<?> aClass = Class.forName(info);

        Object o = aClass.newInstance();

        System.out.println("o = " + o);  // o = com.atguigu.reflect.clazz.Animal@78e03bb5
    }

    @Test
    public void test01(){
        Animal a = new Animal();

        a.eat();  // 动物吃饭

        Cat c = new Cat();
        c.eat();  // 小猫爱吃鱼....

        Dog d = new Dog();
        d.eat();  // 小狗爱吃骨头....
    }
}

3.2 创建任意引用类型的对象

示例代码:

package com.atguigu.reflect.instance;

public class Person {

    private String name;
    private int age;
    private double salary;
    private double height;

    public Person() {
        System.out.println("------------- Person() ------------");
    }

    public Person(String name, int age, double salary, double height) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.height = height;
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private Person(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    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 double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

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

package com.atguigu.reflect.instance;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class PersonTest {
    @Test
    public void test05() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 私有构造器

        // 1.获取Class对象
        Class<Person> personClass = Person.class;

        // 2.获取指定的构造器
        Constructor<Person> constructor = personClass.getDeclaredConstructor(String.class, double.class);

        // 3.给构造器赋值创建对象
        // 需设置私有资源可以操作,不然会报错
        constructor.setAccessible(true);  // person = Person{name='王安石', age=0, salary=100000.0, height=0.0}
        Person person = constructor.newInstance("王安石", 100000);

        // 4.输出对象
        System.out.println("person = " + person);
    }


    @Test
    public void test04() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 默认权限的构造器

        // 1.获取Class对象
        Class<Person> personClass = Person.class;

        // 2.获取指定的构造器
        Constructor<Person> constructor = personClass.getDeclaredConstructor(String.class, int.class);

        // 3.给构造器赋值创建对象
        Person person = constructor.newInstance("杜甫", 20);

        // 4.输出对象
        System.out.println("person = " + person);  // person = Person{name='杜甫', age=20, salary=0.0, height=0.0}
    }

    @Test
    public void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 有参 public 构造器
        // 1.创建Class对象
        Class<?> aClass = Class.forName("com.atguigu.reflect.instance.Person");
        // 2.获取指定的构造器
        Constructor<?> constructor = aClass.getConstructor(String.class, int.class, double.class, double.class);

        // 3.给构造器赋值 完成对象创建
        Object o = constructor.newInstance("李白", 18, 20000.0, 1.87);

        // 4.输出对象
        System.out.println("o = " + o);  // o = Person{name='李白', age=18, salary=20000.0, height=1.87}
    }

    @Test
    public void test02() throws IllegalAccessException, InstantiationException {
        // 使用无参构造器创建对象
        // 1.获取Class对象
        Class<Person> personClass = Person.class;

        // 2.创建对象
        Person person = personClass.newInstance();

        System.out.println("person = " + person);  // person = Person{name='null', age=0, salary=0.0, height=0.0}
    }

    @Test
    public void test01() throws NoSuchMethodException {
        // 1.获取所有的构造器

        // 获取Class对象
        Class<Person> personClass = Person.class;

        // 2.获取构造器
        // 获取公共的构造器 getConstructors()
//        Constructor<?>[] constructors = personClass.getConstructors();

        // 获取所有的构造器 包括私有
        Constructor<?>[] constructors = personClass.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("constructor = " + constructor);
        }
    }
}

3.3 操作任意类型的属性

(1)获取该类型的Class对象
Class clazz = Class.forName(“com.atguigu.bean.User”);

(2)获取属性对象
Field field = clazz.getDeclaredField(“username”);

(3)设置属性可访问

field.setAccessible(true);

(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象
Object obj = clazz.newInstance();

(4)设置属性值

field.set(obj,“chai”);
(5)获取属性值
Object value = field.get(obj);

如果操作静态变量,那么实例对象可以省略,用null表示

示例代码:

package com.atguigu.reflect.field;

class Man{
    public String a = "MAN";

    private int c = 20;
}


public class Person extends Man{

    public static int age = 28;
    public String name = "张三";

    private static double salary = 90000;

    private double height = 1.87;

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

package com.atguigu.reflect.field;

import org.junit.Test;

import java.lang.reflect.Field;

public class PersonTest {

    @Test
    public void test05() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        // 私有的height
        // 1.获取Class对象
        Class<Person> personClass = Person.class;
        // 2.获取指定的属性
        Field height = personClass.getDeclaredField("height");
        // 3.创建对象
        Person person = personClass.newInstance();
        // 4.设置私有属性可以操作 不设置将会报错
        height.setAccessible(true);
        // 5.赋值
        height.set(person, 1.76);
        // 6.获取值
        Object value = height.get(person);
        System.out.println("value = " + value);  // value = 1.76


    }

    @Test
    public void test04() throws NoSuchFieldException, IllegalAccessException {
        // 操作公共静态的age

        // 1.获取Class对象
        Class<Person> personClass = Person.class;
        // 2.获取指定的属性
        Field age = personClass.getField("age");
        // 3.设置值
        age.set(null, 90);
        // 4.获取值
        Object value = age.get(null);
        System.out.println("value = " + value);  // value = 90

    }

    @Test
    public void test03() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        // 操作name属性
        // 1.获取Class对象
        Class<Person> personClass = Person.class;
        // 2.获取指定的属性
        Field name = personClass.getField("name");
        // 3.创建对象
        Person person = personClass.newInstance();
        System.out.println("赋值前 = " + person);  // 赋值前 = Person{age=28, name='张三', salary=90000.0, height=1.87}
        // 4.给属性赋值 将白居易赋值给person的name属性
        name.set(person, "白居易");
        // 5.获取属性值
        Object value = name.get(person);
        System.out.println("value = " + value);  // value = 白居易
        // 6.输出对象信息
        System.out.println("赋值后 = " + person);  // 赋值后 = Person{age=28, name='白居易', salary=90000.0, height=1.87}
    }

    @Test
    public void test02(){
        Person.age = 90;
        System.out.println("Person.age = " + Person.age);  // Person.age = 90

        Person p1 = new Person();
        p1.name = "王安石";
        System.out.println("p1.name = " + p1.name);  // p1.name = 王安石
    }

    @Test
    public void test01(){
        Class<Person> personClass = Person.class;

        // 本类以及父类中公共的属性
//        Field[] fields = personClass.getFields();

        // 获取本类中所有的属性 包括private权限的
        Field[] fields = personClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("field = " + field);
        }
    }
}

3.4 调用任意类型的方法

(1)获取该类型的Class对象
Class clazz = Class.forName(“com.atguigu.service.UserService”);
(2)获取方法对象
Method method = clazz.getDeclaredMethod(“login”,String.class,String.class);
(3)创建实例对象
Object obj = clazz.newInstance();
(4)调用方法
Object result = method.invoke(obj,“chai”,"123);

如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

如果方法是静态方法,实例对象也可以省略,用null代替

示例代码:

package com.atguigu.reflect.method;

public class Person {

    public static void show(String message){
        System.out.println("this is static show()" + message);
    }

    public int sum(int a, int b){
        System.out.println("this is sum()");
        return a + b;
    }

    private static String getMessage(int a, double b){
        return "李白" + a + b;
    }

    private void cc(String a){
        System.out.println("this is cc()" + a);
    }
}

package com.atguigu.reflect.method;

import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class PersonTest {

    @Test
    public void test04() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 1.获取Class对象
        Class<Person> personClass = Person.class;
        // 2.获取指定的方法
        Method method = personClass.getDeclaredMethod("getMessage", int.class, double.class);
        // 3.设置私有方法可以操作
        method.setAccessible(true);
        // 4.执行方法获取结果
        Object result = method.invoke(null, 100, 3.14);
        System.out.println("result = " + result);  // result = 李白1003.14


    }

    @Test
    public void test03() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 1.获取Class对象
        Class<Person> personClass = Person.class;
        // 2.获取指定的方法
        Method method = personClass.getDeclaredMethod("sum", int.class, int.class);
        // 3.创建对象
        Person person = personClass.newInstance();
        // 4.执行方法
        Object result = method.invoke(person, 30, 60);
        // 5.输出方法的执行结果
        System.out.println("result = " + result);  // result = 90
    }

    @Test
    public void test02(){
        Person.show("你好");
        System.out.println("------------");  // this is static show()你好

        Person p1 = new Person();
        System.out.println("p1.sum(10, 20) = " + p1.sum(10, 20));  // p1.sum(10, 20) = 30
    }

    @Test
    public void test01(){
        // 1.获取Class对象
        Class<Person> personClass = Person.class;
        // 2.获取所有的方法
        // 获取本类以及父类中公共的方法
//        Method[] methods = personClass.getMethods();

        // 获取本类中所有方法 包含私有的
        Method[] methods = personClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("method = " + method);

        }
    }
}

3.5 动态创建和操作任意类型的数组

在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过使用Array类来动态的创建数组,操作数组元素等。

Array类提供了如下几个方法:

public static Object newInstance(Class<?> componentType, int… dimensions):创建一个具有指定的组件类型和维度的新数组。

public static void setXxx(Object array,int index,xxx value):将array数组中[index]元素的值修改为value。此处的Xxx对应8种基本数据类型,如果该属性的类型是引用数据类型,则直接使用set(Object array,int index, Object value)方法。

public static xxx getXxx(Object array,int index,xxx value):将array数组中[index]元素的值返回。此处的Xxx对应8种基本数据类型,如果该属性的类型是引用数据类型,则直接使用get(Object array,int index)方法。

示例代码:

package com.atguigu.reflect.other;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Animal<T, O> {
}


class Dog extends Animal<String, Integer>{
    public static void main(String[] args){
        Class<Dog> dogClass = Dog.class;

        // 获取父类
        Type genericSuperclass = dogClass.getGenericSuperclass();

        ParameterizedType p1 = (ParameterizedType)genericSuperclass;

        // 获取父类的参数类型
        Type[] types = p1.getActualTypeArguments();

        for (Type type : types) {
            System.out.println("type = " + type);

        }
    }
}

package com.atguigu.reflect.other;

import org.junit.Test;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class ArrayTest {

    @Test
    public void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<Integer> list = new ArrayList<>();

        list.add(10);

//        list.add("李白");  // 报错

        // 通过反射方式添加数组 可以避过泛型的检查
        // 1.获取class对象
        Class aClass = list.getClass();
        // 获取方法
        Method add = aClass.getMethod("add", Object.class);

        // 执行方法
        add.invoke(list, "李白");

        System.out.println("list = " + list);  // list = [10, 李白]

    }

    @Test
    public void test01(){
        // 通过反射创建数组
        Object o = Array.newInstance(String.class, 6);

        // 添加值
        Array.set(o, 1, "王安石");

        // 获取值
//        Object value = Array.get(o, 10);  // ArrayIndexOutOfBoundsException
        Object value = Array.get(o, 1);
        System.out.println("value = " + value);  // value = 王安石


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值