Le contenu suivant est des questions et réponses responsables données après que l'ensemble de questions d'entrevue Java d'origine et les réponses ont été entièrement révisés. Il y avait de nombreuses questions en double et des questions précieuses dans les questions originales, et de nombreuses réponses de référence étaient également erronées. L'ensemble de questions d'interview Java modifié fait référence à la dernière version de JDK, supprime le contenu inutile tel que EJB 2.x et complète la structure de données et les questions liées à l'algorithme, les questions de programmation d'interview classiques, la grande architecture technique du site Web, le système d'exploitation, la base de données, les tests de logiciels, les modèles de conception, l'UML et d'autres contenus. Dans le même temps, de nombreux points de connaissance ont également été analysés en profondeur, tels que la conception de la méthode HashCode, le tas et la génération de collecte des ordures, la nouvelle programmation simultanée de Java, Nio.2, etc. Je crois qu'il sera bénéfique pour les programmeurs Java qui se préparent à rejoindre.
Ensemble de questions d'interview du programmeur Java (1-50)
1. Bases Java
1. Quels sont les aspects des caractéristiques orientées objet?
Réponse: Les principaux aspects des caractéristiques orientées objet sont:
1) Résumé: L'abstraction est le processus de résumé les caractéristiques communes d'un type d'objet dans une classe d'objets, y compris l'abstraction des données et l'abstraction du comportement. L'abstraction se concentre uniquement sur les attributs et les comportements de l'objet et ne prête pas attention aux détails de ces comportements.
2) Héritage: l'héritage est le processus d'obtention des informations sur l'héritage des classes existantes et de la création de nouvelles classes. La classe qui fournit des informations héréditaires est appelée la classe parent (Superclass, classe de base); La classe qui obtient des informations héréditaires est appelée sous-classe (classe dérivée). L'héritage donne au système logiciel changeant un certain degré de continuité, et l'héritage est également un moyen important de résumer les facteurs variables du programme (si vous ne pouvez pas le comprendre, veuillez lire la partie sur le mode Bridge dans les "Java and Matchs" du Dr Yan Hong ou les "modèles de conception exquis").
3) Encapsulation: On pense généralement que l'encapsulation consiste à lier les données à la méthode de fonctionnement des données, et l'accès aux données ne peut être obtenu que via l'interface définie. L'essence de l'objet est de dépeindre le monde réel comme une série d'objets complètement autonomes et fermés. La méthode que nous écrivons dans une classe est d'encapsuler les détails de l'implémentation; Nous écrivons une classe consiste à encapsuler les données et les opérations de données. On peut dire que l'emballage est de cacher tout ce qui peut être caché et ne fournit que l'interface de programmation la plus simple au monde extérieur (vous pouvez penser à la différence entre une machine à laver ordinaire et une machine à laver entièrement automatique. Il est évident que la machine à laver entièrement automatique est mieux emballée et donc plus facile à utiliser; le smartphone que nous utilisons maintenant est également assez bien emballé car quelques boutons peuvent gérer tout).
4) Polymorphisme: le polymorphisme fait référence à l'autorisation d'objets de différents sous-types de répondre différemment au même message. En termes simples, il s'agit d'appeler la même méthode avec la même référence d'objet, mais faites des choses différentes. Les polymorphismes sont divisés en polymorphismes à temps de compilation et en polymorphismes d'exécution. If the object's method is regarded as a service provided by the object to the outside world, then the runtime polymorphism can be explained as: when system A accesses the services provided by system B, system B has multiple ways to provide services, but everything is transparent to system A (just like an electric shaver is system A, its power supply system is system B, system B can be powered by batteries or AC, and it may even be solar energy. System A will only call the power supply method through class B objets, mais il ne sait pas quelle est la mise en œuvre sous-jacente du système d'alimentation et comment il obtient la puissance). La surcharge de méthode met en œuvre le polymorphisme à temps de compilation (également connu sous le nom de prébinding), tandis que la méthode remplace la méthode implémente le polymorphisme d'exécution (également connu sous le nom de post-contrainte). Le polymorphisme d'exécution est la chose la plus essentielle à propos de l'objet. Pour implémenter le polymorphisme, deux choses doivent être faites: 1. Réécriture de la méthode (la sous-classe hérite de la classe parent et réécrit les méthodes existantes ou abstraites dans la classe parent); 2. Modélisation d'objets (se référant à l'objet de type enfant avec la référence de type parent, de sorte que la même référence appelle la même méthode affichera des comportements différents en fonction des différents objets de sous-classe).
2. Quelle est la différence entre l'accès aux modificateurs publics, privés, protégés et non écrits (par défaut)?
Réponse: Les différences sont les suivantes:
La portée est la même que la sous-classe BUN.
public √ √ √ √ √ √
protégé √ √ √ ×
par défaut √ √ × ×
privé √ × × ×
La valeur par défaut est par défaut lorsque les membres de la classe n'écrivent pas de modification d'accès. Par défaut, il est équivalent au public pour d'autres classes dans le même package et privé pour d'autres classes qui ne sont pas dans le même package. Protégé est équivalent à des sous-classes publiques et privées à des classes qui ne sont pas dans le même package qui n'ont aucune relation parent-enfant.
3. La chaîne est-elle le type de données le plus basique?
Réponse: Non À l'exception du type de base (type primitif) et du type d'énumération (type d'énumération), les autres sont des types de référence (type de référence).
4. Float f = 3,4; Est-ce correct?
Réponse: incorrect. 3.4 est un numéro de double précision. L'attribution du double au type de point flottante (float) entraînera une perte de précision (casting des bas, également connu sous le nom de rétrécissement), vous devez donc lancer float f = (float) 3.4; ou écrire float f = 3,4f;.
5. Short S1 = 1; S1 = S1 + 1; Y a-t-il quelque chose de mal? S1 court = 1; S1 + = 1; Y a-t-il quelque chose qui ne va pas?
Réponse: Pour S1 court = 1; S1 = S1 + 1; Puisque 1 est un type int, le résultat de l'opération S1 + 1 est également un type INT, et un type de fonte est nécessaire pour attribuer une valeur au type court. Et court S1 = 1; S1 + = 1; Peut être compilé correctement parce que S1 + = 1; est équivalent à S1 = (court) (S1 + 1); Il y a des moulages implicites.
6. Y a-t-il un goto à Java?
Réponse: Goto est un mot réservé en Java et n'est pas utilisé dans la version actuelle de Java. (A list of Java keywords is given in the appendix of the book "The Java Programming Language" written by James Gosling (the father of Java), which includes goto and const, but these two are keywords that are currently unusable, so some places call it reserved words. In fact, the word reserved words should have a broader meaning, because programmers familiar with C language know that words or combinations of words that have special meanings used in the system La bibliothèque est considérée comme des mots réservés)
7. Quelle est la différence entre INT et INTEGER?
Réponse: Java est un langage de programmation orienté objet presque pur, mais pour la commodité en programmation, il introduit toujours des types de données de base qui ne sont pas des objets. Cependant, afin de faire fonctionner ces types de données de base en tant qu'objets, Java a introduit la classe de wrapper correspondante pour chaque type de données de base. La classe d'emballage d'INT est entier. Depuis JDK 1.5, un mécanisme d'emballage / déballage automatique a été introduit, de sorte que les deux peuvent être convertis les uns aux autres.
Java fournit des types de wrapper pour chaque type primitif:
Types primitifs: booléen, char, octet, court, int, long, flotteur, double
Types d'emballage: booléen, caractère, octet, court, entier, long, flotteur, double
package com.lovo; // Pourquoi poser des questions sur la classe Hovertree. Entier b = 3; // boîte automatique 3 dans un type entier int c = 3; System.out.println (a == b); // Faux Les deux références ne font pas référence au même System d'objet.out.println (a == C); // vrai un déborde automatiquement dans le type int, puis se compare à c}}
Ajouté: J'ai récemment rencontré une question d'entrevue, qui est également liée à l'emballage et à la déballage automatique, le code est le suivant:
classe publique test03 {public static void main (String [] args) {entier f1 = 100, f2 = 100, f3 = 150, f4 = 150; System.out.println (F1 == F2); System.out.println (F3 == F4); }} // hovertree.comSi vous ne le comprenez pas, il est facile de penser que les deux sorties sont vraies ou fausses. Tout d'abord, il est important de noter que les quatre variables F1, F2, F3 et F4 sont tous des objets entiers, de sorte que l'opération == suivante ne compare pas les valeurs mais les références. Quelle est l'essence de l'emballage? Lorsque nous attribuons une valeur int à un objet entier, nous appellerons la valeur de méthode statique de la classe entière. Si nous examinons le code source de la valeur, nous saurons ce qui se passe.
Public Static Integer ValueOf (int i) {if (i> = IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache [i + (-IntegerCache.low)]; retourner un nouvel entier (i); } // hovertree.comIntegerCache est une classe intérieure d'Enteger, et son code ressemble à ceci:
/ ** * Cache pour soutenir la sémantique d'identité d'objet de l'autoboxing pour les valeurs entre * -128 et 127 (inclusives) comme requis par JLS. * * Le cache est initialisé lors de la première utilisation. La taille du cache * peut être contrôlée par l'option {@code -xx: autoboxcacheMax = <Size>}. * Pendant l'initialisation VM, java.lang.integer.integercache.high Property * peut être défini et enregistré dans les propriétés du système privé dans la classe * Sun.Misc.vm. * hovertree.com * / classe statique privée IntegerCache {static final int low = -128; statique final int high; Cache entier final statique []; statique {// La valeur élevée peut être configurée par la propriété int h = 127; String IntegerCacheHighPropValue = Sun.Misc.vm.GetsAvedProperty ("Java.lang.integer.integerCache.high"); if (IntegerCacheHighPropValue! = null) {try {int i = paSeInt (IntegerCacheHighPropValue); i = math.max (i, 127); // La taille maximale du tableau est Integer.max_value h = math.min (i, Integer.max_value - (-low) -1); } catch (NumberFormatexception nfe) {// Si la propriété ne peut pas être analysée dans un int, ignorez-la. }} high = h; cache = nouvel entier [(élevé - bas) + 1]; int j = bas; pour (int k = 0; k <cache.length; k ++) cache [k] = nouveau entier (j ++); // La plage [-128, 127] doit être internalisée (JLS7 5.1.7) ASSERT IntegerCache.high> = 127; } private IntegerCache () {}}Autrement dit, si la valeur littérale se situe entre -128 et 127, le nouvel objet entier ne sera pas nouveau, mais l'objet entier dans le pool constant sera directement référencé. Par conséquent, le résultat de F1 == F2 dans la question d'entrevue ci-dessus est vrai, et le résultat de F3 == F4 est faux. Plus les questions d'entrevue sont simples, plus il y a de mystère et l'intervieweur doit avoir des compétences considérables.
8. Quelle est la différence entre & &&?
Réponse: Il y a deux utilisations de l'opérateur: (1) Bitwise et (2) logique et. L'opérateur && est un court-circuit et une opération. La différence entre la logique et les courts-circuits est très énorme, bien que les deux nécessitent que les valeurs booléennes aux extrémités gauche et droite de l'opérateur soient fidèles à la valeur de toute l'expression. && est appelé une opération de court-circuit car si la valeur de l'expression à gauche de && est fausse, l'expression à droite sera directement en court-circuit et l'opération ne sera pas effectuée. Plusieurs fois, nous devrons peut-être utiliser && au lieu de &. Par exemple, lors de la vérification que le nom d'utilisateur n'est pas nul et n'est pas une chaîne vide, elle doit être écrite comme: nom d'utilisateur! = Null &&! Username.equals (""). L'ordre des deux ne peut pas être échangé et l'opérateur & ne peut pas être utilisé, car si la première condition n'est pas vraie, la comparaison égale de la chaîne ne peut pas être effectuée du tout, sinon une nulpointerException sera générée. Remarque: il en va de même pour la différence entre logique ou opérateur (|) et court-circuit ou opérateur (||).
Ajouté: si vous connaissez JavaScript, vous pourrez peut-être ressentir davantage la puissance de l'informatique court-circuit. Si vous voulez devenir un maître de JavaScript, commencez par jouer à court-circuit informatique.
9. Expliquez l'utilisation des zones de stockage de pile, de tas et de statique en mémoire.
Réponse: Habituellement, nous définissons une variable du type de données de base, une référence d'objet et le stockage sur site des appels de fonction utilisent tous l'espace de pile en mémoire; et les objets créés à travers le nouveau mot-clé et le nouveau constructeur sont placés dans l'espace du tas; Les littéraux du programme, tels que 100, "Hello" et les constantes écrites directement sont placés dans la zone de stockage statique. L'espace de pile fonctionne le plus rapide mais est également très petit. Habituellement, un grand nombre d'objets sont placés dans l'espace du tas, et la mémoire entière, y compris la mémoire virtuelle sur le disque dur, peut être utilisée comme espace de tas.
String str = new String ("Hello");
Dans l'instruction ci-dessus, STR est placé sur la pile, l'objet de chaîne créé avec New est placé sur le tas et le "Hello" littéral est placé sur la zone de stockage statique.
Supplément: Une version plus récente de Java utilise une technologie appelée "analyse d'évasion" qui peut placer certains objets locaux sur la pile pour améliorer les performances opérationnelles des objets.
10. Quel est le Math.round (11.5) égal? Quel est le Math.round (-11,5) égal?
Réponse: La valeur de retour de Math.round (11.5) est de 12, et la valeur de retour de Math.round (-11.5) est -11. Le principe de l'arrondi est d'ajouter 0,5 au paramètre, puis de l'arrondir.
11. SWTICH peut-il agir sur l'octet, long acte sur la chaîne?
Réponse: Dans le premier JDK, dans Switch (EXPR), Expr peut être octet, court, char et int. À partir de la version 1.5, Java a introduit des types d'énuméations (enums) et Expr peut également être des énumérations, à partir de la version 1.7 de JDK, ainsi qu'une chaîne (chaîne). Le type long n'est pas autorisé.
12. Utilisez la méthode la plus efficace pour calculer 2 fois 8?
Réponse: 2 << 3 (le déplacement de 3 bits à gauche est équivalent à se multiplier par 2 à la puissance de 3, et déplacer 3 bits à droite équivaut à diviser par 2 à la puissance de 3).
Supplément: Lorsque nous réécrivons la méthode HashCode pour la classe que nous avons écrite, nous pouvons voir le code ci-dessous. En fait, nous ne comprenons pas très bien pourquoi nous utilisons une telle multiplication pour générer un code de hachage (code de hachage), et pourquoi ce nombre est-il un nombre premier, et pourquoi le nombre 31 est-il généralement sélectionné? Vous pouvez Baidu sur les réponses aux deux premières questions. Choisissez 31 car les opérations de décalage et de soustraction peuvent être utilisées au lieu de la multiplication, réalisant ainsi de meilleures performances. En parlant de cela, vous avez peut-être pensé à: 31 * num <==> (num << 5) - Num, le déplacement des 5 bits gauche équivaut à multiplier par 2 à la 5ème puissance (32) et à se soustraire est équivalent à multiplier par 31. Tous les VM peuvent effectuer automatiquement cette optimisation.
package com.loonstudio; classe publique Phonenumber {private int workcode; Préfixe de chaîne privée; Livre de lining à chaîne privée; @Override public int hashcode () {final int prime = 31; Int résultat = 1; result = prime * Result + AreaCode; result = prime * result + ((lineNumber == null)? 0: lineNumber.hashcode ()); result = prime * result + ((prefix == null)? 0: prefix.hashcode ()); Résultat de retour; } @Override public boolean equals (objet obj) {if (this == obj) return true; if (obj == null) return false; if (getClass ()! = obj.getClass ()) return false; Phonenumber Autre = (Phonenumber) obj; if (areacode! = autre.aacode) renvoie false; if (lineNumber == null) {if (autre.lineNumber! = null) return false; } else if (! lineNumber.equals (autre.lineNumber)) renvoie false; if (prefix == null) {if (autre.prefix! = null) return false; } else if (! prefix.equals (autre.prefix)) renvoie false; Retour Vrai; }} // Pourquoi poser des questions sur hovertree.com13. Y a-t-il une méthode de longueur () pour les tableaux? Y a-t-il une méthode Longueur () pour la chaîne?
Réponse: Le tableau n'a pas de méthode longueur (), mais a un attribut de longueur. La chaîne a une méthode Longueur (). En JavaScript, l'obtention de la longueur de la chaîne est obtenue via l'attribut de longueur, qui est facilement confondu avec Java.
14. En Java, comment sortir des multiples boucles imbriquées actuelles?
Réponse: Ajoutez une marque comme A avant la boucle la plus externe, puis utilisez Break A; Plusieurs boucles peuvent être brisées. (Java prend en charge les instructions Tagged Break and Continuer, et leurs fonctions sont un peu similaires aux instructions GOTO en C et C ++, mais tout comme éviter GOTO, vous devez éviter la pause étiquetée et continuer car elle ne rendra pas votre programme plus élégant, et souvent même avoir l'effet opposé, donc cette syntaxe est en fait mieux.)
15. Le constructeur peut-il être remplacé?
Réponse: Le constructeur ne peut pas être hérité, il ne peut donc pas être réécrit, mais il peut être surchargé.
16. Deux objets ont la même valeur (x.equals (y) == true), mais ils peuvent avoir des codes de hachage différents. Est-ce que c'est vrai?
Réponse: Non, si les deux objets x et y satisfont x.equals (y) == true, leur code de hachage devrait être le même. Java stipule la méthode Eqauls et la méthode de code de hash comme suit: (1) Si deux objets sont les mêmes (l'égalité de la méthode renvoie true), alors leurs valeurs de code de hash doivent être les mêmes; (2) Si les codes de hash des deux objets sont les mêmes, ils ne sont pas nécessairement les mêmes. Bien sûr, vous n'avez pas à faire au besoin, mais si vous violez les principes ci-dessus, vous constaterez que lorsque vous utilisez des conteneurs, le même objet peut apparaître dans la collection de jeux et l'efficacité de l'ajout de nouveaux éléments sera considérablement réduite (pour les systèmes utilisant le stockage de hachage, les conflits fréquents dans les codes de hachage entraîneront une forte baisse des performances d'accès).
Supplément: De nombreux programmes Java connaissent les méthodes d'égaux et de codes de hash, mais beaucoup de gens le savent. Dans le chef-d'œuvre de Joshua Bloch "Effective Java" (de nombreuses sociétés de logiciels, "Effective Java", "Java Programming Thoughts" et "Refactoring: Amélioration de la qualité du code existant" sont des livres incontournables par les programmeurs Java. Si vous ne l'avez pas lu, la méthode de la méthode Amazon. True), et la symétrie (x.equals (y) renvoie true, y.equals (x) doit également être, il doit retourner vrai), la transitivité (x.equals (y) et y.equals (z) doit également retourner vrai) et la cohérence (lorsque les informations de l'objet référencées par x et y ne sont pas modifiées, plusieurs appels vers X.equals (y) devraient obtenir la même valeur de retour) et pour toute référence non-non. Les astuces pour implémenter les méthodes d'égaux de haute qualité incluent: 1. Utilisez l'opérateur == pour vérifier "si le paramètre est une référence à cet objet"; 2. Utilisez l'opérateur d'instance OFF pour vérifier "si le paramètre est le type correct"; 3. Pour les attributs de clés de la classe, vérifiez si les attributs transmis à l'objet le correspondent; 4. Après avoir écrit la méthode égaux, demandez-vous si elle satisfait la symétrie, le transitoire et la cohérence; 5. Réécrivez toujours HashCode lors de la réécriture égaux; 6. Ne remplacez pas l'objet objet dans les paramètres de la méthode égaux par d'autres types, et n'oubliez pas l'annotation @Override lors de la réécriture.
17. La classe de chaînes peut-elle être héritée?
Réponse: La classe String est une classe finale et ne peut pas être héritée.
Supplément: hériter de la chaîne est un mauvais comportement en soi. La meilleure façon de réutiliser les types de chaînes est l'association (HAS-A) plutôt que l'héritage (IS-A).
18. Lorsqu'un objet est passé sous forme de paramètre à une méthode, cette méthode peut modifier les propriétés de l'objet et renvoyer le résultat modifié. Alors, est-ce un laissez-passer de valeur ou un laissez-passer de référence ici?
Réponse: c'est le transfert de valeur. Le langage de programmation Java ne transmet que des paramètres avec des valeurs. Lorsqu'une instance d'objet est transmise dans une méthode en tant que paramètre, la valeur du paramètre est une référence à l'objet. Les propriétés d'un objet peuvent être modifiées pendant le processus d'appel, mais la référence à l'objet ne changera jamais. En C ++ et C #, la valeur des paramètres passa peut être modifiée en passant des références ou en transférant les paramètres.
Supplément: il est vraiment gênant de ne pas passer des références en Java, qui n'a pas été améliorée dans Java 8. C'est précisément de cette façon qu'un grand nombre de classes de wrapper apparaissent dans le code écrit en Java (placer des références qui doivent être modifiées via des appels de méthode dans une classe de wrapper, puis transmettre l'objet de wrapper dans une méthode). Cette approche rendra le code gonflé, en particulier pour les développeurs qui se transforment de C et C ++ en programmeurs Java à intolérable.
19. Quelle est la différence entre String et StringBuilder et StringBuffer?
Réponse: La plate-forme Java fournit deux types de chaînes: String et StringBuffer / StringBuilder, qui peuvent stocker et manipuler des chaînes. Lorsque la chaîne est une chaîne en lecture seule, ce qui signifie que le contenu de la chaîne référencé par la chaîne ne peut pas être modifié. Les objets String représentés par les classes StringBuffer et StringBuilder peuvent être modifiés directement. StringBuilder a été introduit dans JDK 1.5. C'est exactement la même chose que la méthode de StringBuffer, la différence est qu'elle est utilisée dans un seul environnement fileté car tous les aspects ne sont pas modifiés par synchronisés, il est donc légèrement plus efficace que StringBuffer.
Supplément 1: Il y a une question d'entrevue: y a-t-il une situation où l'utilisation de + pour faire la concaténation de la chaîne est meilleure que d'appeler la méthode de l'appel de l'objet StringBuffer / StringBuilder? Si la chaîne obtenue après la connexion existe déjà dans la zone de stockage statique, l'utilisation de + pour la concaténation de la chaîne est meilleure que la méthode annexe de StringBuffer / StringBuilder.
Supplément 2: Ce qui suit est également une question d'entrevue, demandant à la sortie du programme de voir si vous pouvez donner la bonne réponse.
package com.lovo; // Pourquoi poser des questions sur la classe Hovertree. String b = new String ("Programming"); String c = "Program" + "Ming"; System.out.println (a == b); System.out.println (a == C); System.out.println (a.equals (b)); System.out.println (a.equals (c)); System.out.println (a.intern () == b.intern ()); }}20. La différence entre la surcharge et la remplacement. Les méthodes surchargées peuvent-elles être distinguées en fonction du type de retour?
Réponse: La surcharge et la réécriture de la méthode sont des moyens de mettre en œuvre le polymorphisme. La différence est que le premier met en œuvre le polymorphisme à temps de compilation, tandis que le second met en œuvre le polymorphisme d'exécution. La surcharge se produit dans une classe. Si une méthode avec le même nom a une liste de paramètres différente (différents types de paramètres, nombre différent de paramètres, ou les deux), il est considéré comme une surcharge; La réécriture se produit entre la sous-classe et la classe parent. La réécriture nécessite que la méthode réécrit de la sous-classe et la classe parent ont le même type de retour que la méthode réécrit de la classe parent, qui est un meilleur accès que la méthode réécrit de la classe parent, et ne peut pas déclarer plus d'exceptions que la méthode réécrit de la classe parent (principe de substitution de Rischer). La surcharge n'a pas d'exigences spéciales pour les types de retour.
Supplément: Huawei a posé une fois une question dans la question de l'interview: pourquoi ne pouvez-vous pas distinguer la surcharge en fonction du type de retour et racontez votre réponse!
21. Décrivez le principe et le mécanisme des fichiers de classe de chargement JVM?
Réponse: Le chargement des classes dans le JVM est implémenté par un chargeur de classe (Classloader) et ses sous-classes. Le chargeur de classe en Java est un important composant du système d'exécution Java, qui est responsable de la recherche et du chargement des classes dans les fichiers de classe lors de l'exécution.
Remplir:
1. En raison de la nature multiplateforme de Java, le programme de source Java compilé n'est pas un programme exécutable, mais un ou plusieurs fichiers de classe. Lorsqu'un programme Java doit utiliser une classe, le JVM garantit que la classe a été chargée, connectée (vérifiée, préparée et analysée) et initialisée. Le chargement de classe fait référence à la lecture des données du fichier de classe .class dans la mémoire. Habituellement, la création d'un tableau d'octets pour le lire dans le fichier .class, puis générer un objet de classe correspondant à la classe chargée. Une fois le chargement terminé, l'objet de classe est toujours incomplet, donc la classe n'est pas disponible pour le moment. Lorsque la classe est chargée, elle entre dans l'étape de connexion. Cette étape comprend trois étapes: Vérification, préparation (allocation de la mémoire pour les variables statiques et définition de la valeur initiale par défaut) et analyse (remplacer les références de symbole par des références directes). Enfin, le JVM initialise la classe, y compris: 1. Si la classe a une classe parent directe et que la classe n'a pas été initialisée, la classe parent sera initialisée en premier; 2. S'il y a des instructions d'initialisation dans la classe, ces instructions d'initialisation seront exécutées à leur tour.
2. Le chargement des classes est effectué par le chargeur de classe, qui comprend: Root Loder (bootstrap), le chargeur d'extension (extension), le chargeur système (système) et le chargeur de classe défini par l'utilisateur (sous-classe de java.lang.classloadher). À partir de JDK 1.2, le processus de chargement de classe adopte le mécanisme de délégation du père (PDM). PDM assure mieux la sécurité de la plate-forme Java. Dans ce mécanisme, le propre bootstrap de JVM est le chargeur racine, et d'autres chargeurs ont et n'ont qu'un seul chargeur de classe parent. Le chargement de classe demande d'abord le chargeur de classe parent à charger, et le chargeur de classe parent ne sera chargé que par son chargeur de sous-classe lorsqu'il est impuissant. Le JVM ne fournit pas de références à Bootstrap aux programmes Java. Voici quelques instructions pour plusieurs chargeurs de classe:
a) Bootstrap: il est généralement implémenté à l'aide du code local et est responsable du chargement de la bibliothèque de classe de base de base de JVM (RT.JAR);
b) Extension: Chargez la bibliothèque de classe à partir du répertoire spécifié par la propriété système java.ext.DIRS, et son chargeur parent est bootstrap;
c) Système: Également connu sous le nom de chargeur de classe d'application, sa classe parent est une extension. C'est le chargeur de classe le plus utilisé. Il enregistre les classes du répertoire spécifié par la variable d'environnement ClassPath ou l'attribut système java.class.path, et est le chargeur parent par défaut du chargeur défini par l'utilisateur.
22. Un caractère chinois peut-il être stocké dans une variable de type char? Pourquoi?
Réponse: Le type de char peut stocker un caractère chinois, car le codage utilisé dans Java est Unicode (aucun encodage spécifique n'est sélectionné, et les caractères sont directement utilisés dans le numéro de jeu de caractères, qui est la seule méthode unifiée). Un type de char prend 2 octets (16 bits), il n'est donc pas un problème de mettre un chinois.
Supplément: L'utilisation de Unicode signifie que les caractères ont des manifestations différentes à l'intérieur et à l'extérieur du JVM et sont tous deux Unicode à l'intérieur du JVM. Lorsque ce caractère est transféré de la JVM à l'extérieur (par exemple, stocké dans le système de fichiers), une conversion de codage est requise. Par conséquent, Java a des flux d'octets et des flux de caractères, ainsi que des flux de conversion qui convertissent entre les flux de caractères et les flux d'octets, tels que InputStreamReader et OutputStreamReader. Ces deux classes sont des classes d'adaptateurs entre les flux d'octets et les flux de caractères et entreprennent la tâche de codage de conversion; Pour les programmeurs C, pour terminer une telle conversion de codage, ils s'appuient probablement sur les caractéristiques de la mémoire partagée de l'Union (Union / Community) à réaliser.
23. Quelles sont les similitudes et les différences entre la classe abstraite et l'interface?
Réponse: Les classes abstraites et les interfaces ne peuvent pas être instanciées, mais les références aux classes abstraites et aux types d'interface peuvent être définies. Si une classe hérite d'une classe abstraite ou implémente une interface, elle doit implémenter toutes les méthodes abstraites, sinon la classe doit encore être déclarée comme une classe abstraite. Les interfaces sont plus abstraites que les classes abstraites, car les constructeurs peuvent être définis dans des classes abstraites, et il peut y avoir des méthodes abstraites et des méthodes concrètes, tandis que les constructeurs ne peuvent pas être définis dans les interfaces, et toutes les méthodes en elles sont des méthodes abstraites. Les membres des classes abstraits peuvent être privés, par défaut, protégés et publics, tandis que les membres des interfaces sont tous publics. Les variables membres peuvent être définies dans les classes abstraites, tandis que les variables des membres définies dans les interfaces sont en fait des constantes. Les classes avec des méthodes abstraites doivent être déclarées comme des classes abstraites et les classes abstraites n'ont pas nécessairement de méthodes abstraites.
24. Quelle est la différence entre les classes imbriquées statiques et les classes intérieures (classe intérieure)?
Réponse: La classe imbriquée statique est une classe intérieure déclarée statique, qui peut être instanciée sans s'appuyer sur des instances de classe externe. Les classes intérieures habituelles doivent être instanciées après l'instanciation de la classe externe, et la syntaxe est assez bizarre, comme indiqué ci-dessous.
package com.lovo; / ** * Classe de poker (un jeu de poker) Pourquoi demander Hovertree.com * * / classe publique Poker {String statique privé [] suites = {"Spade", "Rose", "Flower", "Cube"}; Faces statiques privées statiques = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; cartes de carte privée []; / ** * constructeur * * / public poker () {cartes = new carte [52]; for (int i = 0; i <suites.length; i ++) {for (int j = 0; j <faces.length; j ++) {cartes [i * 13 + j] = new card (suites [i], faces [j]); }}} / ** * shuffle (aléatoire hors de l'ordre) * * / public void shuffle () {for (int i = 0, len = cards.length; i <len; i ++) {int index = (int) (math.random () * len); Carte tempor = cartes [index]; cartes [index] = cartes [i]; cartes [i] = temp; }} / ** * Deal Card * @param index la position de l'accord * * / Public Card Deal (int index) {return cartes [index]; } / ** * Classe de carte (un morceau de poker) * [classe interne] * @author luo hao * * / public class card {private String Suite; // convient au visage privé; // Points Public Card (String Suite, int face) {this.suite = Suite; this.face = face; } @Override public String toString () {String FACEstr = ""; switch (face) {cas 1: facestr = "a"; casser; Cas 11: facestr = "j"; casser; Cas 12: facestr = "Q"; casser; Cas 13: facestr = "k"; casser; Default: facistr = string.valueof (face); } return Suite + FACEstr; }}} Classe de test:
package com.lovo; class pokerTest {public static void main (String [] args) {poker poker = new poker (); poker.shuffle (); // shuffle poker.card c1 = poker.deal (0); // sert la première carte // pour les cartes de classe interne non statiques // L'objet de la carte peut être créé uniquement via son objet de poker de classe externe poker.card c2 = poker.new card ("Red Heart", 1); // Créez une carte vous-même System.out.println (C1); // le premier système.out.println (C2); // Imprimer: Red Heart A}} // Pourquoi demander Hovertree.com25. Y aura-t-il une fuite de mémoire en Java? Veuillez le décrire brièvement.
RÉPONSE: En théorie, Java n'aura pas de fuites de mémoire car elle a un mécanisme de collecte des ordures (GC) (c'est également une raison importante pour laquelle Java est largement utilisé dans la programmation côté serveur); Cependant, dans le développement réel, il peut y avoir des objets inutiles mais accessibles, et ces objets ne peuvent pas être recyclés par GC et des fuites de mémoire se produiront. Un exemple est que les objets de la session d'Hibernate (cache de niveau un) sont persistants, et le collecteur de déchets ne recyclera pas ces objets, mais il peut y avoir des objets de poubelle inutiles dans ces objets. L'exemple suivant montre également la fuite de mémoire en Java:
package com.lovo; // Pourquoi poser des questions sur Hovertree.commport Java.util.arrays; Importer java.util.emptystackexception; classe publique MyStack <T> {Éléments privés T []; private int size = 0; Final statique privé int init_capacity = 16; public MyStack() { elements = (T[]) new Object[INIT_CAPACITY]; } public void push(T elem) { ensureCapacity(); elements[size++] = elem; } public T pop() { if(size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if(elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); }}}上面的代码实现了一个栈(先进后出(FILO))结构,乍看之下似乎没有什么明显的问题,它甚至可以通过你编写的各种单元测试。然而其中的pop方法却存在内存泄露的问题,当我们用pop方法弹出栈中的对象时,该对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,因为栈内部维护着对这些对象的过期引用(obsolete reference)。在支持垃圾回收的语言中,内存泄露是很隐蔽的,这种内存泄露其实就是无意识的对象保持。如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象,也不会处理该对象引用的其他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大影响,极端情况下会引发Disk Paging(物理内存与硬盘的虚拟内存交换数据),甚至造成OutOfMemoryError。
26、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
27、静态变量和实例变量的区别?
答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。在Java开发中,上下文类和工具类中通常会有大量的静态成员。
28、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?
答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,因此在调用静态方法时可能对象并没有被初始化。
29、如何实现对象克隆?
答:有两种方式:
1.实现Cloneable接口并重写Object类中的clone()方法;
2.实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下。
package com.lovo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class MyUtil { private MyUtil() { throw new AssertionError(); } public static <T> T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源} } //何问起hovertree.com下面是测试代码:
package com.lovo; import java.io.Serializable; /** * Human* @author Luo Hao* */ class Person implements Serializable { private static final long serialVersionUID = -9102017020286042305L; private String name; // Name private int age; // Age private Car car; // Car public Person(String name, int age, Car car) { this.name = name; this.age = age; this.car = car; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } } /** * Car class* @author Luo Hao* */ class Car implements Serializable { private static final long serialVersionUID = -5713945027627603702L; private String brand; // Brand private int maxSpeed; // Top speed public Car(String brand, int maxSpeed) { this.brand = brand; this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } @Override public String toString() { return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]"; } } //Why ask about hovertree.comclass CloneTest { public static void main(String[] args) { try { Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300)); Person p2 = MyUtil.clone(p1); // Deep cloning p2.getCar().setBrand("BYD"); // Modify the brand attributes of the cloned Person object p2-associated car object// The original Person object p1-associated car will not be affected in any way// Because when cloning Person object, the car object associated with it is also cloned System.out.println(p1); } catch (Exception e) { e.printStackTrace(); }}}注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。
30、GC 是什么?为什么要有GC?
答: GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
与垃圾回收相关的JVM参数:
-Xms / -Xmx --- 堆的初始大小/ 堆的最大大小
-Xmn --- 堆中年轻代的大小
-XX:-DisableExplicitGC --- 让System.gc()不产生任何作用
-XX:+PrintGCDetail --- 打印GC的细节
-XX:+PrintGCDateStamps --- 打印GC操作的时间戳
31、String s=new String(“xyz”);创建了几个字符串对象?
答:两个对象,一个是静态存储区的"xyz",一个是用new创建在堆上的对象。
32、接口是否可继承(extends)接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)?
答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。
33、一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
答:可以,但一个源文件中最多只能有一个公开类(public class)而且文件名必须和公开类的类名完全保持一致。
34、Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?
答:可以继承其他类或实现其他接口,在Swing编程中常用此方式来实现事件监听和回调。
35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?
答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。
36、Java 中的final关键字有哪些用法?
答: (1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
37、指出下面程序的运行结果:
class A{ static{ System.out.print("1"); } public A(){ System.out.print("2"); } } class B extends A{ static{ System.out.print("a"); } public B(){ System.out.print("b"); } } //Why ask about hovertree.compublic class Hello{ public static void main(String[] args){ A ab = new B(); ab = new B(); }}答:执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。
38、数据类型之间的转换:
1)如何将字符串转换为基本数据类型?
2)如何将基本数据类型转换为字符串?
répondre:
1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf(…)方法返回相应字符串
39、如何实现字符串的反转及替换?
答:方法很多,可以自己写实现也可以使用String或StringBuffer / StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示:
public static String reverse(String originStr) { if(originStr == null || originStr.length() <= 1) return originStr; return reverse(originStr.substring(1)) + originStr.charAt(0); } //何问起hovertree.com40、怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?
答:代码如下所示:
String s1 = "你好";String s2 = newString(s1.getBytes("GB2312"), "ISO-8859-1");41、日期和时间:
1)如何取得年月日、小时分钟秒?
2)如何取得从1970年1月1日0时0分0秒到现在的毫秒数?
3)如何取得某月的最后一天?
4)如何格式化日期?
答:操作方法如下所示:
1)创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值
2)以下方法均可获得该毫秒数:
Calendar.getInstance().getTimeInMillis(); System.currentTimeMillis(); //何问起hovertree.com
3)示例代码如下:
Calendar time = Calendar.getInstance(); time.getActualMaximum(Calendar.DAY_OF_MONTH); //何问起hovertree.com
4)利用java.text.DataFormat 的子类(如SimpleDateFormat类)中的format(Date)方法可将日期格式化。
42、打印昨天的当前时刻。
répondre:
public class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); System.out.println(cal.getTime()); } } //何问起hovertree.com43、比较一下Java 和JavaSciprt。
答: JavaScript 与Java是两个公司开发的不同的两个产品。Java 是原Sun 公司推出的面向对象的程序设计语言,特别适合于互联网应用程序开发;而JavaScript是Netscape公司的产品,为了扩展Netscape浏览器的功能而开发的一种可以嵌入Web页面中运行的基于对象和事件驱动的解释性语言,它的前身是LiveScript;而Java 的前身是Oak语言。
下面对两种语言间的异同作如下比较:
1)基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象(Object-Based)和事件驱动(Event-Driven)的编程语言。因而它本身提供了非常丰富的内部对象供设计人员使用;
2)解释和编译:Java 的源代码在执行之前,必须经过编译;JavaScript 是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行;
3)强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量声明,采用其弱类型。即变量在使用前不需作声明,而是解释器在运行时检查其数据类型;
4)代码格式不一样。
补充:上面列出的四点是原来所谓的标准答案中给出的。其实Java和JavaScript最重要的区别是一个是静态语言,一个是动态语言。目前的编程语言的发展趋势是函数式语言和动态语言。在Java中类(class)是一等公民,而JavaScript中函数(function)是一等公民。对于这种问题,在面试时还是用自己的语言回答会更加靠谱。
44、什么时候用assert?
答: assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后, assertion检查通常是关闭的。在实现中,断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式计算为false,那么系统会报告一个AssertionError。
断言用于调试目的:
assert(a > 0); // throws an AssertionError if a <= 0
断言可以有两种形式:
assert Expression1;
assert Expression1 : Expression2 ;
Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息。
断言在默认情况下是禁用的,要在编译时启用断言,需使用source 1.4 标记:
javac -source 1.4 Test.java
要在运行时启用断言,可使用-enableassertions 或者-ea 标记。
要在运行时选择禁用断言,可使用-da 或者-disableassertions 标记。
要在系统类中启用断言,可使用-esa 或者-dsa 标记。还可以在包的基础上启用或者禁用断言。可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。
45、Error 和Exception 有什么区别?
答: Error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
Supplement: During the interview with Motorola in 2005, I asked a question like "If a process reports a stack overflow run-time error, what's the most possible cause?", giving four options a. lack of memory; né write on an invalid memory space; c. recursive function calling; d. array index out of boundary. Java programs may also encounter StackOverflowError when running. This is an error that cannot be recovered, so I can only re-modify the code. The answer to this interview question is c. If you write recursion that cannot converge quickly, it is very likely to cause a stack overflow error, as shown below:
package com.lovo; public class StackOverflowErrorTest { public static void main(String[] args) { main(null); } } //何问起hovertree.com因此,用递归编写程序时一定要牢记两点:1. 递归公式;2. 收敛条件(什么时候就不再递归而是回溯了)。
46、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
答:会执行,在方法返回调用者前执行。Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C#中就从语法上规定不能做这样的事。
47、Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
答: Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java 中,每个异常都是一个对象,它是Throwable 类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java 的异常处理是通过5 个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throw)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;try用来指定一块预防所有“异常”的程序;catch 子句紧跟在try块后面,用来指定你想要捕捉的“异常”的类型;throw 语句用来明确地抛出一个“异常”;throws用来标明一个成员函数可能抛出的各种“异常”;finally 为确保一段代码不管发生什么“异常”都被执行一段代码;可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try 语句,“异常”的框架就放到栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种“异常”进行处理,栈就会展开,直到遇到有处理这种“异常”的try 语句。
48、运行时异常与受检异常有何异同?
答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,神作《Effective Java》中对异常的使用给出了以下指导原则:
不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
对可以恢复的情况使用受检异常,对编程错误使用运行时异常避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
优先使用标准的异常每个方法抛出的异常都要有文档保持异常的原子性不要在catch中忽略掉捕获到的异常
49、列出一些你常见的运行时异常?
répondre:
ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下表越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)
50、final, finally, finalize 的区别?
答: final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final 的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final 的方法也同样只能使用,不能在子类中被重写。finally:通常放在try…catch的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。
Ce qui précède est tout le contenu de cet article. I hope it will be helpful to everyone in the Java interview, and I hope everyone will support Wulin.com more.