java学习笔记15——反射机制

Java反射机制概述

总结:

通过使用反射前后的例子的对比,回答:
1.面向对象中创建对象,调用指定结构(属性、方法)等功能,可以不使用反射,也可以使用反射。请问有什么区别?
不使用反射,我们需要考虑封装性。比如:出了Person类之后,就不能调用Person类中私有的结构
使用反射,我们可以调用运行时类中任意的构造器、属性、方法。包括了私有的属性、方法、构造器。
2.以前创建对象并调用方法的方式,与现在通过反射创建对象并调用方法的方式对比的话,哪种用的多?
  场景是什么?
> 从我们作为程序员开发者的角度来讲,我们开发中主要是完成业务代码,对于相关的对象、方法的调用都是确定的。
    所以,我们使用非反射的方式多一些,
> 因为反射体现了动态性(可以在运行时动态的获取对象所属的类,动态的调用相关的方法),所以我们在设计框架的时候,
    会大量的使用反射。意味着,如果大家需要学习框架源码,那么就需要学习反射。
    框架 = 注解 +反射 + 设计模式
3.单例模式的饿汉式和懒汉式中,私有化类的构造器了! 此时通过反射,可以创建单例模式中类的多个对象吗?
是的!
4.通过反射,可以调用类中私有的结构,是否与面向对象的封装性有冲突?是不是Java语言设计存在Bug?
不存在bug!
封装性:体现的是是否建议我们调用内部api的问题。比如,private声明的结构,意味着不建议调用
反射:体现的是我们能否调用的问题。因为类的完整结构都加载到了内存中,所有我们就有能力进行调用。

代码:

public class ReflectionTest {
    /**
     * 使用反射之前可以执行的操作
     */
    @Test
    public void test1(){
        //1.创建Person类的实例
        //public Person()
        Person p1 = new Person();
        //2.调用属性
        p1.age = 10;
        System.out.println(p1.age);
        //3.调用方法
        //public void show()
        p1.show();
    }
    /**
     * 使用反射完成上述的操作
     */
    @Test
    public void test2() throws InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {
        //1.创建Person类的实例
        //public Person()
        Class<Person> clazz = Person.class;
        Person p1 = clazz.newInstance();
        System.out.println(p1);
        //2.调用属性
        //public int age
        Field ageField = clazz.getField("age");
        ageField.set(p1,10);
        System.out.println(ageField.get(p1));
        //3.调用方法
        //public void show()
        Method showMethod = clazz.getMethod("show");
        showMethod.invoke(p1);
    }
    /**
     * 出了Person类之后,就不能直接调用Person类中声明的private权限修饰符的结构
     * 但是,我们可以通过反射的方式,调用Person类中私有的结构 ---> 暴力反射
     */
    @Test
    public void test3() throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {
        //1.调用私有的构造器,创建Person的实例
        //private Person(String name,int age)
        Class clazz = Person.class;
        Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
        cons.setAccessible(true);
        Person p1 = (Person) cons.newInstance("Tom", 12);
        System.out.println(p1);
        //2.私有的属性
        //public String name;
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(p1,"Jerry");
        System.out.println(nameField.get(p1));
        //3.调用私有方法
        //private String showNation(String nation)
        Method showNationMethod = clazz.getDeclaredMethod("showNation",String.class);
        showNationMethod.setAccessible(true);
        String info = (String) showNationMethod.invoke(p1,"CHN");
        System.out.println(info);
    }
}
Person 
public class Person {
    //属性
    private String name;
    public int age;

    //构造器
    public Person() {
        System.out.println("Person() ...");
    }

    public Person(int age) {
        this.age = age;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //方法
    public void show(){
        System.out.println("你好,我是一个Perosn");
    }
    private String showNation(String nation){
        return "我的国籍是:" + nation;
    }

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

理解Class类并获取Class的实例

类的加载与ClassLoader的理解

 总结:

1.Class类的理解(掌握)
(如下以Java类的加载为例说明)
针对于编写好的.java源文件进行编译(使用javac.exe),会生成一个或多个.class字节码文件。接着,我们使用
java.exe命令对指定的.class文件进行解释运行。这个解释运行的过程中,我们需要将.class字节码文件加载(使用类的加载器)
到内存中(存放在方法区)。加载到内存中的.class文件对应的结构即为Class的一个实例。
比如:加载到内存中的Person类或String类或User类,都作为Class的一个的实例
Class clazz1 = Person.class; //运行时类
Class clazz2 = String.class;
Class clazz3 =User.class;
Class clazz4= Comparable.class;
说明:运行时类在内存中会缓存起来,在整个执行期间,只会加载一次。
2.体会:Class看做是反射的源头
3.获取Class实例的几种方式(掌握前三种)
见代码
4.Class的实例都可以指向哪些结构呢?(熟悉)
简言之,所有Java类型!
(1)class:外部类,成员(成员内部类,静态内部类),局部内部类,名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void

5.类的加载过程(了解)
过程1:类的装载(loading)
将类的class文件读入内存,并为之创建一个java.lang.class对象。此过程由类加载器完成
过程2:链接(linking)
> 验证(Verify):确保加载的类信息符合JVM规范,例如:以cafebabe开头,没有安全方面的问题。
> 准备(Prepare):正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
> 解析(Resolve):虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
过程3:初始化(initialization)
执行类构造器<clinit>()方法的过程。
类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。

5.关于类的加载器(了解、JDK8版本为例)
5.1 作用:负靠类的加载,并对应于一个class的实例。

5.2 分类(分为两种):
> BootstrapclassLoader:引导类加载器、启动类加载器
    > 使用C/C++语言编写的,不能通过Java代码获取其实例
    > 负责加载Java的核心库(JAVA_HOME/jre/lib/rt.jar或sun.boot.class.path路径下的内容)
> 继承于ClassLoader的类加载器
    > ExtensionClassLoader:扩展类加载器
        > 负贵加载从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录下加载类库
    > SystemclassLoader/ApplicationclassLoader:系统类加载器、应用程序类加载器
        > 我们自定义的类,默认使用的类的加载器,
    > 用户自定义类的加载器
        > 实现应用的隔离(同一个类在一个应用程序中可以加载多份),数据的加密
5.3 以上的类的加载器是否存在继承关系? No!
class ClassLoader{
    ClassLoader parent;
    public ClassLoader(ClassLoader parent){
        this.parent = parent;
    }
}
//测试代码:
ClassLoader loader0 =new ClassLoader();
ClassLoader loader1=new ClassLoader(loader0);
我们就把loader0叫做loader1的父类加载器
6.(掌握)使用类的加载器获取流,并读取配置文件信息
/**
     * 需求:通过ClassLoader加载指定的配置文件
     */
    @Test
    public void test3() throws IOException {
        Properties props = new Properties();
        //此时通过类的加载器读取的文件的默认路径为:当前module下的src下
        //"../info.properties"获取不到
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("info1.properties");
        props.load(is);
        String name = props.getProperty("name");
        String pwd = props.getProperty("password");
        System.out.println(name + ":" + pwd);
    }

代码:

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

    public User() {
        System.out.println("User()...");
    }

    public User(int age) {
        this.age = age;
    }

    public User(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 "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Order 
public class Order {
    static int orderDesc =1;
    static{
        orderDesc = 2;
    }
}

 

ClassTest 
public class ClassTest {
    /**
     * 获取Class实例的几种方式(掌握前三种)
     */
    @Test
    public void test1() throws ClassNotFoundException {
        //1.调用运行时类的静态属性:class
        Class clazz1 = User.class;
        System.out.println(clazz1);

        //2.调用运行时类的对象的getClass()
        User u1 = new User();
        Class clazz2 = u1.getClass();

        //3.调用Class的静态方法forName(String className)
        String className = "com.atguigu02._class.User"; //全类名
        Class clazz3 = Class.forName(className);

        System.out.println(clazz1 == clazz2); //true
        System.out.println(clazz1 == clazz3); //true
        //4.使用类的加载器的方式(了解)
        Class clazz4 = ClassLoader.getSystemClassLoader().loadClass("com.atguigu02._class.User");
        System.out.println(clazz1 == clazz4); //true
    }
    @Test
    public void test2(){
        Class c1 = Object.class;
        Class c2 = Comparable.class;
        Class c3 = String[].class;
        Class c4 = int[][].class;
        Class c5 = ElementType.class;
        Class c6 = Override.class;
        Class c7 = int.class;
        Class c8 = void.class;
        Class c9 = Class.class;

        int[] a = new int[10];
        int[] b = new int[100];
        Class c10 = a.getClass();
        Class c11 = b.getClass();
        // 只要元素类型与维度一样,就是同一个Class
        System.out.println(c10 == c11); //true
    }
}
ClassLoaderTest 
public class ClassLoaderTest {
    /**
     * 在jdk8中执行如下的代码:
     */
    @Test
    public void test1() {
        //获取系统类加载器
        ClassLoader classLoader1 = ClassLoader.getSystemClassLoader();
        System.out.println(classLoader1); //jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
        //获取扩展类加载器
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2); //jdk.internal.loader.ClassLoaders$PlatformClassLoader@73f792cf
        //获取引用类加载器:失败
        ClassLoader classLoader3 = classLoader2.getParent();
        System.out.println(classLoader3); //null
    }

    @Test
    public void test2() throws ClassNotFoundException {
        //用户自定义的类使用的是系统类加载器加载的
        Class clazz1 = User.class;
        ClassLoader classLoader = clazz1.getClassLoader();
        System.out.println(classLoader); //jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
        //对于Java的核心api使用引导类加载器加载的
        Class clazz2 = Class.forName("java.lang.String");
        ClassLoader classLoader1 = clazz2.getClassLoader();
        System.out.println(classLoader1); //null
    }

    /**
     * 需求:通过ClassLoader加载指定的配置文件
     */
    @Test
    public void test3() throws IOException {
        Properties props = new Properties();
        //此时通过类的加载器读取的文件的默认路径为:当前module下的src下
        //"../info.properties"获取不到
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("info1.properties");
        props.load(is);
        String name = props.getProperty("name");
        String pwd = props.getProperty("password");
        System.out.println(name + ":" + pwd);
    }

    //properties:处理属性文件
    @Test
    public void test4() throws IOException {
        Properties props = new Properties();
        //读取的文件的默认路径为:当前module
//        FileInputStream is = new FileInputStream(new File("info.properties"));
        FileInputStream is = new FileInputStream(new File("src/info1.properties"));
        props.load(is);
        String name = props.getProperty("name");
        String pwd = props.getProperty("password");
        System.out.println(name + ":" + pwd);
    }
}

创建运行时类的对象

获取运行时类的完整结构

调用运行时类的指定结构

反射的应用:动态代理

总结:

1.(掌握)反射的应用1:创建运行时类的对象
1.1 如何实现?
通过Class的实例调用newInstance()方法即可
1.2 要想创建对象成功,需要满足:
条件1:要求运行时类中必须提供一个空参的构造器
条件2:要求提供的空参的构造器的权限要足够。
1.3 回忆:JavaBean中要求给当前类提供一个公共的空参的构造器。有什么用?
> 场景1:子类对象在实例化时,子类的构造器的首行默认调用父类空参的构造器。
> 场景2:在反射中,经常用来创建运行时类的对象。那么我们要求各个运行时类都提供一个空参的构造器,便于我们编写
    创建运行时类对象的代码。
1.4 在jdk9中标识为过时,替换成什么结构
通过Constructor类调用newInstance(...)
2.反射应用2:获取运行时类的内部结构
2.1(了解)获取运行时类的内部结构1:所有属性、所有方法、所有构造器
2.2(熟悉)获取运行时类的内部结构2:父类、接口们、包、带泛型的父类、父类的泛型等

3.(掌握)反射的应用3:调用指定的结构:指定的属性、方法、构造器
3.1 调用指定的属性(步骤)
步骤1.通过Class实例调用qetDeclaredField(string fieldName),获取运行时类指定名的属性
步骤2.setAccessible(true):确保此属性是可以访问的,
步骤3.通过Filed类的实例调用get(0bject obj)(获取的操作)
        或 set(0bject obj,0bject value)(设置的操作)进行操作。
3.2 调用指定的方法(步骤)
步骤1.通过Class实例调用getDeclaredField(String methodName,Class ... args), 获取指定的方法
步骤2.setAccessible(true):确保此方法是可访问的
步骤3.通过Method的实例调用invoke(Object obj,Object ... objs),即为对Method对应的方法的调用
     invoke()的返回值即为Method对应的方法的返回值
     特别的:如果Method对应的方法的返回值类型为void,则invoke()返回值为null
3.3 调用指定的构造器

4.(了解)反射的应用4:通过反射获取注解的信息(见com.atguigu04.other.annotation包的测试)
复习:自定义注解
① 参照@SuppressWarnings 进行创建即可,
② 注解要想通过反射的方式获取,必须声明元注解:@Retention(RetentionPolicy.RUNTIME)

代码:

data文件,存储调用的总数据

Creature
public class Creature<T> {
    boolean gender;
    public int id;
    public void breath(){
        System.out.println("呼吸");
    }
    private void info(){
        System.out.println("我是一个生物");
    }
}

Person 
@MyAnnotation("t_persons")
public class Person extends Creature<String> implements Comparable<Person>,MyInterface {
    private String name;
    public int age = 1;
    @MyAnnotation("info")
    private static String info;

    public Person() {
        System.out.println("Person()...");
    }
    protected Person(int age){
        this.age = age;
    }

    private Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void show() throws RuntimeException,ClassNotFoundException{
        System.out.println("你好,我是一个Person");
    }
    @MyAnnotation(value = "show_nation")
    private String showNation(String nation,int age){
        System.out.println("showNation...");
        return "我的国籍是:"+nation+",生活了"+age+"年";
    }

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

    @Override
    public int compareTo(Person o) {
        return 0;
    }

    @Override
    public void method() {

    }
    public static void showInfo(){
        System.out.println("我是一个人");
    }
}
MyAnnotation 
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    //自定义注解 定义默认值hello
    String value() default "hello";
}
MyInterface 
public interface MyInterface {
    void method();
}

应用测试1:

public class NewInstanceTest {
    @Test
    public void test1() throws InstantiationException, IllegalAccessException {
        Class clazz = Person.class;
        //创建Person类的实例
        Person per = (Person) clazz.newInstance();
        System.out.println(per);

    }
}

应用测试2:

FieldsTest
public class FieldsTest {
    @Test
    public void test1(){
        Class clazz = Person.class;
        //getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
//        Field[] fields = clazz.getFields();
//        for(Field f : fields){
//            System.out.println(f);
//        }
        //getDeclareFields():获取当前运行时类中声明的所有属性
        Field[] decalaredFields = clazz.getDeclaredFields();
        for(Field f : decalaredFields){
            System.out.println(f);
        }
    }
    //权限修饰符  变量类型   变量名
    @Test
    public void test2(){
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
            /**
             * 1.权限修饰符
             * 0x是十六进制
             * PUBLIC                 = 0x00000001; 1    1
             * PRIVATE                = 0x00000002; 2    10
             * PROTECTED              = 0x00000004; 4    100
             * STATIC                 = 0x00000008; 8    1000
             * FINAL                  = 0x00000010; 16   10000
             * ...
             */
            int modifier = f.getModifiers();
            System.out.print(modifier + ":" + Modifier.toString(modifier) + "\t");
            //2.数据类型
            Class type = f.getType();
            System.out.print(type.getName() + '\t');
//            //3.变量名
            String fName = f.getName();
            System.out.println(fName);
            System.out.println();
        }
    }
}

 

MethodsTest 
public class MethodsTest {
    @Test
    public void test1(){
        Class clazz = Person.class;
        //getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
//        Method[] methods = clazz.getMethods();
//        for (Method m : methods) {
//            System.out.println(m);
//        }
        //getDeclaredMethods():获取当前运行时类中声明的所有方法
        Method[] decalredMethods = clazz.getDeclaredMethods();
        for (Method m : decalredMethods) {
            System.out.println(m);
        }
    }
    // 注解信息
    // 权限修饰符 返回值类型 方法名(形参类型1 参数1,形参类型2 参数2,...)throws 异常类型1,...{}
    @Test
    public void test2(){
        Class clazz = Person.class;
        Method[] decalredMethods = clazz.getDeclaredMethods();
        for (Method m : decalredMethods) {
            //1.获取方法声明的注解
            Annotation[] annos = m.getAnnotations();
            for (Annotation a : annos) {
                System.out.println(a);
            }
            //2.权限修饰符
            System.out.print(Modifier.toString(m.getModifiers())+'\t');
            //返回值类型
            System.out.print(m.getReturnType().getName()+'\t');
            //4.方法名
            System.out.print(m.getName());
            System.out.print("(");
            //5.形参列表
            Class[] parameterTypes = m.getParameterTypes();
            if(!(parameterTypes == null && parameterTypes.length == 0)){
                for(int i = 0; i < parameterTypes.length; i++){
                    if(i==parameterTypes.length-1){
                        System.out.print(parameterTypes[i].getName() + "args_" + i);
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + "args_"+ i +",");
                }
            }
            System.out.print(")");
            //6.抛出异常
            Class[] exceptionTypes = m.getExceptionTypes();
            if(exceptionTypes.length > 0){
                System.out.println("throws ");
                for(int i = 0; i < exceptionTypes.length; i++){
                    if(i==exceptionTypes.length-1){
                        System.out.println(exceptionTypes[i].getName() + "args_" + i);
                        break;
                    }
                    System.out.print(exceptionTypes[i].getName()+",");
                }
            }
            System.out.println();
        }
    }
}
public class OtherTest {
    //(熟悉)获取运行时类的内部结构2:父类、接口们、包、带泛型的父类、父类的泛型等
    //1.获取运行时类的父类
    @Test
    public void test1() throws ClassNotFoundException {
        Class clazz = Class.forName("com.atguigu03.reflectapply.data.Person");
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }
    //2.获取运行时类实现的接口
    @Test
    public void test2() throws ClassNotFoundException {
        Class clazz = Class.forName("com.atguigu03.reflectapply.data.Person");
        Class[] interfaces = clazz.getInterfaces();
        for (Class c : interfaces) {
            System.out.println(c);
        }
    }
    //3.获取运行时类所在的包
    @Test
    public void test3() throws ClassNotFoundException {
        Class clazz = Class.forName("com.atguigu03.reflectapply.data.Person");
        Package pack = clazz.getPackage();
        System.out.println(pack);
    }
    //4.获取运行时类的带泛型的父类
    @Test
    public void test4() throws ClassNotFoundException {
        Class clazz = Class.forName("com.atguigu03.reflectapply.data.Person");
        Type superclass = clazz.getGenericSuperclass();
        System.out.println(superclass);
    }
    //5.获取运行时类的父类的泛型(难)

    /**
     * 平时写的代码:
     * 类型1:业务逻辑代码(多关注)
     * 类型2:算法逻辑代码(多积累)
     */
    @Test
    public void test5() throws ClassNotFoundException {
        Class clazz = Class.forName("com.atguigu03.reflectapply.data.Person");
        //获取带泛型的父类,(Type是一个接口,Class实现了此接口)
        Type superclass = clazz.getGenericSuperclass();
        //如果父类是带泛型的,则可以强转为ParameterizedType
        ParameterizedType paramType = (ParameterizedType) superclass;
        //调用getActualTypeArguments()获取泛型的参数,结果是一个数组,因为可能有多个泛型参数
        Type[] arguments = paramType.getActualTypeArguments();
        //获取泛型参数的名称
        System.out.println(((Class)arguments[0]).getName());
    }
}

应用测试3:

public class ReflectTest {
    //***********如下是调用指定的属性**************
    /**
     * 反射的应用3-1:调用指定的属性
     */
    //public int age = 1;
    @Test
    public void test1() throws Exception {
        Class clazz = Person.class;
        //
        Person per = (Person) clazz.newInstance();
        //1.获取运行时类指定名的属性
        Field ageField = clazz.getField("age");
        //2.获取或设置此属性的值
        ageField.set(per, 2);
        System.out.println(ageField.get(per));
    }

    //private String name;
    @Test
    public void test2() throws Exception {
        Class clazz = Person.class;
        //
        Person per = (Person) clazz.newInstance();
        //1.通过Class实例调用getDeclaredField(String fieldName), 获取运行时类指定名的属性
        Field nameField = clazz.getDeclaredField("name");
        //2.setAccessible(true):确保此属性是可以访问的
        nameField.setAccessible(true);
        //3.通过Field类的实例调用get(Object obj)(获取的操作)
        //或 set(Object obj,Object value) (设置的操作)  进行操作
        nameField.set(per, "Tom");
        System.out.println(nameField.get(per));
    }

    //private static String info;
    @Test
    public void test3() throws Exception {
        Class clazz = Person.class;
        //
        Person per = (Person) clazz.newInstance();
        //1.通过Class实例调用getDeclaredField(String fieldName), 获取运行时类指定名的属性
        Field infoField = clazz.getDeclaredField("info");
        //2.setAccessible(true):确保此属性是可以访问的
        infoField.setAccessible(true);
        //3.通过Field类的实例调用get(Object obj)(获取的操作)
        //或 set(Object obj,Object value) (设置的操作)  进行操作
//        infoField.set(Person.class,"我是一个人");
//        System.out.println(infoField.get(Person.class));
        //或 (仅限于类变量可以如下的方式调用)
        infoField.set(null, "我是一个人");
        System.out.println(infoField.get(null));
    }
    //***********如下是调用指定的方法**************
    /**
     * 反射的应用3-2:调用指定的方法
     */
    @Test
    public void test4() throws Exception {
        Class clazz = Person.class;
        Person per = (Person) clazz.newInstance();
        //1.通过Class实例调用getDeclaredField(String methodName,Class ... args), 获取指定的方法
        Method showNationMethod = clazz.getDeclaredMethod("showNation", String.class, int.class);
        //2.setAccessible(true):确保此方法是可访问的
        showNationMethod.setAccessible(true);
        //3.通过Method的实例调用invoke(Object obj,Object ... objs),即为对Method对应的方法的调用
        //invoke()的返回值即为Method对应的方法的返回值
        //特别的:如果Method对应的方法的返回值类型为void,则invoke()返回值为null
        Object returnValue = showNationMethod.invoke(per, "CHN", 10);
        System.out.println(returnValue);
    }
    //public static void showInfo()
    @Test
    public void test5() throws Exception {
        Class clazz = Person.class;
        //1.通过Class实例调用getDeclaredField(String methodName,Class ... args), 获取指定的方法
        Method showNationMethod = clazz.getDeclaredMethod("showInfo");
        //2.setAccessible(true):确保此方法是可访问的
        showNationMethod.setAccessible(true);
        //3.通过Method的实例调用invoke(Object obj,Object ... objs),即为对Method对应的方法的调用
        //invoke()的返回值即为Method对应的方法的返回值
        //特别的:如果Method对应的方法的返回值类型为void,则invoke()返回值为null
        Object returnValue = showNationMethod.invoke(null);
        System.out.println(returnValue);
    }
    //***********如下是调用指定的构造器**************
    /**
     * 反射的应用3-3:调用指定的构造器
     */
    //private Person(String name, int age)
    @Test
    public void test6() throws Exception{
        Class clazz = Person.class;
        //1.通过Class的实例调用getDeclaredConstructor(Class ... args),获取指定参数类型的构造器
        Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
        //2.setAccessible(true):确保此构造器是可以访问的
        constructor.setAccessible(true);
        //3.通过Constructor实例调用newInstance(Object ... objs),返回一个运行时类的实例
        Person per = (Person) constructor.newInstance("Tom",12);
        System.out.println(per);
    }
    //使用Constructor替换原有的使用Class调用newInstance()的方式创建对象
    @Test
    public void test7() throws Exception{
        Class clazz = Person.class;
        //1.通过Class的实例调用getDeclaredConstructor(Class ... args),获取指定参数类型的构造器
        Constructor constructor = clazz.getDeclaredConstructor();
        //2.setAccessible(true):确保此构造器是可以访问的
        constructor.setAccessible(true);
        //3.通过Constructor实例调用newInstance(Object ... objs),返回一个运行时类的实例
        Person per = (Person) constructor.newInstance();
        System.out.println(per);
    }
}
针对于注解中信息的获取
1.公式: 框架 = 反射 + 注解 + 设计模式

2.(了解)自定义注解在框架中的使用
相关代码:
public class AnnotationTest {
    //获取类声明上的注解
    @Test
    public void test1(){
        Class clazz = Customer.class;
        Table annotation = (Table)clazz.getDeclaredAnnotation(Table.class);
        System.out.println(annotation.value());
    }
    //获取属性声明的注解
    @Test
    public void test2() throws Exception{
        Class clazz = Customer.class;
        Field nameField = clazz.getDeclaredField("name");
        //获取属性声明上的注解
        Column nameColumn = nameField.getDeclaredAnnotation(Column.class);
        System.out.println(nameColumn.columnName()); //cust_name
        System.out.println(nameColumn.columnType()); //varchar(15)
    }
}


@Target({FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String columnName();
    String columnType();
}

@Target({TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}

@Table(value="t_customer")
public class Customer {
    @Column(columnName = "cust_name",columnType="varchar(15)")
    private String name;
    @Column(columnName = "cust_age",columnType="int")
    public int age;

    public Customer() {
        System.out.println("Customer() ...");
    }

    public Customer(int age) {
        this.age = age;
    }

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

}

体会反射的动态性:

public class ReflectTest {
    //体会:静态性
    public Person getInstance(){
        return new Person();
    }
    //体会:反射的动态性
    public <T> T getInstance(String className) throws Exception{
        Class clazz = Class.forName(className);
        Constructor con = clazz.getDeclaredConstructor();
        con.setAccessible(true);
        return (T) con.newInstance();
    }
    @Test
    public void test1() throws Exception{
        Person p1 = getInstance();
        System.out.println(p1);
        String className = "com.atguigu04.other.dynamic.Person";
        Person per1 = getInstance(className);
        System.out.println(per1);

        String className1 = "java.util.Date";
        Date date1 = getInstance(className1);
        System.out.println(date1);
    }
    //体会:反射的动态性
    //举例2:
    public Object invoke(String className, String methodName) throws Exception{
        //1.创建全类名对应的运行时类的对象
        Class clazz = Class.forName(className);
        Constructor con = clazz.getDeclaredConstructor();
        con.setAccessible(true);
        Object obj = con.newInstance();
        //2.获取运行时类中指定的方法,并调用
        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        return method.invoke(obj);
    }
    @Test
    public void test2() throws Exception{
        String className = "com.atguigu04.other.dynamic.Person";
        String methodName = "show";
        Object returnValue = invoke(className, methodName);
        System.out.println(returnValue);
    }
}

public class Person {
    String name;
    int age;

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

    public Person(int age) {
        this.age = age;
    }

    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;
    }
    public void show(){
        System.out.println("Name: " + name+" Age: " + age);
    }

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

题目:

案例:榨汁机榨水果汁,水果分别有苹果(Apple)、香蕉(Banana)、桔子(Orange)等
效果如图。
提示:
1、声明(Fruit)水果接口,包含榨汁抽象方法:void squeeze();/skwi:z/
2、声明榨汁机(Juicer),包含运行方法:public void run(Fruit f),方法体中,调用f的榨汁方法squeeze()
3、声明各种水果类,实现水果接口,并重写squeeze();
4、在src下,建立配置文件:config.properties,并在配置文件中配上fruitName=xxx(其中xx为某种水果的全类名)
5、在FruitTest测试类中,
(1)读取配置文件,获取水果类名,并用反射创建水果对象,
(2)创建榨汁机对象,并调用run()方法

代码:

public class Apple implements Fruit {
    @Override
    public void squeeze() {
        System.out.println("榨一杯苹果汁儿");
    }
}

public class Banana implements Fruit{
    @Override
    public void squeeze() {
        System.out.println("榨一杯香蕉汁儿");
    }
}

public class Orange implements Fruit{
    @Override
    public void squeeze() {
        System.out.println("榨一杯桔子汁儿");
    }
}

public class Juicer {
    public void run(Fruit f){
        f.squeeze();
    }
}

public interface Fruit {
    //榨汁儿的方法
    void squeeze();
}

public class FruitTest {
    @Test
    public void test1() throws Exception{
        //1.读取配置文件中的信息,获取全类名
        Properties pros = new Properties();
        File file = new File("src/config.properties");
        FileInputStream fis = new FileInputStream(file);
        pros.load(fis);
        String fruitName = pros.getProperty("fruitName");
        //2.通过反射:创建指定全类名对应的类的实例
        Class clazz = Class.forName(fruitName);
        Constructor con = clazz.getDeclaredConstructor();
        con.setAccessible(true);
        Fruit fruit = (Fruit)con.newInstance();
        //3.通过榨汁机的对象调用run()
        Juicer juicer = new Juicer();
        juicer.run(fruit);
    }
}

面试题:

public class Order {
    static int orderDesc =1;
    static{
        orderDesc = 2;
        System.out.println("Order static block ...");
    }
}

public class OrderTest {
    @Test
    public void test1() throws ClassNotFoundException {
        String className = "com.atguigu04.other.interview.Order";
        Class.forName(className);
//        Class.forName(className);
    }
    @Test
    public void test2() throws ClassNotFoundException {
        String className = "com.atguigu04.other.interview.Order";
        ClassLoader.getSystemClassLoader().loadClass(className);
    }
}

public class StringTest {
    /**
     * 针对于核心源码的api,内部的私有的结构在jdk17就不可以通过反射调用了
     */
    @Test
    public void test1() throws Exception {
        Class clazz = Class.forName("java.lang.String");
        String obj = (String)clazz.newInstance();
        //获取value,并获取其值
        Field valueField = clazz.getDeclaredField("value");
        valueField.setAccessible(true);
        valueField.set(obj, 10);
    }
}

对应项目目录:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值