JAVA高级-反射与动态代理(十五)

观看尚硅谷视频做的视频笔记

一、高级-反射与动态代理(十四)

1、反射概述

1)java程序中,所有的对象都有两种类型:编译时类型,运行时类型,而很多时候对象的编译类型和运行时类型不一致。

此处就是多态性体现。

Object obj=new String(“hello”);

2)例如:某些变量或形参的声明类型是Object类型,但是程序却需要调用该对象运行时类new String(“hello”);的方法compareTo方法,该方法不是Object中的方法,那么如何解决?

方案1:多态中有用到,向下转型。在编译和运行是都完全知道类型的具体的信息,在这种情况下,我们可以直接先使用instanceof运算符进行判断是否为String类型,若是就利用强制类型转换符将其转成运行时类的变量即可,强制转换后就可以用String里面的方法。缺点:①若用这种方法会写很多instanceof这种判断。②此判断是否全,是否满足需求。此时写好了代码,形参是Object类型。判断obj是否为A类型,是就进行强转,调方法,B类型,C类型,目前只是ABC三个对象。后续可能DEF,也有可能作为参数传进来,就需要进行修改,有没有更好的方案解决此问题,自然而然就考虑方案2.

在这里插入图片描述

方案2:编译时根本无法预知该对象和类的真实信息,程序只能依靠运行时obj已经在内存中,信息来发现该对象和类的真实信息,这就必须使用反射。(程序运行过程中,动态获取所属类的类型obj.getClass,obj对象是哪个类造的,动态获取,及时把类转换成声明,动态的转换,再去调特有的方法就需要用到反射)

obj.getClass在Object中声明
框架中用的比较多。

3)反射是被是视为动态语言的关键,反射机制允许程序在运行期间借助于RelectionAPI取得任何类得内部信息,并能直接操作任意对象得内部属性及方法。(跟对象里面方法属性的权限都无关)

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象。(一个类只有一个Class对象),这个对象就包含了完整的类的结构的信息。我们可以i通过这个对象看到类的结构,这个对象就像一面镜子,通过这个镜子看到类的结构,所以我们形象的称为反射。

4)代码示例(利用面向对象做的操作 、 使用反射完成调属性方法操作、使用反射完成调私有属性方法操作)

package com.zhou.java;

import org.junit.Test;

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

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 Exception {
//

        //1.创建类的实例
        //person.class就作为Class的实例出现
        Class<Person> clazz = Person.class;
        Person p1 = clazz.newInstance();//jdk9之后不建议用
                System.out.println(p1);


        //2.调属性、先获取当前类当中叫age名的属性。
        Field agefield = clazz.getField("age");
        agefield.set(p1, 10);
        System.out.println(agefield.get(p1));

        //3.调方法,先获取当前类当中叫show的方法。
        Method showmethod = clazz.getMethod("show");
        showmethod.invoke(p1);


    }


    //反射做其他事儿

    @Test
    public void test3() throws Exception {

        //1.调用私有的构造器,创建Person实例
        //   private(String name,int age){}

        Class clazz1 = Person.class;
        Constructor cons = clazz1.getDeclaredConstructor(String.class, int.class);//不用填写构造器名称,只需要告诉参数就行,需要传的是String参数和int参数,构造器有了,就需要造对象  
        cons.setAccessible(true);
        Person p1 = (Person) cons.newInstance("Tom", 20);
        System.out.println(p1);
        //2.调用私有的属性
        Field namefield = clazz1.getDeclaredField("name");
        namefield.setAccessible(true);
        namefield.set(p1, "Jerry");
        System.out.println(p1);


        //2.调用私有的方法
        //private String showNation(){}

        Method showNation = clazz1.getDeclaredMethod("showNation", String.class);
        showNation.setAccessible(true);
        String info = (String) showNation.invoke(p1, "CHN");
        System.out.println(info);


    }
}

5)通过使用反射前后的的例子的对比

①面向对象中创建对象,请用指定结构(属性、方法)等功能,可以不使用反射,也可以使用反射,请问有什么区别?

运行时类,运行的代码中,person类就会加载到内存中,放到内存中的类就称为运行时类。

不使用反射:我们需要考虑封装性,比如,出了Person类之后,就不能再调用Person类中的私有结构。使用反射:我们可以调用运行时类中任意的构造器、属性、方法。包括了私有的属性、方法、构造器。

②以前创建对象并调用方法的方式,与现在通过反射创建对象并调用方法的方式对比的话,哪种用的多?

从我们程序员来讲,我们开发中主要是完成义务代码。对于相关的对象,方法的调用都是确定,所以我们使用非反射的方式多一些。

因为反射体现了多态性(可以再运行时动态的获取对象所属的类,动态的调用相关的方法),所以我们在设计框架的时候,会大量的使用反射。

框架=注解+反射(获取相关注解)+设计模式

③单例模式的饿汉式和懒汉式,私有化的构造器,此时通过反射,可以创建单列模式的多个对象吗?

是的,单列模式的饿汉式和懒汉式,构造器都被私有。在类的内部造对象,外部直接用就可以。通过反射可以调构造器。

④.通过反射,可以调用类中私有结构,是否与面对对象的封装有冲突》是不是java语言设计存在bug?

不存在bug

封装性:体现的是否会建议我们调用内部api的问题,比如,private声明的结构,意味着不建议调用。

反射:体现的是我们能否调用的问题,因为类的完整结构都加载到了内存中,我们就有能力进行调用。

反射理解:是假设内存中有一个内存对象,通过这个对象,可以看成是哪个类创建的,通过类可以看到是在哪个包中声明的。

6)java反射机制提供的功能

在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.Class类的理解

在这里插入图片描述
在这里插入图片描述

1)如下以Java类的加载为例说明

编译:针对于编写好的.java源文件进行编译(使用Javac.exe),会生成一个或多个.class字节码文件。
接着,我们使用Java.exe命令对指定的.class字节码文件进行解释运行。这个解释运行的过程中,我们需要将.class字节码文件加载到(使用类的构造器)内存中(方法区),加载到内存的class文件对应的结构即为Class的一个实例

比如:加载到内存中的Person类或String类或User类,都作为Class的一个一个的实例
接口加载到内存中也是对应得一个Class实例

Class clazz1=Person.class;
Class clazz2=String.class;
Class clazz3=User.class;
Class clazz4=Compareable.class;

3.获取Class实例的几种方式(掌握前三种)

import com.zhou.java.Person;
import org.junit.Test;

public class ClassTest {

    //1.调用运行时类的静态属性
    @Test
    public void test1() throws Exception {
        Class clazz1 = Person.class;
        System.out.println(clazz1);

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

        System.out.println(clazz1 = clazz2);//true


        //3.调用Class的静态方法forName(String className)
        String className = "com.zhou.java.Person";//全类名
        Class clazz = Class.forName(className);


        //4.
        Class systemClassLoader = ClassLoader.getSystemClassLoader().loadClass("com.zhou.java.Person");


    }


}


4.class看作是反射源头

5.Class的实列都可以指向哪些结构呢?

class:外部类,成员(成员内部类,静态内部类)、局部内部类、匿名内部类
interface:接口
[]:数组
enum:枚举
annotation:注解
基本数据类型
void

在这里插入图片描述

6.类的加载过程(详细在jvm中有)

在这里插入图片描述

6.1过程1:loading(装载)

将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由加载器完成

6.2过程2linking(连接)

验证、准备、解析
验证(Verify):确保加载的类信息符合JVM规范,例如:以cafebabe开头,没有安全方面的问题。
准备prepare):正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。

解析(Resolve):虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
在这里插入图片描述

6.3过程3Initialization(初始化)

在这里插入图片描述

6.4关于类的加载器(了解,JDK8版本为例)

1)作用:负责类的加载,并对应一个Class的实例

虽叫类的加载器,不仅能加载类,还能加载接口、没接、注解等
负责将字节码文件放到内存中
在这里插入图片描述

2) 分类(分为两种)

在这里插入图片描述
似乎是继承关系,其实不是继承关系,而是层级关系
在这里插入图片描述
在这里插入图片描述

①BootStrapClassLoader:引导加载器、启动加载器

使用C、c++语言编写的,不能通过java代码获取实例
负载加载java的核心库。(Java_Home/jar/lib/rt.jar)
java代码获取实例,获取的时候返回为null

②继承于ClassLoader的类加载器

扩展类加载器(jdk提供的)
系统类加载器、应用程序类加载器(jdk提供的)自定义的类默认使用的类的加载器
用户自定义类的加载器(Tomcat中也定义了一些类加载器)

在这里插入图片描述
在这里插入图片描述

③代码演示
获取系统类加载器

在这里插入图片描述

获取扩展加载器(获取上一层加载器)

在这里插入图片描述

在这里插入图片描述

获取引导类加载器失败,获取不到。返回值为null

在这里插入图片描述

用户自定义的类是系统类加载加载的
方式一

在这里插入图片描述

方式二

在这里插入图片描述
在这里插入图片描述

3)以上的类的加载器是否存在继承关系

4)掌握使用类的加载器获取流,并读取配置文件信息。

方案一:

propertites处理属性文件
读取配置文件时:
使用单元测试方法,默认就是使用的是当前module下面
在这里插入图片描述
通过propertites读取流当中文件的数据
在这里插入图片描述

处理的key和值都是String类型
在这里插入图片描述
在这里插入图片描述

以后会实现数据和代码的分离
数据会放在具体的配置文件中

使用Classloader也可以做这样的事儿
拿到系统加载器
在这里插入图片描述
作为流拿到一个资源
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

方案二:

7.反射的应用

7.1反射的应用1:创建运行时类的对象

1)如何实现:通过Class的实例调用newInstance()方法即可
2)要想创建对象成功,需要满足
①条件1:要求运行是类必须满足一个空参的构造器。
②条件2:要求提供的空参构造器的权限要足够。

Person类实现了两个接口

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/235dae5963cd448a9876eaaff8a30cd7

在这里插入图片描述
.png)

创建Person对象此处的创建运行时类对象指的是Person类
在这里插入图片描述
当把Person类加载到内存中时
使用Java.exe指令时,走类的加载过程:loading,linking、initilion环节,在方法区就会有一个大的实例。就称为运行时类。

首先有一个大的Class实例,获取实例。
在这里插入图片描述

在这里插入图片描述

per调的是toString方法
在这里插入图片描述

若Person类里没有空参构造器,则抛异常在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

还有一种异常是有构造器但不能用私有权限
在这里插入图片描述

在这里插入图片描述
默认权限,同包别的类能用
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3)回忆:javabean中要求当前类:一个空参构造器,有什么用?
①场景1:子类对象在实例化时,子类的构造器的首行默认调用父类的空参的构造器默认有super()
②场景2:在反射中,经常用来创建运行时类的对象,那么我们要求各个运行时类都提供一个空参构造器,便于我们创建运行时类对象的代码。

在这里插入图片描述

Javabean的要求,当前类是公共的,提供当前类的空参构造器,有属性提供get、set方法、有toString方法、重写equals、hashcode方法,是为了防止将对象放在集合中、toString方法(打印对象变量时,打印地址、打印属性的值)

为啥要有这个提供空参构造器这个要求?

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.zhou.java;

public class Creature<T> {
    boolean gender;
    public int id;

    public void breath(){
        System.out.println("呼吸");

    }

    private void info(){

        System.out.println("我是一个生物");
    }
}
package com.zhou.java;

public interface myInterface {

    void method();

}
package com.zhou.java;

import org.junit.Test;

public class NewInstanceTest {
    @Test
    public void test() throws InstantiationException, IllegalAccessException {

        Class clazz = Person.class;
        //获取Person类的实例
        Person per = (Person) clazz.newInstance();
        System.out.println(per);//调的是toString()方法


    }


}
package com.zhou.java;

public class Person extends Creature<String> implements Comparable, myInterface {
    private String name;
    public int age = 1;

    private static String info;

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

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

    protected Person(String name) {
        this.name = name;
    }


    Person() {

        System.out.println("person()========");
    }


    public void show() {

        System.out.println("您好我是一个Person");
    }


    private String showNation(String nation, int age) {
        System.out.println("shownation");
        return "我的国籍是:" + nation + ",生活了" + age + "年";
    }

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


    public static void showInfo() {

        System.out.println("我是一个人");
    }

    @Override
    public void method() {

    }

    @Override
    public int compareTo(Object o) {
        return 0;
    }
}
4)在jdk标识为过时,替换成什么结构

通过Constructor类调用newInstance()

7.2反射的应用2:获取运行时类所有的结构

1)获取运行时类的内部结构1:所有属性、所有方法、所有构造器
2)获取运行时类的内部结构1:父类、接口们、包、贷泛型的父亲、父亲的泛型

在这里插入图片描述
在这里插入图片描述

package com.atguigu03.reflectapply.apply2;

import com.atguigu03.reflectapply.data.Person;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * @author shkstart
 * @create 14:28
 */
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);
        }

        //getDeclaredFields():获取当前运行时类中声明的所有属性
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            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
             * ...
             *
             * 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
             *
             * mod = 17          0x00000011
             * if ((mod & PUBLIC) != 0)  说明修饰符中有public
             * if ((mod & FINAL) != 0)   说明修饰符中有final
             */
            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.print(fName);
//
            System.out.println();
        }
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
得到的都是Person类声明的,父类的没有

在这里插入图片描述
在这里插入图片描述
获取每一个具体的信息
在这里插入图片描述
f.getModifiers()获取修饰符
在这里插入图片描述
类调里面的toString方法,可以看到权限修饰符
在这里插入图片描述
怎么做的?因为modifer这个数在Modifer这个类中有对应的十六进制对应关系
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

获取方法
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

都是当前类中有的
在这里插入图片描述

package apply2;

import com.zhou.java.Person;
import org.junit.Test;

import java.lang.reflect.Method;

public class MethodTest {
    @Test
    public void test1() {

        Class clazz = Person.class;
      /*  //getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
        Method[] methods = clazz.getMethods();
        for (Method m:methods) {
            System.out.println(m);

        }*/


        //getDeclareMethods():获取当前运行时类中声明的所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println(m);
        }

    }


}
package apply2;

import com.zhou.java.Person;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class FieldsTest {


    //权限修饰符、变量类型、变量名
    @Test
    public void test2() {

        Class clazz = Person.class;
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            //1.权限修饰符

            int modifier = f.getModifiers();
            System.out.print(modifier + ":" + Modifier.toString(modifier) + "\t");


            //2.数据类型
            Class type = f.getType();
            System.out.println(type.getName() + "\t");

            //3.变量名
            String sname = f.getName();
            System.out.println(sname);
            System.out.println();


        }


    }


    @Test
    public void test1() {

        Class clazz = Person.class;
        //getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
        /*Field[] fields = clazz.getFields();
        for (Field c:fields) {
            System.out.println(c);

        }*/


        //getDeclareFields():获取当前运行时类中声明的所有属性
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            System.out.println(f);
        }


    }
}

在这里插入图片描述
person里使用了注解
在这里插入图片描述
自定义注解,要想在反射中获取注解及注解的信息,需要求注解的生命周期长

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
首先有大的实例,指明全类名
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
person继承时带泛型
在这里插入图片描述
希望结果里带上泛型
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一个类可以实现多个接口,所以就是数组
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

什么时候用到,泛型写apply时
自定义泛型时,写dao时,dao通用的增删改查操作
操作的哪个表暂时不确定,回到Java层面哪个类不确定?

有可能需要当前类中继承的方法,有一些需要重写,有一些需要继承父类调用的方法,在这里需要获取这里这个类继承的父类的泛型
在这里插入图片描述
获取某一个对象,就不用传大的Class

获取Person类的实例,希望打印出String
先获取带泛型的父类
在这里插入图片描述

在这里插入图片描述
也有可能这个类,父类没有泛型,
也有可能有泛型,若有泛型就进行强转。

在这里插入图片描述
数组就是泛型参数构成的
在这里插入图片描述
角标0就是想要的String
在这里插入图片描述

在这里插入图片描述
不想要class,就获取class名字
调getname()调不了
是因为目前看到的是Type
在这里插入图片描述

Type是Class实现的接口
强转成Class
在这里插入图片描述
然后再进行Class.getName
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package apply2;

import org.junit.Test;

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

public class OtherTest {
    //获取运行时类的内部结构2:父类、接口们、包、带泛型的父类、父类的泛型等

    //5.获取运行时类的父类的泛型(难)
    @Test
    public void test5() throws ClassNotFoundException {
        Class clazz = Class.forName("com.zhou.java.Person");
        //获取带泛型的父类(Type是一个接口,Class实现了此接口)
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
        //如果父类是带泛型的,进行强转为ParameterizedType
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        //调用getActualTypeArguments()获取泛型的参数,结果是一个数组,因为可能有多个泛型参数。
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        //获取泛型参数的名称
        System.out.println(((Class) actualTypeArguments[0]).getName());


    }


    //4.获取运行时类所在的包
    @Test
    public void test4() throws ClassNotFoundException {

        Class clazz = Class.forName("com.zhou.java.Person");
        Package aPackage = clazz.getPackage();
        System.out.println(aPackage);


    }


    //3.获取运行时类实现的接口
    @Test
    public void test3() throws ClassNotFoundException {
        Class clazz = Class.forName("com.zhou.java.Person");

        Class[] interfaces = clazz.getInterfaces();
        for (Class i : interfaces) {
            System.out.println(i);

        }


    }


    //1.获取运行时类的父类
    @Test
    public void test1() throws ClassNotFoundException {
        Class clazz = Class.forName("com.zhou.java.Person");
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);


    }

    //2.获取运行时类的带泛型的父类
    @Test
    public void test2() throws ClassNotFoundException {

        Class clazz = Class.forName("com.zhou.java.Person");
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);


    }


}
package apply2;

import com.zhou.java.Person;
import org.junit.Test;

import java.lang.reflect.Method;

public class MethodTest {
    @Test
    public void test1() {

        Class clazz = Person.class;
      /*  //getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
        Method[] methods = clazz.getMethods();
        for (Method m:methods) {
            System.out.println(m);

        }*/


        //getDeclareMethods():获取当前运行时类中声明的所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println(m);
        }

    }


}
package apply2;

import com.zhou.java.Person;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class FieldsTest {


    //权限修饰符、变量类型、变量名
    @Test
    public void test2() {

        Class clazz = Person.class;
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            //1.权限修饰符

            int modifier = f.getModifiers();
            System.out.print(modifier + ":" + Modifier.toString(modifier) + "\t");


            //2.数据类型
            Class type = f.getType();
            System.out.println(type.getName() + "\t");

            //3.变量名
            String sname = f.getName();
            System.out.println(sname);
            System.out.println();


        }


    }


    @Test
    public void test1() {

        Class clazz = Person.class;
        //getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
        /*Field[] fields = clazz.getFields();
        for (Field c:fields) {
            System.out.println(c);

        }*/


        //getDeclareFields():获取当前运行时类中声明的所有属性
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            System.out.println(f);
        }


    }
}

7.3反射的应用3:调用指定的结构、指定的属性、方法、构造器

在这里插入图片描述

在这里插入图片描述
还是针对Person类

在这里插入图片描述
age非静态,获取它的值,跟对象打交道
创建当前类的对象
在这里插入图片描述
创建Person类的实例

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

获取当前类中名字叫age属性,File是java.lang包下的子类
在这里插入图片描述
在这里插入图片描述

这个属性是实例变量,得跟对象打交道
得说明是哪一个对象的值,是per对象的
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

因为此处是默认权限
在这里插入图片描述
改成public
在这里插入图片描述
在这里插入图片描述
设置属性的值
在这里插入图片描述

在这里插入图片描述

package apply3;

import com.zhou.java.Person;
import org.junit.Test;

import java.lang.reflect.Field;

public class ReflectTest {

    //反射的应用:调用指定的属性
    // public int age = 1;
    @Test
    public void test() throws Exception {
        Class clazz = Person.class;
        Person person = (Person) clazz.newInstance();


        //1.获取运行时类指定名的属性
        Field agefield = clazz.getField("age");

        System.out.println(agefield.get(person));
        //2.获取或设置属性的值
        agefield.set(person, 2);
        System.out.println(agefield.get(person));
    }

}

操作私有权限的属性
按age代码重先更改为name
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

package apply3;

import com.zhou.java.Person;
import org.junit.Test;

import java.lang.reflect.Field;

public class ReflectTest {

     //private String name;
    @Test
    public void test2() throws  Exception{
        Class clazz = Person.class;
        Person person = (Person)clazz.newInstance();
        //1.通过Class实例调用getDeclareField(String fieldName)获取运行时类指定的属性
        Field namefield = clazz.getDeclaredField("name");
        //2、确保此属性可以访问
        namefield.setAccessible(true);
        //3、通过Filed类的实例调用get(Object obj)获取
        // 或设置此属性的值set(Object obj,Object value)
        namefield.set(person,"Tom");

        System.out.println(namefield.get(person));

}
    }

在这里插入图片描述

调用静态属性
在这里插入图片描述

在这里插入图片描述
infoField.get()里参数不写不行,因为他不是可变参数。写null是没问题的。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
怎么理解此处null?获取属性时就是用Class获取的,clazz就是Person.class
在这里插入图片描述
若是实例变量,就必须要传对象
在这里插入图片描述

在这里插入图片描述

public class ReflectTest {
    
    //调用静态属性
   // private static String info;

    @Test
    public void test3() throws  Exception{
        Class clazz = Person.class;
        Field infofield = clazz.getDeclaredField("info");
        infofield.setAccessible(true);
       /* infofield.set(Person.class,"我是一个人");
        System.out.println(infofield.get(Person.class));
*/

       infofield.set(null,"我是一个人");
        System.out.println(infofield.get(null));
    }

}

在这里插入图片描述

这里是引用

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
这里为啥不能写Integer
在这里插入图片描述
因为不同类型的值才可以自动装箱,此处是类型
int class和Integer class 显然是不同的实例
这叫自动装箱
在这里插入图片描述
在这里插入图片描述
正常情况下,非静态方法用对象去调,传实参
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
发现方法有返回值,返回值怎么体现呢?
~~删除在这里插入图片描述

invoke方法的返回值就是shownation的返回值
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest {

    //反射应用3-2:调用指定的方法
    // private String showNation(String nation, int age){}
    @Test
    public void test4() throws Exception{

        Class clazz = Person.class;
        Person person =(Person) clazz.newInstance();
        //1.通过Class的实列调用getDeclareMethod(String methodName,Claass...args)获取指定的方法
        Method showNation = clazz.getDeclaredMethod("showNation", String.class, int.class);
       //2.setAccessible(true);确保此方法是可以调用的
        showNation.setAccessible(true);
        //3.通过Method实例调用invoke(Onject obj,objs)即为对Method对应的方法调用
        //invoke()返回值即为Method对应的返回值
        //特别的,如果Method对应的返回值类型为void,则invoke()返回值为bull
        Object invoke = showNation.invoke(person, "CHN", 10);
        System.out.println(invoke);


    }

在这里插入图片描述
涉及静态方法
在这里插入图片描述

在这里插入图片描述

package apply3;

import com.zhou.java.Person;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest {
    //调用静态方法
   // public static void showInfo() {}
    @Test
    public void test5() throws  Exception{
        Class clazz = Person.class;
        Method declaredMethod = clazz.getDeclaredMethod("showInfo");
        declaredMethod.setAccessible(true);
        Object invoke = declaredMethod.invoke(null);
        System.out.println(invoke);

}
    }

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package apply3;

import com.zhou.java.Person;
import org.junit.Test;

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

public class ReflectTest {
    //调用指定构造器
    @Test
    public void test6() throws Exception{

        Class clazz= Person.class;
        Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
        constructor.setAccessible(true);
        Person per = (Person)constructor.newInstance("Tom", 12);
        System.out.println(per);

    }
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
框架大量使用注解
框架使用反射去读注解,根据注解属性值做相应处理
熟悉常用注解,知道注解怎么赋值
参照SupperssWarming,他怎么写,我们就怎么写,
在这里插入图片描述

Table修饰类、接口类型
在这里插入图片描述

在这里插入图片描述
注解能让我们获取就的是Runnntime在这里插入图片描述
在类的声明处就可以使用
此处为什么报错
没有进行赋值
在这里插入图片描述
在这里插入图片描述
此处可以进行默认赋值
在这里插入图片描述

此处就不再报错

反射复习
1.反射的概述(熟悉)
Java给我们提供了一套API
在这里插入图片描述
运行时动态获取指定对象所属类(通过对象调getClass)

在这里插入图片描述
API
在这里插入图片描述
在这里插入图片描述

2.Class的源头

3.类的加载过程、类的加载器(理解)

4.反射的应用1:创建运行时类的对象
5.反射的应用2:获取运行时类所有的结构
6.反射的应用3:调用指定的结构:属性、方法、构造器
7.反射的应用4:注解的使用
8.体会反射的动态性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/691654.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据库分库分表mycat

为啥要分库分表 IO瓶颈&#xff1a;热点数据太多&#xff0c;数据库缓存不足&#xff0c;产生大量磁盘IO&#xff0c;效率较低。 请求数据太多&#xff0c;带宽不够&#xff0c;网络IO瓶颈。 CPU瓶颈&#xff1a;排序、分组、连接查询、聚合统计等SQL会耗费大量的CPU资源&#…

pre-commit 慢

执行这个命令 pre-commit run --all-files 有时候会卡在Initializing environment for https://github.com/xxx那里&#xff0c;如下图&#xff1a; 这个情况可以这样复现&#xff1a; git clone gitgithub.com:TheKevJames/coveralls-python cd coveralls-python python3.1…

c# 学习 2

常量 转义字符 类型转换

关于python中的关键字参数

在python语言中存在两种传参方式&#xff1a; 第一种是按照先后顺序来传参&#xff0c;这种传参风格&#xff0c;称为“位置参数”这是各个编程语言中最普遍的方式。 关键字传参~按照形参的名字来进行传参&#xff01; 如上图所示&#xff0c;在函数中使用关键字传参的最大作…

微服务开发与实战Day03

一、导入黑马商城项目 资料文档&#xff1a;Docs 1. 安装MySQL ①删除root目录下的mysql rm -rf mysql/ ②把课前资料里的mysql目录上传到root目录下 ③创建一个通用网络 docker network create hm-net ④使用下面的命令安装MySQL docker run -d \--name mysql \-p 330…

SpringCloud整合OpenFeign实现微服务间的通信

1. 前言 1.1 为什么要使用OpenFeign&#xff1f; 虽说RestTemplate 对HTTP封装后, 已经⽐直接使⽤HTTPClient简单⽅便很多, 但是还存在⼀些问题. 需要拼接URL, 灵活性⾼, 但是封装臃肿, URL复杂时, 容易出错. 代码可读性差, ⻛格不统⼀。 1.2 介绍一下微服务之间的通信方式 微…

高能来袭|联想拯救者携手《黑神话:悟空》玩转东方神话世界

从2020年首次发布实机演示视频以来&#xff0c;《黑神话&#xff1a;悟空》便在全球范围内获得了广泛关注&#xff0c;成为国产3A游戏的现象级爆款。6月&#xff0c;联想拯救者正式宣布成为《黑神话&#xff1a;悟空》全球官方合作伙伴&#xff0c;致力于共同革新国产游戏体验&…

独立游戏之路 -- TapTap广告收益损失和常见问题

一个操作带来的TapTap广告收益损失 一,收益损失1.1 广告入口1.2 损失对比二,常见问题2.1 有展现量没有预估收益 /eCPM 波动大?2.2 新建正式媒体找不到预约游戏2.3 聚合模式由于没有回传 oaid 无数据2.4 每日观看次数限制是否有限制一,收益损失 1.1 广告入口 TapTap广告联…

三端植物大战僵尸杂交版来了

Hi&#xff0c;好久不见&#xff0c;最近植物大战僵尸杂交版蛮火的 那今天苏音整理给大家三端的植物大战僵尸杂交版包括【苹果端、电脑端、安卓端】 想要下载的直接划到最下方即可下载。 植物大战僵尸&#xff0c;作为一款古老的单机游戏&#xff0c;近期随着B站一位UP主潜艇…

并查集进阶版

过关代码如下 #define _CRT_SECURE_NO_WARNINGS #include<bits/stdc.h> #include<unordered_set> using namespace std;int n, m; vector<int> edg[400005]; int a[400005], be[400005]; // a的作用就是存放要摧毁 int k; int fa[400005]; int daan[400005]…

k8s学习--kubernetes服务自动伸缩之水平收缩(pod副本收缩)HPA详细解释与案例应用

文章目录 前言HPA简介简单理解详细解释HPA 的工作原理监控系统负载模式HPA 的优势使用 HPA 的注意事项应用类型 应用环境1.metircs-server部署2.HPA演示示例&#xff08;1&#xff09;部署一个服务&#xff08;2&#xff09;创建HPA对象&#xff08;3&#xff09;执行压测 前言…

PXE、无人值守实验

PXE部署 [roottest2 ~]# systemctl stop firewalld [roottest2 ~]# setenforce 0一、部署tftp服务 [roottest2 ~]# yum -y install tftp-server.x86_64 xinetd.x86_64 [roottest2 ~]# systemctl start tftp [roottest2 ~]# systemctl enable tftp [roottest2 ~]# systemctl …

【Vue】练习-mutations的减法功能

文章目录 一、需求二、完整代码 一、需求 步骤 二、完整代码 Son1.vue <template><div class"box"><h2>Son1 子组件</h2>从vuex中获取的值: <label>{{ $store.state.count }}</label><br><button click"handleA…

【病理数据】svs格式数据解读

Openslide 病理图像通常以.svs格式存储在数据库中。要想使用python处理svs格式的图像&#xff0c;我们通常使用Openslide模块。 关于Openslide模块的安装详见这个博客&#xff1a; 【解决Error】ModuleNotFoundError: No module named ‘openslide‘ 病理图像数据结构 病理图…

(杂交版)植物大战僵尸

1.为什么我老是闪退&#xff1f; 答&#xff1a;主页控制台把“后台运行”点开&#xff0c;尽量避免全屏就会好很多。 2.哪里下载&#xff1f; 答&#xff1a;夸克https://pan.quark.cn/s/973efb326f81 3.为啥我没有14个卡槽&#xff1f; 答&#xff1a;冒险没打&#xff0c;怪…

Bio-Info 每日一题:Rosalind-04-Rabbits and Recurrence Relations

&#x1f389; 进入生物信息学的世界&#xff0c;与Rosalind一起探索吧&#xff01;&#x1f9ec; Rosalind是一个在线平台&#xff0c;专为学习和实践生物信息学而设计。该平台提供了一系列循序渐进的编程挑战&#xff0c;帮助用户从基础到高级掌握生物信息学知识。无论你是初…

xm文件怎么转换成mp3文件,亲测有效!附工具下载

朋友们&#xff0c;你们有没有遇到过喜马拉雅的.xm文件转成MP3格式的麻烦&#xff1f;别急&#xff0c;我这儿有个好消息告诉你&#xff0c;有个免费的转换工具&#xff0c;简单几步就能搞定&#xff0c;还能批量处理呢&#xff01; 咱们先聊聊这个数字音频的小困扰。喜马拉雅…

278 基于Matlab GUI的中重频PD雷达仿真系统

基于Matlab GUI的中重频PD雷达仿真系统。具有26页文档报告。仿真雷达信号的发射、传播、散射、接收、滤波、信号处理、数据处理的全部物理过程&#xff0c;因此应当实现对雷达发射机、天线、接收机、回波信号处理、数据处理的建模与仿真。程序已调通&#xff0c;可直接运行。 2…

企业差旅费管理如何实现真正的降本增效

看企业发展&#xff0c;不能只看当下&#xff0c;尤其对于看重长期价值的企业家来说&#xff0c;必须要用更长远的目光去看行业的未来。开源节流&#xff0c;扔掉一些没用的包袱减少负担&#xff0c;然后轻装上阵&#xff0c;并寻找企业发展的新增长点&#xff0c;仍然是众多企…

【QT5】<应用> 小游戏:贪吃蛇

文章目录 一、项目要求 二、需求分析 三、实现效果 四、代码 一、项目要求 【1】主要实现&#xff1a;游戏界面存在一条蛇&#x1f40d;&#xff0c;使用键盘wsad或者↑↓←→键盘可以控制蛇的行走方向。同时界面中会随机出现食物&#xff0c;蛇可以吃食物&#xff0c;然后…