2024-07-08
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Die unterste Ebene von ArrayList wird basierend auf Arrays implementiert. Dies geschieht durch dynamisches Erweitern oder Verringern der Größe des Arrays. Wenn die Kapazität nicht ausreicht, wird ein größeres Array erstellt, dann die Originaldaten kopiert und schließlich die neuen Daten hinzugefügt.
Der Mechanismus der ArrayList-Erweiterung ist: Wenn das erste Element hinzugefügt wird, beträgt die Kapazität von ArrayList jedes Mal 10. Wenn die Kapazität überschritten wird, wird die ursprüngliche Kapazität verdoppelt, dh die ursprüngliche Kapazität * 2 Wenn die ursprüngliche Kapazität 0 ist, ist die neue Kapazität 1.
Die interne Implementierung von ArrayList basiert auf Arrays. Wenn mehrere Threads gleichzeitig auf dieselbe ArrayList zugreifen, kann es zu Dateninkonsistenzen kommen, wenn beispielsweise ein Thread die Daten der ArrayList liest und ein anderer Thread Daten hinzufügt/löscht In der ArrayList kann es sein, dass die Daten in der ArrayList geändert werden, sodass der Thread, der die ArrayList-Daten liest, möglicherweise falsche Daten liest, was zu einem Programmfehler führt.
Der Stapel ist eine spezielle lineare Tabelle. Seine Besonderheit besteht darin, dass Daten nur an einem Ende eingefügt und gelöscht werden können, basierend auf dem First-In-Last-Out-Last-In-First-Out-Prinzip. Es handelt sich um eine Speicherstruktur, die zum Speichern von Funktionsparameterwerten, lokalen Variablen usw. verwendet werden kann.
Ein Heap ist eine spezielle Baumstruktur, die dadurch gekennzeichnet ist, dass die Werte aller Knoten größer oder gleich den Werten ihrer untergeordneten Knoten sind und der Wert des Wurzelknotens der größte oder kleinste ist. Der Heap ist eine dynamische Speicherstruktur, die zum Speichern großer Datenmengen wie Sortieren, Suchen usw. verwendet werden kann.
Die Essenz einer Coroutine ist ein leichter Thread. Jede Coroutine verfügt über einen Stapel zum Speichern von Funktionen und ihren Parametern, lokalen Variablen usw. Die Coroutine kann so angehalten, fortgesetzt und umgeschaltet werden.
Zustandssynchronisation Es bezieht sich auf die Übertragung des Status (z. B. Position, Geschwindigkeit, Beschleunigung usw.) jeder Maschine im Mehrmaschinensystem an andere Maschinen in jedem Steuerzyklus, sodass jede Maschine synchronisiert bleibt. Durch die Zustandssynchronisierung kann eine Echtzeitleistung der kollaborativen Steuerung mehrerer Maschinen erreicht werden. Da jedoch in jedem Steuerungszyklus eine große Datenmenge übertragen werden muss, ist die Genauigkeit möglicherweise relativ gering.
Frame-Synchronisation Dies bedeutet, dass in jedem Steuerzyklus die Steuerbefehle jeder Maschine im Mehrmaschinensystem an andere Maschinen übertragen werden, sodass jede Maschine synchronisiert bleibt. Durch die Rahmensynchronisation kann die Genauigkeit einer kollaborativen Steuerung mehrerer Maschinen erreicht werden. Da jedoch in jedem Steuerungszyklus nur eine geringe Anzahl von Steuerbefehlen übertragen wird, ist die Echtzeitleistung möglicherweise relativ gering.
Die unterste Ebene von HashMap wird mithilfe einer Array-verknüpften Liste (Rot-Schwarz-Baum) implementiert. Sie speichert Daten entsprechend dem HashCode-Wert des Schlüssels. Sie kann die Position der Daten im Array (Hash-Konflikt) basierend auf dem Hash berechnen Code und verwendet eine verknüpfte Liste (Rot-Schwarz-Baum), um Konflikte zu speichern. HashMap Wenn in Java 8 die Länge der verknüpften Liste den Schwellenwert überschreitet (Standard ist 8), wird sie in einen rot-schwarzen Baum konvertiert, um die Abfrageeffizienz zu verbessern.Wenn die Kapazität nicht ausreicht, wird sie automatisch erweitert. Der Standardlastfaktor beträgt 0,75 und die Erweiterungsmethode beträgt das Zweifache der Kapazität.
Was sind die Nutzungsszenarien von Stapeln und Warteschlangen?
Die Vorwärts- und Rückwärtsfunktionen des Browsers: Die vom Browser besuchten Webseiten können die Vorwärts- und Rückwärtsfunktionen über die Stapeldatenstruktur realisieren.
Das TCP-Sticky-Problem bezieht sich auf die Tatsache, dass das TCP-Protokoll die Daten beim Übertragen von Daten nicht fragmentiert, was dazu führt, dass die vom empfangenden Ende empfangene Datenmenge größer ist als die vom sendenden Ende gesendete Datenmenge.
Erstens können UDP-Datagramme dabei helfen, den Drei-Wege-Handshake-Prozess im TCP/IP-Protokoll zu implementieren. Beim ersten Handshake sendet ein Client ein UDP-Datagramm mit einer Handshake-Anfrage. Wenn der Server diese Nachricht empfängt, antwortet er mit einer Bestätigungsnachricht, die angibt, dass der Server die Handshake-Anfrage des Clients erhalten hat und bereit ist, Dienste bereitzustellen. Beim zweiten Handshake sendet der Client erneut ein UDP-Datagramm. Diesmal enthält die Nachricht einige nützliche Informationen, wie z. B. die IP-Adresse des Clients, die Portnummer usw., damit der Server den Client identifizieren kann. Beim dritten Handshake sendet der Server ein UDP-Datagramm, das anzeigt, dass die Verbindung hergestellt wurde und der Client mit dem Senden von Daten beginnen kann.
Zweitens können UDP-Datagramme auch dabei helfen, den Datenübertragungsprozess im TCP/IP-Protokoll zu realisieren. Wenn der Client Daten an den Server senden muss, werden die Daten in ein UDP-Datagramm gekapselt und an den Server gesendet. Nachdem der Server das UDP-Datagramm empfangen hat, analysiert er die in der Nachricht enthaltenen Daten und führt die entsprechende Verarbeitung durch.
Schließlich können UDP-Datagramme auch dabei helfen, den Terminierungsprozess im TCP/IP-Protokoll zu implementieren.Wenn der Client nicht mehr mit dem Server kommunizieren muss, kann er ein UDP-Datagramm senden, um anzuzeigen, dass der Client die Verbindung beendet. Nachdem der Server diese Nachricht erhalten hat, gibt er die entsprechenden Ressourcen frei und vervollständigt so das gesamte TCP/IP-Protokoll . Verbindungsprozess
Coroutinen ermöglichen es Programmen, zwischen verschiedenen Aufgaben zu wechseln, wodurch die Programmeffizienz verbessert und die Programmlaufzeit verkürzt wird. Coroutinen ermöglichen es einem Programm, zwischen mehreren Aufgaben zu wechseln, anstatt auf den Abschluss einer Aufgabe zu warten, bevor es eine andere startet. Außerdem können Variablen zwischen verschiedenen Threads gemeinsam genutzt werden, wodurch die Laufzeit des Programms verkürzt wird. Bei Multitasking-Anwendungen kann der Einsatz von Coroutinen die Leistung erheblich verbessern, was zu schnelleren Ausführungsgeschwindigkeiten führt.
Arrays sind schneller, da die Adresse jedes Elements des Arrays kontinuierlich und fest ist und die Adresse des nächsten Elements schnell ermittelt werden kann, während die Adresse jedes Elements der verknüpften Liste diskontinuierlich ist und Sie den Zeiger durchlaufen müssen Um die Adresse des nächsten Elements zu erhalten, ist die Durchquerung des Arrays schneller.
Eine virtuelle Funktion ist eine spezielle Funktion, die sich von gewöhnlichen Funktionen dadurch unterscheidet, dass sie automatisch vom Compiler definiert wird und zur Kompilierungszeit aufgerufen werden kann. Das Merkmal einer virtuellen Funktion besteht darin, dass ihre Implementierung zur Laufzeit und nicht zur Kompilierungszeit bestimmt wird.
Der Hauptzweck virtueller Funktionen besteht darin, Polymorphismus zu erreichen. Eine abstrakte Klasse kann mehrere virtuelle Funktionen definieren und ihre Unterklassen können diese Funktionen dann implementieren.
Es muss keine virtuelle Funktion sein, es wird jedoch im Allgemeinen empfohlen, eine virtuelle Funktion zu verwenden, da eine virtuelle Funktion von einer abgeleiteten Klasse überschrieben werden kann, sodass der Destruktor der abgeleiteten Klasse korrekt ausgeführt werden kann Wird es nicht verwendet, wird der Destruktor der abgeleiteten Klasse nicht aufgerufen, was zu Problemen wie Speicherverlusten führen kann.
Die Rendering-Pipeline besteht aus einer Reihe von Schritten, mit denen Spielszenendaten von Eingabeinformationen in auf dem Bildschirm angezeigte Bilder umgewandelt werden.
Der Prozess der Rendering-Pipeline ist in drei Hauptphasen unterteilt: Vorbereitungsphase, Geometriephase und Beleuchtungsphase.
In der Vorbereitungsphase lädt die Spiel-Engine die Modelle und Texturen der Spielszene in die Grafikverarbeitungseinheit (GPU) und organisiert die Daten für die Verwendung in nachfolgenden Phasen.
Während der Geometriephase werden Matrixtransformationen verwendet, um das Modell im dreidimensionalen Raum zu platzieren und das Modell in eine Form umzuwandeln, die von Pixeln auf dem Bildschirm unterstützt werden kann.
In der Beleuchtungsphase werden die Lichtquelle und das Beleuchtungsmodell verwendet, um den Farbwert jedes Pixels zu berechnen, und das resultierende Bild wird schließlich auf dem Bildschirm angezeigt.
Die Bedingungen dafür, dass der Greedy-Algorithmus die optimale Lösung erhält, sind die „optimale Unterstruktur“ und die „Greedy-Selection-Eigenschaft“: