1. Initialisation du chargement de classe
-
Chargement
Charger un fichier de classe en mémoire
-
Mise en relation
-
Vérification
Vérifiez que le caractère du fichier de classe ne répond pas à la norme de fichier de classe
-
Préparation
Attribuez des valeurs par défaut aux variables statiques static int count = 10;
Dans cette étape, nombre = 0 valeur par défaut
-
Résolution
Les références de symboles sont converties en adresses mémoire accessibles directement
-
-
Initialisation
Affectation de variable statique à la valeur initiale
2. Chargeur de classe
1. JVM est chargé dynamiquement à la demande et adopte un mécanisme de délégation parent
Utilisez getClassLoader pour obtenir le chargeur de classe. S'il est Null, il s'agit du chargeur de classe BootStrap car il est implémenté en C ++ et il n'y a pas de classe correspondante.
Les classes que nous écrivons habituellement sont sous le chemin de classe, elles sont donc chargées par le chargeur de classe App
Remarque: ces quatre chargeurs de classe n'ont pas de relation d'héritage mais une relation séquentielle
Le chargeur parent n'est pas la classe parente, il dit simplement qu'il ne peut pas être chargé par lui-même, donc il est transféré au niveau supérieur pour être chargé
Il ne s'agit pas d'une relation d'héritage, comment sont-ils entrés en contact? Utilisez une combinaison ~~
2. Le diagramme de l'étape 1 n'illustre-t-il pas la tâche des parents? Je vais vous donner une image pour vous faire comprendre la mission des parents
Non, pourquoi devrais-je utiliser des images? Permettez-moi de décrire en une phrase: classLoader trouve dans son propre cache si la classe XX a été chargée, sinon, trouve son chargeur de classe parent, et le chargeur de classe parent trouve dans son propre cache s'il a déjà été chargé Classe XX, s'il est trouvé , retourne, s'il n'est pas trouvé, puis trouve le chargeur de classe parent, jusqu'à BootStrap, s'il n'est pas trouvé dans le cache, puis regarde en arrière depuis le chargeur de classe parent, le chargeur parent demande à votre fils de voir de quoi vous êtes responsable Y a-t-il une telle classe dans le package jar? Si tel est le cas, vous pouvez la charger dans la mémoire. Sinon, vous pouvez consulter le chargeur de classe de votre fils. Vérifiez-le tout le temps et voir si le plus petit chargeur de classe est renvoyé à la fin , ou Si vous ne le trouvez pas, lancez une exception. ClassNotFoundException
J'ai quand même succombé à l'image ci-dessus.
/**
* @author 木子的昼夜
*/
public class MyClassLoaderTest {
public static void main(String[] args) throws ClassNotFoundException {
MyClassLoaderTest.class.getClassLoader().loadClass("classtest.MyClassLoaderTest");
}
}
// ClassLoader#loadClass
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 肯定是要上锁的 不然加载冲了咋个办呢?
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
// 首先,判断这个类是否已经加载到当前层级内存了
Class<?> c = findLoadedClass(name);
// 如果当前层级内存没有
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
// 如果还有父级 那就在上一层的缓存里找
c = parent.loadClass(name, false);
} else {
// 如果没有了 那就是最后一层了 在自己的管辖范围 找
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
// 上级一直没有找到 那就只能找自己负责的范围了
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
// 如果还是没有 那就往下一级 接着在负责范围找
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
Modèle de conception: méthode de modèle de fonction de crochet
3. Comment se passe-t-il lorsqu'un fichier de classe est chargé en mémoire?
4. GetClassLoader () qui veut savoir quel chargeur de classe est chargé en mémoire par une certaine classe
System.out.println(String.class.getClassLoader());
// null --> BootStrap类加载器
System.out.println(sun.awt.HKSCS.class.getClassLoader());
// null --> BootStrap类加载器
System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
// sun.misc.Launcher$ExtClassLoader@1d44bcfa --> Ext
System.out.println(ClassLoaderTest.class.getClassLoader());
// sun.misc.Launcher$AppClassLoader@18b4aac2--> App
5. Pourquoi les parents délèguent-ils
-
Par sécurité, s'il n'y a pas de délégation parente, recherchez la classe directement à partir du chargeur de classe personnalisé (le problème principal)
(1) Si je personnalise un java.lang.String ici,
j'écris un script de minage dans la classe String
(2) Ensuite, Xiaoyueyue a téléchargé ma bibliothèque pour l'utiliser!
Il a utilisé String, il pensait que c'était une classe jdk, mais j'ai prédit sa prédiction. Cette classe String est déjà la mienne et contrôlée par moi
(3) La délégation parentale peut éviter ce problème, car le système ira toujours à la couche supérieure pour voir s'il y a cette classe parce que la couche supérieure l'a, donc il n'utilisera pas la classe String que j'ai définie.
- Si le calque parent est chargé, je n’ai pas à le charger, puis le chargement est un gaspillage de ressources (problème secondaire)
6. Maintenant que vous l'avez personnalisé, n'est-ce pas simplement ce que j'ai dit?
Non! Le chargeur de classe est déjà restreint
7. L'exemple de relation parent-enfant du chargeur de classe n'est pas un héritage mais une composition
En regardant le code ci-dessous, les lecteurs peuvent réessayer et essayer soigneusement cette phrase: Le chargeur de classe qui charge le chargeur de classe n'est pas le chargeur de classe parent du chargeur de classe
System.out.println(ParentDemo.class.getClassLoader());
System.out.println(ParentDemo.class.getClassLoader().getClass().getClassLoader());
System.out.println(ParentDemo.class.getClassLoader().getParent());
System.out.println(ParentDemo.class.getClassLoader().getParent().getParent());
输出结果:
sun.misc.Launcher$AppClassLoader@18b4aac2
null
sun.misc.Launcher$ExtClassLoader@6e0be858
null
8. La portée de chaque chargeur de classe
Vous pouvez consulter le code source de sun.misc.Launcher
- BootstrapClassLoader: sun.boot.class.path
- ExtensionClassLoader: java.ext.dirs
- AppClassLoader: java.class.path
public static void main(String[] args) {
System.out.println("---------BOOT-----------------------");
String boot = System.getProperty("sun.boot.class.path");
Arrays.stream(boot.split(";")).forEach(s-> System.out.println(s));
System.out.println("--------------Ext-------------------");
String ext = System.getProperty("java.ext.dirs");
Arrays.stream(ext.split(";")).forEach(s-> System.out.println(s));
System.out.println("----------APP-----------------------");
String app = System.getProperty("java.class.path");
Arrays.stream(app.split(";")).forEach(s-> System.out.println(s));
}
输出结果:
---------BOOT-----------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\sunrsasign.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_144\jre\classes
--------------Ext-------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext
C:\WINDOWS\Sun\Java\lib\ext
----------APP-----------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\deploy.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\access-bridge-64.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\cldrdata.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\dnsns.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jaccess.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jfxrt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\localedata.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\nashorn.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunec.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\zipfs.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\javaws.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfxswt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\management-agent.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\plugin.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar
E:\workspace_idea\blogmaven\target\classes
// 读者注意看这一个 这个是当前项目class文件地址
9. Chargeur de classe personnalisé
-
Définissez d'abord une classe java chargée Test.java
public class Test { public void say(){ System.out.println("成功喽!"); } }
-
Compilez Test.java dans le répertoire spécifié
javac -encoding utf-8 -d E:/classes Test.java
-
Hériter de ClassLoader, remplacer la méthode de modèle findClass, appeler defineClass
/** * @author 木子的昼夜 */ public class MyClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { FileInputStream inputStream = null; ByteArrayOutputStream out = null; try { // 类名 aa.xx 转换为 aa/xx.class File file = new File("E:\\classes\\",name.replaceAll("\\.","/").concat(".class")); // 获取输入流 inputStream = new FileInputStream(file); // 输出字节流 out = new ByteArrayOutputStream(); // 转换为字节数组 int available = inputStream.available(); byte[] byteArr = new byte[available]; inputStream.read(byteArr); // 生成class return defineClass(name,byteArr,0,byteArr.length); }catch (Exception e) { throw new ClassNotFoundException(); }finally { // 关闭流 if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
test
public static void main(String[] args) { try { Class<?> clazz = new MyClassLoader().loadClass("Test"); // 获取声明的方法 Method say = clazz.getDeclaredMethod("say"); // 创建实例 Object instance = clazz.newInstance(); // 调用方法 say.invoke(instance); }catch (Exception e) { e.printStackTrace(); } } 输出结果: 成功喽!
-
Le chargeur de classe personnalisé charge les classes auto-chiffrées
- Le fichier est le vôtre, vous pouvez le crypter par un algorithme une fois la compilation terminée,
et lorsque vous le chargez avec un ClassLoader personnalisé, vous pouvez le décrypter vous-même - Peut empêcher la décompilation
- Peut empêcher la falsification
- Le fichier est le vôtre, vous pouvez le crypter par un algorithme une fois la compilation terminée,
10. Compilation hybride
-
Interprète: interprète bytecode
-
JIT: Just In - Time compilateur
1. -Xmixed 默认为混合模式 开始使用解释执行 启动速度快 对热点代码进行实时检测和编译 2. -Xint 使用解释模式 启动快 执行慢 3. -Xcomp 使用纯编译模式 启动慢 运行快
-
Mode mixte
-
Interprète + compilation de code à chaud
-
Interprète
-
La détection de code à chaud détecte l'utilisation de la compilation de code à chaud
1. 多次被调用的方法(方法计数器:监测方法执行频率) 2. 多次被调用的循环(循环计数器:监测循环执行频率)
-
À suivre...
Il y a beaucoup de photos dans cet article. Si vous n'êtes pas sûr, vous pouvez faire attention au compte public: Muzi's Day and Night
Envoyez "Class Load" pour obtenir l'adresse d'accès de l'image HD
Envoyez "route" pour obtenir le plan de cette série d'articles
Vous pouvez également m'envoyer les questions que vous souhaitez poser, je vous répondrai dès que je le verrai
Enfin, j'ai joint mon compte public et j'ai juste commencé à rédiger un souhait et à progresser ensemble:
Remarque : Le texte ci-dessus ne représente que des opinions personnelles et est pour référence uniquement. Si vous avez des questions, veuillez le signaler et sortir immédiatement du lit et apporter des corrections.