Java Class类与反射机制学习笔记

类的加载

当一个程序使用某一个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三个步骤来实现对这个类的初始化。

  • 加载
    就是指将该类的 .class文件读入内存中,并为之创建一个Class对象( java.lang.class对象 )。这个Class对象就是用来表示 .class文件内容的东西。(.class文件内容一般包括成员变量、构造方法、成员方法),任何类被使用时,系统都会建立一个Class对象。 
  • 连接
    验证 是否有正确的内部结构,并和其他类协调一致
    准备 负责为类的静态成员分配内存,并设置默认初始值(静态是随着类的加载而加载的,静态内部类只有在被调用时,才会被加载
    public class Test {  
        static {  
            System.out.println("外部类的输出。");  
        }  
          
        //静态内部类  
        static class StaticInner {  
            static {  
                System.out.println("内部类的输出。");  
            }  
              
            static void staticInnerMethod() {  
                System.out.println("内部静态方法的输出。");  
            }  
        }  
              
        public static void main(String[] args) {  
            Test outer = new Test();     //这里内部类不会被加载
             System.out.println("------------------分割线------------------");  
            Test.StaticInner.staticInnerMethod();      //调用内部类的静态方法  
        }  
    }  
    运行结果:
  • 解析 将类的二进制数据中的符号引用替换为直接引用
    (关于验证、准备、解析更加详细过程见JAVA虚拟机(JVM)——类加载的过程(加载、验证、准备、解析、初始化))
  • 初始化
    类的初始化阶段,虚拟机负责对类进行初始化,主要就是对类变量进行初始化(包括静态属性、静态初始化块)。类初始化之前,先要进行父类初始化, 因为子类可能会用到父类的东西)。在Java类中对类变量指定初始值有两种方式: 
    方式一:声明类变量时指定初始值;
    方式二:使用静态初始化块为类变量指定初始值。在一个类中,如果希望先执行类的初始化动作,可以使用static定义一个静态区域。当这个类被使用时,首先执行static块中的程序,并且只会执行一次。
class Example_A{
	public static int a = 1;//声明变量时指定初始值
	public static int b;//默认值
	public static String str1 = "Hello";//声明变量时指定初始值
	public static String str2;//默认值
	
	public Example_A(){
		a = 9;
		System.out.println("\n构造函数中\n a的值:" + a);
		System.out.println("b的值:" + b);
		System.out.println("str1的值:" + str1);
		System.out.println("str2的值:" + str2);
	}
	
	static{//静态域
		System.out.println("执行静态域中的内容:");
		System.out.println("静态域中未改变前, a的值"+ a);
		a = 5;
		System.out.println("静态域中改变后, a的值"+a);
	}
}
public class Test {
	public static void main(String[] args){
		Example_A e1 = new Example_A();
		System.out.println("---------------分割线---------------");
		Example_A e2 = new Example_A();
	}
}

运行结果:srh fbcx 

运行结果

分析:从运行结果我们可以看出,Example_A对象的初始化,首先执行的是static域中的内容,并且这个域只被执行一次。

类的加载时机

  1. 创建类的实例
  2. 访问类的静态变量,或者为静态变量赋值
  3. 调用类的静态方法
  4. 使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象
  5. 直接使用java .exe(*)命令来运行某个主类

类的加载器

负责将 .class文件加载到内存中,并为之生成对应的Class对象。JVM在运行时会产生3个类加载器组成的初始化加载器层次结构

组成:
Bootstrap ClassLoader 根类加载器(引导类加载器)C++编写的(因为需要频繁的加载到内存,速度要够快,所以使用C/C++写的),负责Java核心类的加载,比如JDK中JRE的lib目录下rt.jar文件System,String等。该加载器无法直接获取。

Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录。

System ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。

可以通过类加载器中的getResourceAsStream方法来加载资源文件。 
getResourceAsStream(String str):获取类路径下的指定文件的输入流

 Java反射

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制, 在java.lang.reflect包中提供了对该功能的支持。要想解剖一个类,必须先要获取到该类的字节码文件对象而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

反射

四种获取Class对象的方式

  1. 通过运行时的对象获取
    ObjectName obj = new ObjectName();
    Class c = obj
    .getClass();
  2. 通过本身的.class属性获取
    Class c = ObjectName.class; //任意数据类型都具备一个
    class静态属性
  3. 将类名作为字符串传递给Class类中的静态方法forName即可,可通过配置文件配置加载,扩展性强
    Class c =
    Class.forName("ObjectPath");
  4. 通过类加载器加载
    ClassLoader classLoader = ClassName.class.getClassLoader();
    Class c = classLoader.loadClass("ObjectPath");

 创建运行时Class实例对象
 条件:
 1)类必须有一个无参数的构造器, 否则需要指定对应的参数。
 2)类的构造器的访问需要足够权限。

Class<T> c = ... ; //获取一个Class实例对象
T e = c.newInstance(); //创建Class实例对象运行时对应的类T的对象

获取指定的属性 
1. Class<T> c = ... ; //获取一个Class实例对象
2. T e = c.newInstance(); //创建Class实例对象运行时对应的类T的对象

=========获取public权限的属性=========
3. Field f1 = c.getField("属性名称"); //获取public权限的属性
4. f1.set(e, value); //修改属性值

=========获取private权限的属性=========
5. Field f2 = c.getDeclaredField("属性名称");
6. f2.setAccessible(true);
7. f2.set(e, value);

 获取指定的方法
Method m1 =c.getMethod("方法名称", Class<?>... parameterTypes);//获取指定方法
m1.invoke(e, Object... args); //通过invoke方法来调用
=========获取静态方法=========
​​​​​​​Method m1 =c.getMethod("方法名称", Class<?>... parameterTypes);//获取指定方法
m1.invoke(ClassName.class);//调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值