Class Loading
The java classes
- Core classes
- Extension classes
Core classes exists in jre/lib/rt.jar while ext classes exists in jre/lib/ext/
the location of ext can be set by java -cp classes -Djava.ext.dirs=c:\lib
java一般使用两个path:classpath 和 java.library.path 1. classpath是指向jar包的位置 2. java.library.path是非java类包的位置如(dll,so)
LINUX下的系统变量LD_LIBRARY_PATH来添加java.library.path 或者 在vm arguments里添加-Djava.library.path= /usr/local/lib
Delegation modal
set classpath on command line
java -cp classes;lib\helper.jar com.sean.Main
java is going to find com.sean.Main class under classes directory, beside the classpath you provided, java will also find class from
$JAVA_HOME/lib/rt.jar
which contains core java classes$JAVA_HOME/lib/ext/*.jar
which contains extension class
假设我自定义了一个String类,并且也放在java.lang package下,当使用java来执行这个方法的时候,会发生什么情况?
java仍然会找到rt.jar中的String class,因为java使用委托模型,先由BootstrapClassLoader加载,然后再由ExtensionClassLoader, 最后由ApplicationClassloader加载,由于已经在BootstrapClassLoader中加载了String class, 所以我自己定义的String class不会被加载
classLoaders
the sequence of classloader is
Bootstrap class loader
-> Extension class loader
-> Application class loader
package com.sean;
import java.net.URL;
import java.net.URLClassLoader;
public class Delegation {
public static void main(String[] argss) {
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
do {
System.out.println(classLoader);
for (URL url : classLoader.getURLs()) {
System.out.printf("\t %s\n", url.getPath());
}
} while((classLoader = (URLClassLoader) classLoader.getParent()) != null);
System.out.println("Bootstrap classloader");
}
}
implement Our Own Class Loader
package com.sean;
public class SqlServerClassLoader extends ClassLoader {
private ClassLoader parent;
private String connectionString;
public SqlServerClassLoader(String connectionString) {
this(ClassLoader.getSystemClassLoader(), connectionString);
}
public SqlServerClassLoader(ClassLoader parent, String connectionString) {
super(parent);
this.parent = parent;
this.connectionString = connectionString;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class cls = null;
try {
// load the class by parent classLoader
cls = parent.loadClass(name);
} catch(ClassNotFoundException e) {
// if not found, try load the class by this classLoader
byte[] bytes = new bytes[0];
try {
bytes = loadClassFromDatabase(name);
} catch(SqlException sqle) {
throw new ClassNotFoundException();
}
return defineClass(name, bytes, 0, bytes.length);
}
return cls;
}
private byte[] loadClassFromDatabase(String name) throws SQLException {
PreparedStatement pstmt = null;
Connection connection = null;
try {
connection = DriverManager.getConnection(connectionString);
String sql = "select class from CLASSES where ClassName = ?";
pstmt = connection.prepareStatement(sql);
pstmt.setString(1, name);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
Blob blob = rs.getBlob(1);
byte[] data = blob.getBytes(1, (int) blob.length());
return data;
}
} catch(Exception e) {
} finally {
if(pstmt != null) {
try {
pstmt.close();
} catch(e) {
}
}
if (connection != null) {
try {
connection.close();
} catch(e) {
}
}
}
return null;
}
}
Class.forName
ClassLoadedr ucl = new URLClassLoader();
Class clazz = Class.forName("com.sean.Hello", true, ucl);
Class.forName is used to load class by name, and it can also provide a class loader to load the class
if two same class loaded by two classloader, they are now same
...
URLClassLoader ucl1 = new URLClassLoader(...);
URLClassLoader ucl2 = new URLClassLoader(...);
Class clazz1 = Class.forName("com.sean.Hello", true, ucl1);
Class clazz2 = Class.forName("com.sean.Hello", true, ucl2);
IHello h1 = (IHello)clazz1.newInstance();
IHello h2 = (IHello)clazz2.newInstance();
clazz1 != clazz2
h1.getClass() != h2.getClass()
difference between Class.forName and ClassLoader.loadClass
- they both return Class from classLoader
- use Class.forName to load class will
- initialize the class all ** static initializer** will be run
- use ClassLoader.getSystemClassLoader().loadClass(“SomeClass”)
- use the system class loader
- not initialize the class
Reflection
- difference between Class.getMethods and Class.getDeclaredMethods
- getMethods returns all the methods defined on the class inclucing the method from parent class
- getDeclaredMethods only return the methods defined on the Class, including private methods
- load constructor
Constructor[] ctors = cls.getDeclaredConstructors(); for(Constructor ctor : ctors) { ctor.getParameterTypes(); System.out.println(ctor.getName()); }
- execute the code
method.invoke(objectToBeInvoked, parameters);
blog comments powered by Disqus