zoukankan      html  css  js  c++  java
  • Java反射

    什么是反射?

           正常方法是通过一个类创建对象,反射方法就是通过一个对象找到一个类的信息。

           根据类的信息来加载这个类,然后构造这个对象,然后再调用这个类中的属性和方法。(这句话是那个老师说的)

           我个人理解就是,反射就是让你可以随便调用你没有实例化的东西,因为类在实例化之后就固定了,而反射就打破了这种固定模式,即使你的类没有被实例化加载到内存中,你一样可以在你要使用的时候找到它。

           张孝祥说:“反射就是把Java类中的各种成分映射成相应的java类”,其细节方面就是你通过自己编写代码来将类加载到java虚拟机中,也有人称“反射”为“类的自解析”。

           通过反射可以让程序变得更加灵活。

    1.Class对象 VS. 实例对象

    有个系统类叫Class,是所有自定义类的原型,JAVA程序运行时,每个自定义类本身也是Class类的实例化对象

    在Java中我们一般是这样使用类的:编写类,然后new对象,再调用方法。这里new出来的对象暂且称之为实例对象(instance)。其实在这之前还涉及到一个Class对象。这个Class对象就是用来创建类的所有实例对象的。

    每个类都有一个Class对象Class对象是由JVM帮我们自动生成的。每当编写并且编译了一个新类,就会产生一个Class对象(更恰当地说,是被保存在一个同名的.class文件中)。为了生成这个类的实例对象,运行这个程序的的Java虚拟机会使用被称为“类加载器”的子系统。所有类都是在对其第一次使用时,动态加载到JVM中的。类加载器会首先检查这个类的Class对象是否已经加载。若尚未加载,默认的类加载器就会根据类名查找.class文件。一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有实例对象

    所有的Class对象都是java.lang.Class<T>类的实例对象

    2.为了使用一个类而做的准备工作

    1.加载:这是由类加载器执行的。该步骤将查找字节码,并从这些字节码中创建一个Class对象

    2.链接:在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。

    3.初始化:如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。

    初始化被延迟到了对静态方法(构造器隐式地是静态的)首次引用或者对非常数静态域进行首次引用时才执行。

    3.三种方法获得一个类的Class对象的引用

    (1)通过java.lang.Class类的静态方法forName()

    (2)调用实例对象的getClass()方法

    (3)类字面常量方式(比如MyClass.class)

    复制代码
    package com.example;
    
    class MyClass{}
    
    public class ClassTest {
    
    
        public static void main(String[] args) {
            
            System.out.println("第一种方式...");
            Class c1 = null;
            try {
                c1 = Class.forName("com.example.MyClass");    //注意,参数是包名+类型
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            System.out.println(c1.getName());    //输出:com.example.MyClass
            System.out.println(c1.getCanonicalName());    //输出:com.example.MyClass
            System.out.println(c1.getSimpleName());    //输出:MyClass
                    
            
            System.out.println("第二种方式...");
            Object instance = new MyClass();
            Class c2 = instance.getClass();
            System.out.println(c2.getName());    //输出:com.example.MyClass
            
            
            System.out.println("第三种方式...");
            Class c3 = MyClass.class;
            System.out.println(c3.getName());    //输出:com.example.MyClass
        }
    
    }
    复制代码

    4.泛化的Class引用

    (1)Class引用总是指向某个Class对象。在声明Class引用的时候最好指定泛型。如果不能确定具体的类型,Class<?>也是优于平凡的Class的,即便它们是等价的。

    (2)为了创建一个Class引用,并且它被限定为某种类型,或者该类型的任何子类型,可以将通配符与extends关键字结合,创建一个范围。如下:

    Class<? extends Number> bound = int.class;

    注意:虽然Integer继承自Number,但是Integer类的Class对象和Number类的Class对象并没有半毛钱的继承关系。(也就是说Integer类的Class对象并不是Number类的Class对象的子类)

    (3)还可以声明某个Class引用,它被限定为某种类型,并且是该类型的超类,可以这样:

    复制代码
    package com.example;
    
    class BaseClass{}
    
    class ChildClass extends BaseClass{}
    
    public class ClassTest {
    
        public static void main(String[] args) {
            
            Class<ChildClass> childClass = ChildClass.class;
            Class<? super ChildClass> superClazz = childClass.getSuperclass();
            System.out.println(superClazz.getName());    //输出:com.example.BaseClass
        }
    
    }
  • 相关阅读:
    MCU 51-7 I2C Communication EEPROM
    FinalShell(免费的XShell替代品)
    Docker部署Redis
    Docker-Compose部署ELK
    Linux清空文件
    Linux防火墙的操作
    VSCode远程连接Linux服务器
    Apollo分布式配置中心
    SpringBoot整合log4j2
    MySQL区分大小写
  • 原文地址:https://www.cnblogs.com/thiaoqueen/p/6654577.html
Copyright © 2011-2022 走看看