ThreadLocal (Kopie der Thread-Variablen)
Synchronized implementiert die Speicherfreigabe und ThreadLocal verwaltet eine lokale Variable für jeden Thread.
Verwenden Sie Platz für die Datenisolation zwischen Threads und stellen Sie eine Kopie für jeden Thread bereit, der die Variable verwendet. Jeder Thread kann seine eigene Kopie unabhängig ändern, ohne dass es zu Konflikten mit den Kopien anderer Threads kommt.
Die ThreadLocal-Klasse verwaltet eine Map, um eine Kopie der Variablen jedes Threads zu speichern. Der Schlüssel des Elements in der Map ist das Thread-Objekt und der Wert ist die Variablenkopie des entsprechenden Threads.
ThreadLocal spielt in Spring eine große Rolle und erscheint in Modulen wie Bean-Management, Transaktionsmanagement, Aufgabenplanung und AOP im Anforderungsbereich.
Die meisten Beans in Spring können als Singleton-Bereich deklariert und mit ThreadLocal gekapselt werden, sodass Stateful Beans normal in Multithreads auf Singleton-Art arbeiten können.
Die Java Virtual Machine-Spezifikation unterteilt Java-Laufzeitdaten in sechs Typen.
1. Programmzähler: Es handelt sich um eine Datenstruktur, die zum Speichern der Speicheradresse des aktuell ausgeführten Programms verwendet wird. Das Multithreading der Java Virtual Machine wird durch abwechselndes Wechseln der Threads und Zuweisen von Prozessorzeit erreicht. Um nach dem Thread-Wechsel zur richtigen Position zurückzukehren, benötigt jeder Thread einen unabhängigen Programmzähler, der sich nicht gegenseitig beeinflusst. Thread privat".
2. Java Virtual Machine Stack: Thread privat, derselbe wie der Thread-Lebenszyklus, der zum Speichern lokaler Variablentabellen, Operationsstapel und Methodenrückgabewerte verwendet wird. Die lokale Variablentabelle enthält grundlegende Datentypen und Objektreferenzen.
3. Lokaler Methodenstapel: Er ist dem Stapel der virtuellen Maschine sehr ähnlich, bedient jedoch die von der virtuellen Maschine verwendeten nativen Methoden.
4.Java-Heap: Ein von allen Threads gemeinsam genutzter Speicherbereich, in dem fast alle Objektinstanzen Speicher zuweisen.
5. Methodenbereich: Ein von jedem Thread gemeinsam genutzter Bereich, in dem von der virtuellen Maschine geladene Klasseninformationen, Konstanten, statische Variablen und kompilierter Code gespeichert werden.
6. Laufzeitkonstantenpool: Stellt die Konstantentabelle in jeder Klassendatei zur Laufzeit dar. Enthält verschiedene Arten von Konstanten: numerische Konstanten zur Kompilierungszeit, Methoden- oder Feldverweise.
„Können Sie darüber sprechen, wann, was und was Java GC getan hat?“
Wann:
1 Die neue Generation hat einen Eden-Bereich und zwei. Bringen Sie das Objekt zuerst in den Eden Wenn nicht genügend Platz vorhanden ist, platzieren Sie es in einem der Überlebensbereiche. Wenn es immer noch nicht passt, wird ein kleinerer GC ausgelöst, der in der neuen Generation auftritt und die überlebenden Objekte in einen anderen Überlebensbereich legt die Erinnerung an Eden und das bisherige Überlebensgebiet. Wenn während eines bestimmten GC-Prozesses Objekte gefunden werden, die nicht abgelegt werden können, werden diese Objekte in den Speicher der alten Generation gestellt.
2. Große Gegenstände und langfristig überlebende Gegenstände gelangen direkt in den Seniorenbereich.
3. Jedes Mal, wenn eine kleinere GC ausgeführt wird, sollten die Objekte, die in die alte Generation verschoben werden sollen, analysiert werden. Wenn die Größe dieser alten Objekte die verbleibende Größe des alten Bereichs überschreitet, Führen Sie dann eine vollständige GC durch, um im Seniorenbereich so viel Platz wie möglich zu erhalten.
Über was: Es kann nicht von GC Roots aus durchsucht werden und es gibt immer noch kein wiederbelebtes Objekt nach einer Markierungsbereinigung.
Was zu tun ist: Junge Generation: Kopierbereinigung; Alte Generation: Mark-Sweep- und Mark-Komprimierungsalgorithmen; Permanente Generation: Speichert Klassen in Java und den Klassenlader selbst, der Klassen lädt.
Was sind die GC-Wurzeln: 1. Objekte, auf die im Stapel der virtuellen Maschine verwiesen wird. 2. Objekte, auf die durch statische Eigenschaften im Methodenbereich verwiesen wird, Objekte, auf die durch Konstanten verwiesen wird. 3. JNI-Referenzen (im Allgemeinen native Methoden) im lokalen Methodenstapelobjekt .
Synchronized und Lock sind beide wiedereintrittsfähige Sperren. Wenn derselbe Thread den Synchronisationscode erneut eingibt, kann er die erworbene Sperre verwenden.
Synchronized ist ein pessimistischer Sperrmechanismus und eine exklusive Sperre. Locks.ReentrantLock sperrt nicht jedes Mal, geht jedoch davon aus, dass kein Konflikt vorliegt, und schließt einen Vorgang ab. Wenn er aufgrund eines Konflikts fehlschlägt, wird der Vorgang wiederholt, bis er erfolgreich ist. Anwendbare Szenarien für ReentrantLock
Ein Thread muss unterbrochen werden, während er auf die Kontrolle einer Sperre wartet
Einige Wartebenachrichtigungen müssen separat verarbeitet werden , kann die Bedingungsanwendung in ReentrantLock steuern, welcher Thread benachrichtigt werden soll, und die Sperre kann an mehrere Bedingungen gebunden werden.
verfügt über eine Fair-Lock-Funktion, jeder eingehende Thread wird in die Warteschlange gestellt, um zu warten.
StringBuffer ist threadsicher. Jedes Mal, wenn ein String manipuliert wird, generiert StringBuffer ein neues Objekt. StringBuffer ist jedoch nicht threadsicher >fail-fast: Mechanismus ist ein Fehlermechanismus in der Java-Sammlung (Collection). Wenn mehrere Threads den Inhalt derselben Sammlung bearbeiten, kann ein Fail-Fast-Ereignis auftreten.
Zum Beispiel: Wenn ein Thread A eine Sammlung durch einen Iterator durchläuft und der Inhalt der Sammlung von anderen Threads geändert wird, wird beim Zugriff von Thread A auf die Sammlung eine ConcurrentModificationException-Ausnahme ausgelöst, die zu einem Fail-Fast-Ereignis führtpassiert vor: Wenn zwischen zwei Vorgängen eine Vorher-Vorher-Beziehung besteht, ist das Ergebnis des vorherigen Vorgangs für den späteren Vorgang sichtbar.
1. Programmsequenzregeln: Jede Operation in einem Thread findet vor jeder nachfolgenden Operation im Thread statt.
2. Regeln für die Monitorsperre: Das Entsperren einer Monitorsperre erfolgt vor der anschließenden Sperrung der Monitorsperre.
3. Regeln für flüchtige Variablen: Das Schreiben in ein flüchtiges Feld erfolgt vor jedem weiteren Lesen dieses flüchtigen Felds.
4. Transitivität: Wenn A passiert – vor B und B passiert – vor C, dann passiert A – vor C.
5. Thread-Startregeln: Die start()-Methode des Thread-Objekts erfolgt vor jeder Aktion dieses Threads.
Vier Unterschiede zwischen Volatile und Synchronized:
1 Unterschiedliche Granularität, ersteres zielt auf Variablen ab, letzteres sperrt Objekte und Klassen
2 Syn-Blöcke, flüchtige Threads blockieren nicht
3 Syn garantiert drei Hauptmerkmale: Volatilität garantiert keine Atomizität
4 Syn-Compiler-Optimierung, Volatilität optimiert nicht. Volatilität hat zwei Eigenschaften:
1 Garantiert die Sichtbarkeit dieser Variablen für alle Threads, bezieht sich auf die Änderung durch ein Thread Wenn der Wert dieser Variablen geändert wird, ist der neue Wert für andere Threads sichtbar, aber er ist nicht multithreadsicher.
2. Deaktivieren Sie die Optimierung der Neuordnung von Anweisungen.
Wie Volatile die Speichersichtbarkeit gewährleistet:
1. Beim Schreiben einer flüchtigen Variablen aktualisiert JMM die gemeinsam genutzte Variable im lokalen Speicher, die dem Thread im Hauptspeicher entspricht .
2. Beim Lesen einer flüchtigen Variablen macht JMM den dem Thread entsprechenden lokalen Speicher ungültig. Als nächstes liest der Thread die gemeinsam genutzte Variable aus dem Hauptspeicher.
Synchronisation: Der Abschluss einer Aufgabe hängt von einer anderen Aufgabe ab. Die abhängige Aufgabe kann erst abgeschlossen werden, nachdem auf den Abschluss der abhängigen Aufgabe gewartet wurde.
Asynchron: Es besteht keine Notwendigkeit, auf den Abschluss der abhängigen Aufgabe zu warten, sondern die abhängige Aufgabe nur darüber zu informieren, welche Arbeiten abgeschlossen werden müssen. Solange die Aufgabe abgeschlossen ist, wird die abhängige Aufgabe benachrichtigt zurück, ob es abgeschlossen ist. (Das Merkmal von Asynchronität ist die Benachrichtigung). Anrufe und SMS sind Metaphern für synchrone und asynchrone Vorgänge.
Blockierung: Die CPU stoppt und wartet auf den Abschluss eines langsamen Vorgangs, bevor sie andere Arbeiten abschließt.
Nicht blockierend: Nicht blockierend bedeutet, dass die CPU während der langsamen Ausführung andere Arbeiten ausführt. Nachdem die langsame Ausführung abgeschlossen ist, führt die CPU nachfolgende Vorgänge aus.
Nicht-Blockierung führt zu einem Anstieg der Thread-Umschaltung. Es muss berücksichtigt werden, ob eine erhöhte CPU-Nutzungszeit die Umstellungskosten des Systems ausgleichen kann.
Sperrfreier CAS-Algorithmus (Compare And Swap): CAS ist eine optimistische Sperrtechnologie. Wenn mehrere Threads versuchen, CAS zu verwenden, um dieselbe Variable gleichzeitig zu aktualisieren, kann dies nur einer der Threads Aktualisieren Sie den Wert der Variablen. Wenn andere Threads fehlschlagen, wird der fehlgeschlagene Thread nicht angehalten, sondern darüber informiert, dass der Wettbewerb fehlgeschlagen ist, und kann es erneut versuchen. CAS hat 3 Operanden, den Speicherwert V, den alten erwarteten Wert A und den neuen zu ändernden Wert B. Nur wenn der erwartete Wert A und der Speicherwert V gleich sind, ändern Sie den Speicherwert V in B, andernfalls unternehmen Sie nichts.
Die Rolle des Thread-Pools: Wenn das Programm startet, werden mehrere Threads erstellt, um auf die Verarbeitung zu reagieren. Sie werden Thread-Pools genannt, und die Threads darin werden Arbeits-Threads genannt
Erstens: Reduzieren Ressourcenverbrauch. Reduzieren Sie die Kosten für die Erstellung und Zerstörung von Threads, indem Sie erstellte Threads wiederverwenden.
Zweitens: Reaktionsgeschwindigkeit verbessern. Wenn eine Aufgabe eintrifft, kann die Aufgabe sofort ausgeführt werden, ohne auf die Erstellung des Threads warten zu müssen.
Drittens: Verbessern Sie die Thread-Verwaltbarkeit.
Häufig verwendete Thread-Pools: ExecutorService ist die Hauptimplementierungsklasse. Zu den häufig verwendeten gehören Executors.newSingleThreadPool(), newFixedThreadPool(), newcachedTheadPool(), newScheduledThreadPool().
Arbeitsmechanismus des Klassenladers:
1. Laden: Java-Binärcode in JVM importieren und Klassendatei generieren.
2. Verbindung: a) Überprüfung: Überprüfen Sie die Richtigkeit der geladenen Klassendateidaten b) Vorbereitung: Zuweisen von Speicherplatz zu statischen Variablen der Klasse c) Parsen: Konvertieren von Symbolreferenzen in direkte Referenzen
3: Initialisierung: Führen Sie Initialisierungsarbeiten für statische Variablen, statische Methoden und statische Codeblöcke der Klasse durch.
Übergeordnetes Delegationsmodell: Wenn der Klassenlader eine Klassenladeanforderung empfängt, delegiert er die Anforderung zunächst an den übergeordneten Klassenlader, um den benutzerdefinierten Lader abzuschließen – >Anwendungslader – >Erweiterungsklassenlader – >Klasse starten Lader.
Konsistentes Hashing:
Memcahed-Cache:
Datenstruktur: Schlüssel, Wertepaar
Verwendungsmethoden: get, put und andere Methoden
Redis Datenstruktur: String – String (Schlüsselwerttyp)
Hash – Wörterbuch (Hashmap) Mit der Hash-Struktur von Redis können Sie nur einen bestimmten Attributwert ändern, genau wie das Aktualisieren eines Attributs in der Datenbank
Liste – Liste implementiert die Nachrichtenwarteschlange
Satz – Satz nutzt Einzigartigkeit
Sortierter Satz – Geordneter Satz kann sortiert und Datenpersistenz erreicht werden
Eingehende Analyse des automatischen Boxings und Unboxings von Java
Sprechen Sie über Java Reflexionsmechanismus
Wie schreibe ich eine unveränderliche Klasse?
Index: B+, B-, Volltextindex
Der MySQL-Index ist eine Datenstruktur, die es der Datenbank ermöglichen soll, Daten effizient zu finden.
Die häufig verwendete Datenstruktur ist B+Tree. Jeder Blattknoten speichert nicht nur die relevanten Informationen des Indexschlüssels, sondern fügt auch Zeiger auf benachbarte Blattknoten hinzu. Dies bildet einen B+Tree mit sequentiellen Zugriffszeigern Diese Optimierung soll die Leistung verschiedener Bereichszugriffe verbessern.
Wann werden Indizes verwendet:
Felder, die häufig nach den Schlüsselwörtern „Gruppieren nach“, „Sortieren nach“ und „Unterscheiden“ angezeigt werden
erscheinen häufig zusammen mit anderen Felder Zu verbindende Tabellen sollten auf den Verbindungsfeldern indiziert werden
Felder, die häufig in der Where-Klausel erscheinen
erscheinen oft als Abfrage der ausgewählten Felder Feld
Spring IOC (Inversion of Control, Dependency Injection)
Spring unterstützt drei Abhängigkeitsinjektionsmethoden, nämlich Attributinjektion (Setter-Methode), Konstruktorinjektion und Schnittstelleninjektion.
In Spring werden die Objekte, aus denen die Anwendung besteht und vom Spring IOC-Container verwaltet werden, Beans genannt.
Der IOC-Container von Spring instanziiert Beans und stellt über den Reflexionsmechanismus Abhängigkeiten zwischen Beans her.
Einfach ausgedrückt ist Bean ein Objekt, das vom Spring IOC-Container initialisiert, zusammengestellt und verwaltet wird.
Der Prozess zum Abrufen des Bean-Objekts besteht darin, zuerst die Konfigurationsdatei über Resource zu laden und den IOC-Container zu starten, dann das Bean-Objekt über die getBean-Methode abzurufen und dann seine Methode aufzurufen.
Spring Bean-Bereich:
Singleton: Es gibt nur eine gemeinsam genutzte Bean-Instanz im Spring IOC-Container, bei der es sich im Allgemeinen um einen Singleton-Bereich handelt.
Prototyp: Jede Anfrage generiert eine neue Bean-Instanz.
Anfrage: Jede http-Anfrage generiert eine neue Bean-Instanz.
Die gemeinsamen Vorteile von Proxys: Business-Klassen müssen sich nur auf die Geschäftslogik selbst konzentrieren, um die Wiederverwendbarkeit von Business-Klassen sicherzustellen.
Statischer Java-Proxy:
Das Proxy-Objekt und das Zielobjekt implementieren dieselbe Schnittstelle. Das Zielobjekt ist ein Attribut des Proxy-Objekts. In der spezifischen Schnittstellenimplementierung kann das Proxy-Objekt davor und danach andere Geschäftsverarbeitungen hinzufügen Aufruf der entsprechenden Methode des Zielobjekts.
Nachteil: Eine Proxy-Klasse kann nur eine Business-Klasse vertreten. Wenn die Business-Klasse Methoden hinzufügt, muss die entsprechende Proxy-Klasse auch Methoden hinzufügen.
Dynamischer Java-Proxy:
Der dynamische Java-Proxy soll eine Klasse schreiben, um die InvocationHandler-Schnittstelle zu implementieren und die Invoke-Methode zu überschreiben. In der Invoke-Methode kann nur dann eine erweiterte Verarbeitungslogik geschrieben werden, wenn diese öffentliche Proxy-Klasse ausgeführt wird Es ist klar, was es will. Das Proxy-Objekt kann auch die Methoden der Proxy-Klasse implementieren und dann bei der Implementierung der Klassenmethoden Erweiterungen durchführen.
Eigentlich: Methoden von Proxy-Objekten = erweiterte Verarbeitung + Methoden von Proxy-Objekten
Der Unterschied zwischen JDK und CGLIB, die dynamische Proxy-Klassen generieren:
Dynamische JDK-Proxys können nur für Klassen generiert werden, die Schnittstellen-Proxy implementieren (eine Klasse instanziieren). Zu diesem Zeitpunkt implementieren das Proxy-Objekt und das Zielobjekt dieselbe Schnittstelle, und das Zielobjekt wird als Attribut des Proxy-Objekts verwendet. In der spezifischen Schnittstellenimplementierung kann vor und nach dem Aufruf der entsprechenden Methode eine andere Geschäftsverarbeitungslogik hinzugefügt werden des Zielobjekts
CGLIB implementiert einen Proxy für Klassen, hauptsächlich um eine Unterklasse der angegebenen Klasse zu generieren (ohne eine Klasse zu instanziieren) und die darin enthaltenen Methoden zu überschreiben.
Spring AOP-Anwendungsszenarien
Leistungstests, Zugriffskontrolle, Protokollverwaltung, Transaktionen usw.
Die Standardstrategie besteht darin, die dynamische JDK-Proxy-Technologie zu verwenden, wenn die Zielklasse die Schnittstelle implementiert. Wenn das Zielobjekt die Schnittstelle nicht implementiert, wird standardmäßig der CGLIB-Proxy verwendet
SpringMVC-Funktionsprinzip
Client-Anfragen werden an DispatcherServlet übermittelt
Der DispatcherServlet-Controller fragt HandlerMapping ab, findet es und verteilt es an den angegebenen Controller.
Nachdem der Controller die Geschäftslogikverarbeitung aufgerufen hat, gibt er ModelAndView zurück
DispatcherServlet fragt einen oder mehrere ViewResoler-Ansichtsparser ab und findet die von ModelAndView angegebene Ansicht
Die Ansicht ist für die Anzeige der Ergebnisse für den Client verantwortlich
Eine HTTP-Anfrage
DNS-Domänennamenauflösung–> Drei-Wege-Handshake –> ; Initiieren Sie eine http-Anfrage nach dem Herstellen einer TCP-Verbindung –> Der Server antwortet auf die http-Anfrage und der Browser ruft den HTML-Code ab und fordert die Ressourcen im HTML an Code (wie Javascript, CSS, Bilder usw.) –> Durchsuchen Der Server rendert die Seite und präsentiert sie dem Benutzer
Entwerfen Sie ein Speichersystem zum Speichern großer Datenmengen: Entwerfen Sie eine logische Ebene namens „ mittlere Schicht". In dieser Schicht werden die massiven Daten aus der Datenbank erfasst und in einem Cache gespeichert. Sie laufen im Speicher des Servers. Auf die gleiche Weise werden neue Daten, wenn sie eintreffen, zuerst zwischengespeichert und finden dann einen Weg es in der Datenbank beizubehalten. Dies ist eine einfache Idee. Der Hauptschritt ist der Lastausgleich, der Anfragen von verschiedenen Benutzern auf verschiedene Verarbeitungsknoten verteilt, sie dann im Cache speichert und die Daten regelmäßig in der Hauptdatenbank aktualisiert. Der Lese- und Schreibvorgang verwendet einen Mechanismus ähnlich dem optimistischen Sperren, der jederzeit gelesen werden kann (auch beim Schreiben von Daten), jedoch wird bei jedem Lesen eine Versionsmarkierung angezeigt, wenn die gelesene Version dieses Mal niedriger ist als die Bei einer zwischengespeicherten Version werden die Daten erneut gelesen. Diese Situation ist selten und kann toleriert werden.
Sitzung und Cookie: Cookies ermöglichen es dem Server, den Besuch jedes Kunden zu verfolgen, diese Cookies müssen jedoch bei jedem Kundenbesuch zurückgesendet werden. Wenn viele Cookies vorhanden sind, erhöht sich die Menge der Datenübertragung zwischen dem Client und dem Server unsichtbar
Session löst dieses Problem sehr gut. Jedes Mal, wenn derselbe Client mit dem Server interagiert, müssen nicht jedes Mal alle Cookie-Werte zurückgegeben werden. eine eindeutige ID, die vom Server für den ersten Besuch jedes Clients generiert wird. Der Client muss nur diese ID zurückgeben. Diese ID ist normalerweise ein Cookie mit dem Namen JSESSIONID. Auf diese Weise kann der Server mithilfe dieser ID den im Server gespeicherten KV-Wert abrufen.
Sitzungs- und Cookie-Timeout-Probleme, Cookie-Sicherheitsprobleme
Distributed Session Framework
Konfigurationsserver, Zookeeper-Clusterverwaltungsserver können die Konfiguration aller Server einheitlich verwalten Datei
Gemeinsame Sitzungen werden in einem verteilten Cache gespeichert, der jederzeit geschrieben und gelesen werden kann, und die Leistung muss sehr gut sein, wie z. B. Memcache und Tair.
Kapseln Sie eine Klasse, die von HttpSession erbt, speichern Sie die Sitzung in dieser Klasse und speichern Sie sie dann im verteilten Cache
Da Cookies nicht möglich sind Domänenübergreifender Zugriff: Um eine Sitzungssynchronisierung zu erreichen, müssen Sitzungs-IDs synchronisiert und in verschiedene Domänennamen geschrieben werden.
Adaptermodus: Passen Sie eine Schnittstelle an eine andere Schnittstelle an. InputStreamReader in Java I/O passt die Reader-Klasse an InputStream an und erreicht so die Genauigkeit von Byte-Stream zu Zeichen-Stream.
Dekorationsmodus: Behalten Sie die ursprüngliche Benutzeroberfläche bei und verbessern Sie die ursprünglichen Funktionen.
FileInputStream implementiert alle Schnittstellen von InputStream. BufferedInputStreams erbt von FileInputStream und ist ein spezifischer Dekorator-Implementierer, der den von InputStream gelesenen Inhalt im Speicher speichert, um die Leseleistung zu verbessern.
Spring-Transaktionskonfigurationsmethode:
1. Pointcut-Informationen, die zum Auffinden von Geschäftsklassenmethoden verwendet werden, die Transaktionsaspekte implementieren.
2. Diese Attribute umfassen die Transaktionsisolationsstufe und die Transaktionsweitergabe Verhalten, Timeout-Zeitraum, Rollback-Regeln.
Spring verwendet den aop/tx-Schema-Namespace und die @Transaction-Annotationstechnologie für die deklarative Transaktionskonfiguration.
Mybatis
Jede Mybatis-Anwendung basiert auf einer Instanz des SqlSessionFactory-Objekts. Verwenden Sie zunächst einen Bytestream, um die Konfigurationsdatei über Resource zu lesen, erstellen Sie dann eine SqlSessionFactory über die Methode SqlSessionFactoryBuilder().build und erstellen Sie dann eine SqlSession, um jede Datenbanktransaktion über die Methode SqlSessionFactory.openSession() zu bedienen.
Erfahrene Mybatis-Initialisierung -> SQL-Sitzung erstellen -> SQL-Anweisungen ausführen und Ergebnisse in drei Prozessen zurückgeben
Der Unterschied zwischen Servlet und Filter:
Der gesamte Prozess ist: Filter bereitet Benutzeranforderungen vor Verarbeitung, dann die Die Anfrage wird zur Verarbeitung an das Servlet übergeben und eine Antwort wird generiert. Schließlich verarbeitet der Filter die Serverantwort nach.
Filter hat die folgenden Verwendungszwecke:
Filter kann bestimmte URL-Anfragen und -Antworten vor- und nachbearbeiten.
Fangen Sie die HttpServletRequest des Clients ab, bevor die HttpServletRequest das Servlet erreicht.
Überprüfen Sie HttpServletRequest nach Bedarf. Sie können auch den Header und die Daten von HttpServletRequest ändern.
HttpServletResponse abfangen, bevor es den Client erreicht.
Überprüfen Sie HttpServletResponse nach Bedarf. Sie können auch den Header und die Daten von HttpServletResponse ändern.
Tatsächlich sind Filter und Servlet sehr ähnlich. Der einzige Unterschied besteht darin, dass Filter keine direkte Antwort an den Benutzer generieren kann. Tatsächlich ist der Code in der doFilter()-Methode in Filter der gemeinsame Code, der aus der service()-Methode mehrerer Servlets extrahiert wird. Durch die Verwendung von Filter kann eine bessere Wiederverwendung erreicht werden.
Lebenszyklus von Filter und Servlet:
1.Filter wird initialisiert, wenn der Webserver startet
2. Wenn ein Servlet mit 1 konfiguriert ist, wird das Servlet auch initialisiert, wenn Tomcat (Servlet-Container) beginnt.
3. Wenn das Servlet nicht mit 1 konfiguriert ist, wird das Servlet beim Start von Tomcat nicht initialisiert, sondern erst, wenn die Anfrage eingeht.
4. Jedes Mal, wenn eine Anfrage gestellt wird, wird die Anfrage initialisiert. Nach der Beantwortung der Anfrage wird die Anfrage vernichtet.
5. Nachdem das Servlet initialisiert wurde, wird es nicht abgemeldet, wenn die Anfrage endet.
6. Wenn Tomcat geschlossen ist, werden Servlet und Filter nacheinander abgemeldet.
Der Unterschied zwischen HashMap und HashTable.
1. HashMap ist nicht threadsicher und HashTable ist threadsicher.
2. Sowohl Schlüssel als auch Werte von HashMap erlauben Nullwerte, HashTable jedoch nicht.
3. Aufgrund von Thread-Sicherheitsproblemen ist HashMap effizienter als HashTable.
Der Implementierungsmechanismus von HashMap:
Behalten Sie ein Array bei, in dem jedes Element eine verknüpfte Liste ist und jeder Knoten in der verknüpften Liste ein Eintrag []-Schlüssel ist. Wertepaar-Datenstruktur.
implementiert die Eigenschaften von Array + verknüpfter Liste, schnelle Suche, schnelles Einfügen und Löschen.
Für jeden Schlüssel ist sein entsprechender Array-Index-Index int i = hash(key.hashcode)&(len-1);
Jeder neu hinzugefügte Knoten wird am Kopf der verknüpften Liste platziert, und dann zeigt der neu hinzugefügte Knoten auf den Kopf der ursprünglichen verknüpften Liste
Der Unterschied zwischen HashMap und TreeMap
HashMap-Konflikt
Der Unterschied zwischen HashMap, ConcurrentHashMap und LinkedHashMap
ConcurrentHashMap verwendet die Sperrsegmentierungstechnologie, um die Thread-Sicherheit sicherzustellen: Teilen Sie die Daten zunächst zur Speicherung in Segmente auf und weisen Sie dann jedem Datensegment eine Sperre zu Auf Daten in einem Segment zugreifen, auf Daten in anderen Segmenten können auch andere Threads zugreifen
ConcurrentHashMap ist in jedem Segment (Segment) threadsicher
LinkedHashMap verwaltet eine doppelt verknüpfte Liste, und die darin enthaltenen Daten können in der Reihenfolge ausgelesen werden, in der sie geschrieben werden
ConcurrentHashMap-Anwendungsszenarien
1: Anwendungsszenarien von ConcurrentHashMap It ist hochgradig parallel, garantiert jedoch keine Thread-Sicherheit. Nach dem Sperren muss ConcurrentHashMap nur das entsprechende Segment sperren Der gleichzeitige synchrone Zugriff verbessert die Effizienz.
2: Kann in mehreren Threads geschrieben werden.
ConcurrentHashMap unterteilt die HashMap in mehrere Segmente
1. Beim Abrufen wird keine Sperre durchgeführt. Suchen Sie zuerst das Segment und suchen Sie dann den Hauptknoten für den Lesevorgang. Da der Wert eine flüchtige Variable ist, wird garantiert, dass er im Falle einer Race-Bedingung den neuesten Wert liest. Wenn der gelesene Wert null ist, wird er möglicherweise geändert. Anschließend wird die Funktion ReadValueUnderLock aufgerufen und die Sperre angewendet, um dies sicherzustellen Die gelesenen Daten sind korrekt.
2. Es wird beim Putten gesperrt und dem Kopf der Hash-Kette hinzugefügt.
3. Es wird auch beim Entfernen gesperrt. Da es sich bei „next“ um einen endgültigen Typ handelt und dieser nicht geändert werden kann, müssen alle Knoten vor dem gelöschten Knoten kopiert werden.
4.ConcurrentHashMap ermöglicht die gleichzeitige Ausführung mehrerer Änderungsvorgänge. Der Schlüssel liegt in der Verwendung der Sperrentrennungstechnologie. Es verwendet mehrere Sperren, um Änderungen an verschiedenen Segmenten der Hash-Tabelle zu steuern.
Das Anwendungsszenario von ConcurrentHashMap ist eine hohe Parallelität, garantiert jedoch keine Thread-Sicherheit. Nach dem Sperren muss ConcurrentHashMap nicht den gesamten Container sperren Das entsprechende Segment reicht aus, sodass ein hoher gleichzeitiger synchroner Zugriff gewährleistet und die Effizienz verbessert werden kann.
ConcurrentHashMap kann garantieren, dass jeder Aufruf eine atomare Operation ist, aber es garantiert nicht, dass mehrere Aufrufe auch atomare Operationen sind.
Der Unterschied zwischen Vector und ArrayList
ExecutorService service = Executors…. ExecutorService service = new ScheduledThreadPoolExecutor();
ThreadPoolExecutor-Quellcode-Analyse
Der Status des Thread-Pools selbst:
Wartende Aufgabenwarteschlange und Arbeitssatz:
Die Hauptzustandssperre des Thread-Pools:
Die Überlebenszeit und Größe des Thread-Pools:
1.2 ThreadPoolExecutor Internes Arbeitsprinzip
Schauen wir uns anhand der oben definierten Daten an, wie es intern implementiert wird. Doug Leas gesamte Idee ist in 5 Sätzen zusammengefasst:
Wenn die aktuelle Poolgröße poolSize kleiner als corePoolSize ist, erstellen Sie einen neuen Thread, um die Aufgabe auszuführen.
Wenn die aktuelle Poolgröße poolSize größer als corePoolSize ist und die Warteschlange nicht voll ist, geben Sie die Warteschlange ein
Wenn der aktuelle Pool Größe poolSize ist größer als corePoolSize und wenn es kleiner als MaximumPoolSize ist und die Warteschlange voll ist, wird ein neuer Thread erstellt, um die Aufgabe auszuführen.
Wenn die aktuelle Poolgröße poolSize größer als corePoolSize und größer als MaximumPoolSize ist und die Warteschlange voll ist, wird die Ablehnungsrichtlinie aufgerufen, um die Aufgabe zu verarbeiten.
Jeder Thread im Thread-Pool wird nicht sofort nach der Ausführung der Aufgabe beendet. Stattdessen wird geprüft, ob sich Thread-Aufgaben in der Warteschlange befinden, die ausgeführt werden müssen wartet in keepAliveTime. Wenn keine neuen Aufgaben vorhanden sind, wird der Thread beendet.
Executor-Paketstruktur
CopyOnWriteArrayList: Beim Schreiben sperren, den Originalcontainer kopieren, in einen neuen Container kopieren und dann in den neuen Container schreiben, den Verweis des Originalcontainers auf den neuen Container verweisen und beim Lesen die Daten lesen Für den alten Container kann gleichzeitiges Lesen durchgeführt werden, dies ist jedoch eine Strategie mit schwacher Konsistenz.
Verwendungsszenarien: CopyOnWriteArrayList eignet sich für den Einsatz in Szenarien, in denen Lesevorgänge weitaus umfangreicher sind als Schreibvorgänge, z. B. beim Caching.
Allgemeine Linux-Befehle: cd, cp, mv, rm, ps (verarbeiten), tar, cat (Inhalt anzeigen), chmod, vim, find, ls
Notwendige Bedingungen für Deadlock
Mindestens eine Ressource in einem nicht gemeinsam genutzten Zustand gegenseitig ausschließen
Besessen und wartend
Nicht- Präemption
Schleife warten
Um den Deadlock zu lösen, ist der erste die Deadlock-Verhinderung, die verhindern soll, dass die oben genannten vier Bedingungen wahr sind gleichzeitig. Die zweite besteht darin, die Ressourcen vernünftig zu verteilen.
Die dritte Möglichkeit besteht darin, den Bankalgorithmus zu verwenden. Wenn die verbleibende Menge an vom Prozess angeforderten Ressourcen vom Betriebssystem erfüllt werden kann, werden diese zugewiesen.
Interprozess-Kommunikationsmethode
Pipe (Pipe): Pipe ist eine Halbduplex-Kommunikationsmethode und kann nur in eine Richtung fließen in eine Richtung. Wird zwischen verwandten Prozessen verwendet. Prozessaffinität bezieht sich normalerweise auf die Eltern-Kind-Prozessbeziehung.
Named Pipe: Named Pipe ist ebenfalls eine Halbduplex-Kommunikationsmethode, ermöglicht jedoch die Kommunikation zwischen unabhängigen Prozessen.
Semaphor (Semophore): Ein Semaphor ist ein Zähler, mit dem der Zugriff mehrerer Prozesse auf gemeinsam genutzte Ressourcen gesteuert werden kann. Es wird häufig als Sperrmechanismus verwendet, um zu verhindern, dass andere Prozesse auf eine gemeinsam genutzte Ressource zugreifen, während ein Prozess auf die Ressource zugreift. Daher wird es hauptsächlich als Mittel zur Synchronisierung zwischen Prozessen und zwischen verschiedenen Threads innerhalb desselben Prozesses verwendet.
Nachrichtenwarteschlange: Die Nachrichtenwarteschlange ist eine verknüpfte Liste von Nachrichten, die im Kernel gespeichert und durch die Nachrichtenwarteschlangen-ID identifiziert wird. Nachrichtenwarteschlangen überwinden die Nachteile weniger Signalübertragungsinformationen, Pipes können nur unformatierte Byteströme übertragen und begrenzte Puffergrößen.
Signal (sinal): Signal ist eine relativ komplexe Kommunikationsmethode, mit der der empfangende Prozess darüber informiert wird, dass ein Ereignis aufgetreten ist.
Gemeinsamer Speicher (Shared Memory): Beim Shared Memory wird ein Speicherbereich abgebildet, auf den andere Prozesse zugreifen können. Dieser Shared Memory wird von einem Prozess erstellt, kann aber von anderen Prozessen aufgerufen werden mehrere Prozesse. Shared Memory ist die schnellste IPC-Methode und wurde speziell entwickelt, um die Ineffizienzen anderer Methoden zur prozessübergreifenden Kommunikation zu beseitigen. Es wird häufig in Verbindung mit anderen Kommunikationsmechanismen wie Semaphoren verwendet, um eine Synchronisierung und Kommunikation zwischen Prozessen zu erreichen.
Socket: Socket ist im Gegensatz zu anderen Kommunikationsmechanismen auch ein prozessübergreifender Kommunikationsmechanismus, der für die Prozesskommunikation zwischen verschiedenen Maschinen verwendet werden kann.
Der Unterschied und die Verbindung zwischen Prozessen und Threads
Der Prozessplanungsalgorithmus des Betriebssystems
Detaillierte Erläuterung der hierarchischen Speicherstruktur des Computersystems
Eine Datenbanktransaktion bezieht sich auf eine einzelne Abfolge von Vorgängen, die von einer logischen Arbeitseinheit ausgeführt werden.
Zusammenfassung der MySQL-Datenbankoptimierung
Gemeinsame Methoden zur MYSQL-Optimierung
MySQL-Speicher-Engine – der Unterschied zwischen MyISAM und InnoDB
Über SQL-Datenbank Das Paradigma im First-Level-Cache von
Hibernate wird von Session bereitgestellt und existiert daher nur im Lebenszyklus von Session, wenn das Programm save(), update(), saveOrUpdate() und andere Methoden aufruft und ruft Abfragen auf. Wenn die Schnittstelle auflistet, filtert, iteriert und das entsprechende Objekt noch nicht im Sitzungscache vorhanden ist, fügt Hibernate das Objekt dem Cache der ersten Ebene hinzu und der Cache verschwindet, wenn die Sitzung geschlossen wird.
Der Cache der ersten Ebene von Hibernate ist in die Sitzung integriert und kann in keiner Weise deinstalliert oder konfiguriert werden. Der Cache der ersten Ebene wird mithilfe der Schlüsselwert-Map-Methode implementiert Die Schlüssel-ID ist der Schlüssel der Karte und das Entitätsobjekt ist der entsprechende Wert.
Cache der zweiten Ebene in den Ruhezustand versetzen: Legen Sie alle erhaltenen Datenobjekte entsprechend der ID in den Cache der zweiten Ebene. Die Cache-Strategie der zweiten Ebene von Hibernate ist eine Cache-Strategie für ID-Abfragen. Wenn Daten gelöscht, aktualisiert oder hinzugefügt werden, wird gleichzeitig der Cache aktualisiert.
Der Unterschied zwischen Prozessen und Threads:
Prozess: Jeder Prozess verfügt über einen unabhängigen Code- und Datenraum (das Wechseln zwischen Prozessen verursacht einen großen Overhead). .
Threads: Threads desselben Typs teilen sich Code und Datenraum. Jeder Thread verfügt über einen unabhängigen laufenden Stapel- und Programmzähler (PC), und der Aufwand für den Threadwechsel ist gering.
Threads sind wie Prozesse in fünf Phasen unterteilt: Erstellung, Bereitschaft, Ausführung, Blockierung und Beendigung.
Multiprozess bedeutet, dass das Betriebssystem mehrere Aufgaben (Programme) gleichzeitig ausführen kann.
Multithreading bezieht sich auf die Ausführung mehrerer Sequenzflüsse im selben Programm.
Um Multithreading in Java zu erreichen, gibt es drei Möglichkeiten: Eine besteht darin, die Thread-Klasse fortzusetzen, die andere darin, die Runable-Schnittstelle zu implementieren, und die dritte darin, die Callable-Schnittstelle zu implementieren.
Kann Switch String als Parameter verwenden?
a. Vor Java 7 konnte Switch nur Byte, Short, Char, Int oder die entsprechenden Kapselungsklassen und Enum-Typen unterstützen. In Java 7 wurde String-Unterstützung hinzugefügt.
Was sind die öffentlichen Methoden von Object?
a. Die Methode „equals“ testet, ob zwei Objekte gleich sind
b Die Methode „clone“ kopiert das Objekt
c Objekt
d. Die Methoden notify, notifyall und wait werden alle zum Thread-Synchronisieren eines bestimmten Objekts verwendet
Die vier Arten von Java-Referenzen, stark und schwach, und die Szenarien, in denen sie sich befinden gebraucht
a. Verwenden Sie Soft-Referenzen und schwache Referenzen, um das OOM-Problem zu lösen: Verwenden Sie eine HashMap, um die Zuordnungsbeziehung zwischen dem Pfad des Bildes und der dem entsprechenden Bildobjekt zugeordneten Soft-Referenz zu speichern Der belegte Speicherplatz dieser zwischengespeicherten Bildobjekte wird automatisch recycelt, wodurch das OOM-Problem effektiv vermieden wird.
b. Implementieren Sie das Caching von Java-Objekten durch Soft-Accessible-Objektabrufmethoden: Wenn wir beispielsweise eine Employee-Klasse erstellen, müssen wir jedes Mal die Informationen eines Mitarbeiters abfragen. Selbst wenn die Abfrage erst vor wenigen Sekunden erfolgte, muss eine Instanz neu erstellt werden, was viel Zeit in Anspruch nimmt. Wir können Soft-Referenzen und HashMap kombinieren. Speichern Sie zunächst die Referenz: Referenzieren Sie eine Instanz des Employee-Objekts in Form einer Soft-Referenz und speichern Sie die Referenz in der HashMap. Der Schlüssel ist die ID des Mitarbeiters und der Wert ist die Soft-Referenz von Dieses Objekt hingegen dient dazu, die Referenz herauszunehmen und zu prüfen, ob eine Soft-Referenz auf die Employee-Instanz im Cache vorhanden ist. Wenn ja, holen Sie sie aus der Soft-Referenz. Wenn keine Soft-Referenz vorhanden ist oder die aus der Soft-Referenz erhaltene Instanz null ist, erstellen Sie eine Instanz neu und speichern Sie die Soft-Referenz in der neu erstellten Instanz.
c. Starke Referenz: Wenn ein Objekt eine starke Referenz hat, wird es vom Garbage Collector nicht recycelt. Auch wenn der aktuelle Speicherplatz nicht ausreicht, wird die JVM ihn nicht zurückfordern, sondern einen OutOfMemoryError-Fehler auslösen, der dazu führt, dass das Programm abnormal beendet wird. Wenn Sie die Zuordnung zwischen einer starken Referenz und einem Objekt aufheben möchten, können Sie die Referenz explizit auf Null zuweisen, sodass die JVM das Objekt zum richtigen Zeitpunkt wiederverwendet.
d. Soft-Referenz: Wenn genügend Speicherplatz vorhanden ist, kann die Soft-Referenz weiterhin verwendet werden, ohne vom Garbage Collector recycelt zu werden Vom Müllsammler recycelt.
e. Schwache Referenz: Objekte mit schwachen Referenzen haben einen kürzeren Lebenszyklus. Denn wenn die JVM eine Garbage Collection durchführt, wird die schwache Referenz unabhängig davon, ob der aktuelle Speicherplatz ausreicht, recycelt, sobald ein schwaches Referenzobjekt gefunden wird. Da der Garbage Collector jedoch ein Thread mit niedriger Priorität ist, kann er schwache Referenzobjekte möglicherweise nicht schnell finden.
f. Virtuelle Referenz: Wie der Name schon sagt, handelt es sich nur um eine virtuelle Referenz. Wenn ein Objekt nur eine virtuelle Referenz enthält, ist dies gleichbedeutend mit dem Fehlen einer Referenz und kann jederzeit vom Garbage Collector recycelt werden .
Was ist der Unterschied zwischen Hashcode und equal?
a. Es wird auch verwendet, um festzustellen, ob zwei Objekte gleich sind: Liste und Menge. Diese Methode ermöglicht keine wiederholte Implementierung Sie verwenden „equal to“. Wenn zum Vergleich 1.000 Elemente vorhanden sind und Sie ein neues Element erstellen, müssen Sie „equal“ 1.000 Mal aufrufen, um sie einzeln zu vergleichen und festzustellen, ob es sich um dasselbe Objekt handelt, was die Effizienz erheblich verringert. Der Hashcode gibt tatsächlich die Speicheradresse des Objekts zurück. Wenn an dieser Position kein Element vorhanden ist, wird das Element direkt darüber gespeichert. Wenn an dieser Position bereits ein Element vorhanden ist, wird zu diesem Zeitpunkt die Methode equal aufgerufen, um mit dem neuen zu vergleichen Wenn sie identisch sind, werden sie nicht gespeichert und an eine andere Adresse gehasht.
Die Bedeutung und der Unterschied zwischen Override und Overload ist, wie der Name schon sagt, das Neuladen. Es kann sein, dass die Funktion kann den gleichen Funktionsnamen haben, aber die Parameternamen, Rückgabewerte und Typen können nicht gleich sein; mit anderen Worten, die Parameter, Typen und Rückgabewerte können geändert werden, aber der Funktionsname bleibt unverändert. b. Wenn die Unterklasse die übergeordnete Klasse erbt, kann sie eine Methode mit demselben Namen und denselben Parametern wie ihre übergeordnete Klasse definieren. Methoden von Unterklassen und übergeordneten Klassen entsprechen dem Überschreiben (Überschreiben).
Einzelheiten finden Sie in der Analyse von Beispielen zum Unterschied zwischen Überladen und Umschreiben (Überschreiben) in C++
Der Unterschied zwischen abstrakten Klassen und Schnittstellen
Eine Klasse kann nur eine einzelne Klasse erben, aber mehrere Schnittstellen können implementiert werden
b Es kann Konstruktoren in abstrakten Klassen geben, aber keine Konstruktoren in Schnittstellen
c Müssen abstrakt sein, können Sie einige grundlegende Methoden in abstrakten Klassen implementieren. Die Schnittstelle erfordert, dass alle Methoden abstrakt sein müssen
d. Abstrakte Klassen können statische Methoden enthalten, aber Schnittstellen können keine normalen Mitgliedsvariablen haben, und Schnittstellen können nicht möglich sein
Prinzipien und Merkmale verschiedener Methoden zum Parsen von XML: DOM, SAX, PULL
a.DOM: Speicherverbrauch: Lesen Sie zuerst alle XML-Dokumente in den Speicher und verwenden Sie dann die DOM-API, um auf die Baumstruktur zuzugreifen und Daten abrufen. Dies ist sehr einfach zu schreiben, verbraucht jedoch viel Speicher. Wenn die Datenmenge zu groß ist und das Telefon nicht leistungsfähig genug ist, kann es zu einem Absturz des Telefons kommen.
b.SAX: hohe Parsing-Effizienz, geringer Speicherverbrauch, ereignisgesteuert: einfacher, es scannt das Dokument nacheinander Scannen Benachrichtigen Sie die Ereignisverarbeitungsfunktion, wenn der Anfang und das Ende des Dokuments (Dokuments), der Anfang und das Ende des Elements (Elements), das Ende des Dokuments (Dokuments) usw. erreicht sind, und die Ereignisverarbeitungsfunktion führt entsprechende Schritte aus Aktionen ausführen und dann den gleichen Scan bis zum Ende des Dokuments fortsetzen.
c.PULL: Ähnlich wie SAX ist es auch ereignisgesteuert, um das nächste Parsing-Ereignis abzurufen (d. h. Startdokument, Enddokument, Start-Tag, End-Tag). Bei einem bestimmten Element können Sie die getAttributte()-Methode von XmlPullParser aufrufen, um den Wert des Attributs abzurufen, oder Sie können dessen nextText() aufrufen, um den Wert dieses Knotens abzurufen.
Der Unterschied zwischen wait() und sleep()
Sleep kommt von der Thread-Klasse und Wait kommt von der Object-Klasse
Während des Aufrufs von Sleep( )-Methode wird die Objektsperre des Threads nicht freigegeben. Der Thread, der die Wartemethode aufruft, gibt die Objektsperre frei
Sleep gibt nach dem Ruhen keine Systemressourcen auf und andere Threads können die CPU belegen
Sleep (Millisekunden) muss eine Ruhezeit angeben. Es wird automatisch aktiviert, wenn es ankommt
Der Unterschied zwischen Heap und Stack in JAVA. Lassen Sie uns über den Speichermechanismus von Java sprechen
a und Objektreferenzen werden alle auf dem Stapel zugewiesen
b Heap-Speicher wird zum Speichern von Objekten und Arrays verwendet, die durch neue erstellt wurden
c Klassenvariablen, das Programm weist Speicher zu Für Klassenvariablen im Heap wird beim Laden die Speicheradresse im Heap im Stapel gespeichert
d. Wenn Sie das Java-Schlüsselwort new verwenden, weist das System den Variablen im Heap Speicherplatz zu Das ist nicht unbedingt kontinuierlich, sondern basiert auf Streuung. Die Heap-Speicheradresse wird durch einen Hash-Algorithmus in eine lange Zahlenfolge umgewandelt, um den „physischen Ort“ dieser Variablen im Heap darzustellen. Der Lebenszyklus der Instanzvariablen – wenn die Wenn der Verweis auf die Instanzvariable verloren geht, wird sie vom GC (Garbage Collector) in die wiederverwertbare „Liste“ aufgenommen, der Speicher im Heap wird jedoch nicht sofort freigegeben.
E. Lokale Variablen: in einer bestimmten Methode deklariert oder ein bestimmtes Codesegment (z. B. eine for-Schleife), das bis zu seinem Wert ausgeführt wird. Wenn der Speicher auf dem Stapel zugewiesen wird und die lokale Variable den Gültigkeitsbereich verlässt, wird der Speicher sofort freigegeben
Das Implementierungsprinzip von JAVA Polymorphismus
a. Abstrakt gesehen bedeutet Polymorphismus, dass sich dieselben Nachrichten auf viele verschiedene Arten verhalten können, je nachdem, an wen sie gesendet werden. (Das Senden einer Nachricht ist ein Funktionsaufruf)
b. Das Implementierungsprinzip ist die dynamische Bindung der vom Programm aufgerufenen Methode. Durch die Verfolgung des Quellcodes kann festgestellt werden, dass die JVM den entsprechenden Parameter findet durch automatische Transformation.
Verwandte Empfehlungen:
Zusammenfassung der Interviewfragen und Antworten zur Java-Sammlung
Analyse der Ladereihenfolge von Klassen in Java (häufig verwendet in Interviewfragen)
Das obige ist der detaillierte Inhalt vonZusammenfassung und Zusammenstellung von Java-Interviewfragen großer Unternehmen (alle). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!