• Java中的类和类加载机制


    主要介绍以下几方面内容(理解 Class 类、理解 Java 的类加载机制、学会使用 ClassLoader 进行类加载)

    1.理解Class类

    每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。

      Class 对象只能由系统建立对象

         一个类在 JVM 中只会有一个Class实例

        每个类的实例都会记得自己是由哪个 Class 实例所生成

        1: Class是什么?

          Class是一个类:(/小写class表示是一个类类型,大写Class表示这个类的名称)
    public class ReflectionTest {
        @Test
        public void testClass() {
           Class clazz = null;
        }
    }
    //Class的定义
    public final
        class Class<T> implements java.io.Serializable,
                                  java.lang.reflect.GenericDeclaration,
                                  java.lang.reflect.Type,
                                  java.lang.reflect.AnnotatedElement {....}

    2:Class这个类封装了什么信息?

      Class是一个类,封装了当前对象所对应的类的信息
      1、 一个类中有属性,方法,构造器等,比如说有一个Person类,一个Order类,一个Book类,这些都是不同的类,现在需要一个类,用来描述类,这就是Class,它应该有类名,属性,方法,构造器等。Class是用来描述类的类

      2、Class类是一个对象照镜子的结果,对象可以看到自己有哪些属性,方法,构造器,实现了哪些接口等等

          3.对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
        4.Class 对象只能由系统建立对象,一个类(而不是一个对象)在 JVM 中只会有一个Class实例

    package reflect;
    
    public class Person {
        String name;
        private int 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 Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
        public Person() {
            super();
            
        }
        
        
    }
    定义了一个Person类型

    通过Class类获取类对象

    public class ReflectionTest {
        @Test
        public void testClass() {
           Class clazz = null;
           
           //1.得到Class对象
           clazz = Person.class;
           
           System.out.println();  //插入断点
        }
    }

    在断点处就可以看到Class对像包含的信息

     同样,这些属性值是可以获取的

    public class ReflectionTest {
        @Test
        public void testClass() {
           Class clazz = null;
           
           //1.得到Class对象
           clazz = Person.class;
           //2.返回字段的数组
           Field[] fields = clazz.getDeclaredFields();
           
           System.out.println();  //插入断点
        }
    }

    查看fields的内容

     对象为什么需要照镜子呢?

        1. 有可能这个对象是别人传过来的

        2. 有可能没有对象,只有一个全类名 

      通过反射,可以得到这个类里面的信息

    获取Class对象的三种方式

      1.通过类名获取      类名.class    

      2.通过对象获取      对象名.getClass()

      3.通过全类名获取    Class.forName(全类名)

    public class ReflectionTest {
      @Test
      public  void testClass() throws ClassNotFoundException{
          Class clazz=null;
          //1、通过类名获取对象    类名.class
          clazz=Person.class;
          Field[] filed=clazz.getDeclaredFields();
          Field[] fields=clazz.getFields();
          System.out.println(Arrays.deepToString(filed));
          System.out.println(Arrays.deepToString(fields));
          //2、通过对象名
          //这种方式是用在传进来一个对象,却不知道对象的类型时候用
          Person person=new Person();
          clazz=person.getClass();
          Object obj=new Person();
          clazz=obj.getClass();
          //3、通过全类名(会抛出异常)
          String  classname="reflect.Person";
          clazz=Class.forName(classname);
          
          //字符串的例子
          clazz=String.class;
          clazz="javaTest".getClass();
          clazz=Class.forName("java.lang.String");
          System.out.println();
          
      }

    Class类的常用方法

    方法名

    功能说明

    static Class forName(String name)

    返回指定类名 name 的 Class 对象

    Object newInstance()

    调用缺省构造函数,返回该Class对象的一个实例

    Object newInstance(Object []args)

    调用当前格式构造函数,返回该Class对象的一个实例

    getName()

    返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称

    Class getSuperClass()

    返回当前Class对象的父类的Class对象

    Class [] getInterfaces()

    获取当前Class对象的接口

    ClassLoader getClassLoader()

    返回该类的类加载器

    Class getSuperclass()

    返回表示此Class所表示的实体的超类的Class

     Class类的newInstance()方法

    @Test
      public void testNewInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
          //1、获取Class对象
          String className="reflect.Person";
          Class clazz=Class.forName(className);
          //利用class对象的newInstance方法创建一个类的实例
          Object obj=clazz.newInstance();
          System.out.println(obj);
      }

         可以看出确实是创建了一个Person实例
      但是Person类有两个构造方法,到底是调用的哪一个构造方法呢

      实际调用的是类的无参数的构造器。所以在我们在定义一个类的时候,定义一个有参数的构造器,作用是对属性进行初始化,还要写一个无参数的构造器,作用就是反射时候用。

      一般地、一个类若声明一个带参的构造器,同时要声明一个无参数的构造器

    2.ClassLoader

    类装载器是用来把类(class)装载进 JVM 的。JVM 规范定义了两种类型的类装载器:启动类装载器(bootstrap)和用户自定义装载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构 ,如下图所示

     @Test
      public void testClassLoader() throws ClassNotFoundException{
          //1、获取一个系统的类加载器(可以获取,当前这个类ReflecTest就是它加载的)
        ClassLoader classLoader=ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);
         //2、获取系统加载器的父类加载器(扩展器加载器,可以获取)
        classLoader=classLoader.getParent();
        System.out.println(classLoader);
        //3、获取扩展类加载器的父类加载器(引导加载器,不可以获取)
        classLoader=classLoader.getParent();
        System.out.println(classLoader);
        //4、测试当前类用哪个类加载器进行加载(系统类加载器)
        classLoader=Class.forName("reflect.ReflectionTest").getClassLoader();
        System.out.println(classLoader);
       //5、测试JDK提供的Object类由哪个类加载器负责加载(引导类)
        classLoader=Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);
    }

    使用类加载器获取当前类目录下的文件

     首先,系统类加载器可以加载当前项目src目录下面的所有类,如果文件也放在src下面,也可以用类加载器来加载

    调用 getResourceAsStream 获取类路径下的文件对应的输入流.

     @Test
      public void testClassLoader() throws ClassNotFoundException{
         /* //1、获取一个系统的类加载器(可以获取,当前这个类ReflecTest就是它加载的)
        ClassLoader classLoader=ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);
         //2、获取系统加载器的父类加载器(扩展器加载器,可以获取)
        classLoader=classLoader.getParent();
        System.out.println(classLoader);
        //3、获取扩展类加载器的父类加载器(引导加载器,不可以获取)
        classLoader=classLoader.getParent();
        System.out.println(classLoader);
        //4、测试当前类用哪个类加载器进行加载(系统类加载器)
        classLoader=Class.forName("reflect.ReflectionTest").getClassLoader();
        System.out.println(classLoader);
       //5、测试JDK提供的Object类由哪个类加载器负责加载(引导类)
        classLoader=Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);*/
        
       //src目录下直接加载
        InputStream in1=null;
        in1=this.getClass().getResourceAsStream("text1.txt");
        //放在内部文件夹,要写全路径
        InputStream in2=this.getClass().getResourceAsStream("reflect/text2.txt");
        }

    参考:https://www.cnblogs.com/zhaozw/p/10857841.html

  • 相关阅读:
    python day04 列表增删改查
    python day03 字符串操作
    python day02 格式化输出逻辑运算
    面试题
    python基础练习题(一)
    编译安装PostgreSQL
    Python函数初识二
    Python函数初识
    笨办法学Python
    笨办法学Python
  • 原文地址:https://www.cnblogs.com/zouhong/p/12103548.html
Copyright © 2020-2023  润新知