Java类加载

1.Java类加载指的是将class文件读入内存,并为之创建一个java.lang.Class的对象。

2.java初始化类或接口的时机:

   1) 创建类实例,通过new或反射或反序列化创建类实例

   2) 调用类的静态方法

   3) 访问类或接口的静态属性,或为静态属性赋值

   4) 使用反射强制创建某个类或接口对应的java.lang.Class对象。

   5) 初始化某个类的子类,初始化子类时,子类的父类都会被初始化

   6) 直接使用java命令运行某个主类,会先初始化该主类

3.对于一个final修饰的静态属性,如果在编译时就得到属性值,则该属性可当成编译时常量。当程序使用编译时常量时,不会导致该所属类的初始化。

   

class MyTest{
       {
            System.out.println("静态初始化块");
       }
      //编译时常量
      static final String compileConst="const var";
}

public class TestCompileConst{
      public static void main(String[] args){
           //MyTest.compileConst编译时会被替换为"const var",所以不会使得MyTest类被初始化
            System.out.println(MyTest.compileConst);
      }  
}
4.使用ClassLoader类的loadClass()方法只是加载类,不会执行初始化。使用Class的静态方法forName()才会导致强制初始化类

5.JVM启动时,会形成由三个类加载器组成的初始化类加载层次结构:

    Bootstrap ClassLoader:根类加载器

    Extension ClassLoader:扩展类加载器

    System ClassLoader:系统类加载器


    BootStrap ClassLoader负责加载java的核心类。由JVM自身实现,不是java.lang.ClassLoader的子类

    Extension ClassLoader负责加载JRE的扩展目录JAVA_HOME/jre/lib/ext或java.ext.dirs系统属性指定的目录中的jar                                          包

    System ClassLoader负责JVM启动时,加载来自命令java中的-classpath选项或java.class.path系统属性,或

                                      CLASSPATH环境变量指定的JAR包和类路径

6.类加载器的机制

   全盘负责:一个类加载器加载某个Class的时候,该Class所依赖的和引用的其他Class也将由该加载器载入,除非显

                     示使用另外一个类加载器来载入

   父类委托:即先让父类加载器试图加载Class,只有父类无法加载该类时才从自己的类路径中加载该类

   缓存机制:程序要使用某个Class时,类加载器先从缓存中搜寻该Class,只有缓存中不存在该Class,系统才会重新

                     读取该类对应的二进制数据,并转为Class对象,并存入缓存。

7.类加载器之间的父子关系并不是类继承上的父子关系,而是类加载器实例之间的关系


8.类加载器加载Class的大致步骤:

   1)检查该Class是否被载入过即是否存在缓存中,有则进入第8步,否则执行第2步

   2)如果父加载器不存在(父加载器不存在,要么parent为根加载器,要么自己是根加载器),则执行第4步,否则

      执行第3步

   3)请求父加载器载入目标类,成功进入第8步,不成功执行第5步

   4)请求使用根加载器载入目标类,成功进入第8步,不成功执行第7步

   5)寻找Class文件,找到执行第6步,找不到执行第7步

   6)从文件中载入Class,成功进入第8步

   7)抛出ClassNotFoundException

   8)返回Class

9.一个自定义的类加载器

public class CompileClassLoader extends ClassLoader
{
	private byte[] geBytes(String filename) throws IOException
	{
		File file = new File(filename);
		long len = file.length();
		byte[] raw = new byte[(int)len];
		FileInputStream fin = new FileInputStream(file);
		int r = fin.read(raw);
		
		if(r!=len)
			throw new IOException("无法读取全部文件:"+r+"!="+len);
		
		fin.close();
		
		return raw;
	}
	
	//定义编译指定Java文件的方法
	private boolean compile(String javaFile) throws IOException
	{
		System.out.println("CompileClassLoader:正在编译"+javaFile+"...");
		Process p= Runtime.getRuntime().exec("javac "+javaFile);
		
		try
		{
			p.waitFor();
		}
		catch(InterruptedException ie)
		{
			System.out.println(ie);
		}
		int ret=p.exitValue();
		return ret==0;
	}
	
	protected Class<?> findClass(String name) throws ClassNotFoundException
	{
		Class clazz=null;
		String fileStub=name.replace(".","/");
		String javaFilename=fileStub+".java";
		String classFilename=fileStub+".class";
		File javaFile=new File(javaFilename);
		File classFile=new File(classFilename);
		
		if(javaFile.exists() && (!classFile.exists() || javaFile.lastModified()>classFile.lastModified()))
		{
			try
			{
				if(!compile(javaFilename) || !classFile.exists())
				{
					throw new ClassNotFoundException("ClassNotFoundException:"+javaFilename);
				}
			}
			catch(IOException ex)
			{
				ex.printStackTrace();
			}
		}
		
		if(classFile.exists())
		{
			try
			{
				byte[] raw=geBytes(classFilename);
				clazz=defineClass(name,raw,0,raw.length);
			}
			catch(IOException ie)
			{
				ie.printStackTrace();
			}
		}
		
		if(clazz==null)
		{
			throw new ClassNotFoundException(name);
		}
		
		return clazz;
	}
	
	public static void main(String[] args) throws Exception
	{
		if(args.length<1)
		{
			System.out.println("缺少运行的目标类,请按如下格式运行Java源文件:");
			System.out.println("java CompileClassLoader ClassName");
		}
		
		String progClass=args[0];
		String[] proArgs=new String[args.length-1];
		System.arraycopy(args,1,proArgs,0,proArgs.length);
		CompileClassLoader ccl=new CompileClassLoader();
		Class<?> clazz=ccl.loadClass(progClass);
		Method main=clazz.getMethod("main",(new String[0]).getClass());
		Object[] argsArray={proArgs};
		main.invoke(null,argsArray);
	}
}

public class Hello
{
	public static void main(String[] args)
	{
		for(String arg:args)
		{
			System.out.println("运行Hello的参数:"+arg);
		}
	}
}

java CompileClassLoader Hello MyCompileClassLoader
10.自定义加载类可以实现的常见功能:

    1)执行代码前自动验证数字签名

    2)根据用户提供的密码解密代码,从而实现代码混淆器来避免反编译class文件

    3)根据用户需求来动态加载类

    4)根据应用需求把其他数据以字节码的形式加载到应用中

11.Java的ClassLoader提供了一个URLClassLoader实现类,该类也是系统类加载器和扩展类加载器的父类。其可以从本地系统获取二进制文件来加载类,也可以从远程主机获取二进制文件来加载类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值