1. What is the difference between JDK and JRE?
JDK: short for Java Development Kit, Java Development Kit provides a java development environment and running environment.
JRE: short for Java Runtime Environment, which provides the required environment for the operation of java.
Specifically, JDK actually includes JRE, javac compiler for compiling java source code, and many tools for Java program debugging and analysis. Simply put: if you need to run Java programs, just install JRE. If you need to write Java programs, you need to install JDK.
2. What is the difference between = = and equals
1) = = interpretation
The basic type and reference type = = have different effects, as shown below:
- Basic type: compares whether the values are the same;
- Reference type: compares whether references are the same;
Code example:
String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.out.println(x.equals(y)); // true System.out.println(x.equals(z)); // true
Code interpretation: because x and y point to the same reference, = = is also true, and the rewriting of the new String() method opens up memory space, so = = results in false, while equals always compares values, so the results are true.
2) equals interpretation
Equals is essentially = =, but String and Integer override the equals method and turn it into value comparison. Just look at the code below.
First, by default, equals compares an object with the same value. The code is as follows:
class Cat { public Cat(String name) { this.name = name; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Cat c1 = new Cat("Xiao Wang"); Cat c2 = new Cat("Xiao Wang"); System.out.println(c1.equals(c2)); // false
The output result was unexpected and turned out to be false? What's going on? Just look at the equals source code. The source code is as follows:
public boolean equals(Object obj) { return (this == obj); }
It turns out that equals is essentially = =.
The question is, why do two String objects with the same value return true? The code is as follows:
String s1 = new String("bachelor"); String s2 = new String("bachelor"); System.out.println(s1.equals(s2)); // true
Similarly, when we enter the equals method of String, we find the answer. The code is as follows:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
Originally, String rewrites the equals method of Object and changes the reference comparison to value comparison.
Summary: = = value comparison for basic types and reference for reference types; By default, equals is a reference comparison, but many classes have changed the equals method, such as String and Integer, into a value comparison. Therefore, generally, equals compares whether the values are equal.
3. If the hashCode() of two objects is the same, equals() must also be true, right
No, the hashCode() of the two objects is the same, and equals() is not necessarily true.
Code example:
String str1 = "conversation"; String str2 = "Heavily"; System.out.println(String.format("str1: %d | str2: %d", str1.hashCode(),str2.hashCode())); System.out.println(str1.equals(str2));
Results of execution:
str1: 1179395 | str2: 1179395 false
Code interpretation: obviously, the hashCode() of "call" and "chongdi" are the same, but the equals() is false, because in the hash table, the hashCode() is equal, that is, the hash values of the two key value pairs are equal. However, if the hash values are equal, the key value pairs may not be equal.
4. What are the characteristics of object-oriented?
Answer: object oriented features mainly include the following aspects:
1) Encapsulation
The state information of the object is hidden inside the object as much as possible, and only limited interfaces and methods are reserved to interact with the outside world, so as to avoid the destruction of the internal properties of the object by the outside world.
Access control characters are used in Java to protect access to classes, variables, methods and constructor methods. Java supports four different access rights.
Modifier | Current class | Same package | Subclass | Other packages |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
Class members do not write access modifiers. The default is default. By default, it is equivalent to public for other classes in the same package, and private for other classes not in the same package. protected is equivalent to public for subclasses, and private for classes not in the same package without parent-child relationship. In Java, the modifiers of external classes can only be public or default, and are members of classes (including inner classes) can have the above four modifiers.
2) Inherit
java creates hierarchical classes through inheritance, which can be understood as the process of an object obtaining properties from another object.
Class inheritance is a single inheritance, that is, a subclass can only have one parent class
The following practices are illegal:
public class extends Animal, Mammal{}
However, we can use multiple inheritance interfaces, such as:
public class Apple extends Fruit implements Fruit1, Fruit2{}
The two most commonly used keywords in inheritance are extensions (for basic and abstract classes) and implements (for interfaces).
Note: the child class has all the member variables of the parent class, but does not have access to the member variables of the parent class private, which ensures the encapsulation of the parent class.
The following is the implementation of inheritance using the keyword extends.
public class Animal { } public class Mammal extends Animal { } public class Reptile extends Animal { } public class Dog extends Mammal { }
By using the keyword extends, a subclass can inherit all the methods and properties of its parent class, but cannot use private methods and properties.
By using the instanceof operator, we can determine that an object is a classification of another object.
public class Dog extends Mammal { public static void main(String args[]) { Animal a = new Animal(); Mammal m = new Mammal(); Dog d = new Dog(); System.out.println(m instanceof Animal); System.out.println(d instanceof Mammal); System.out.println(d instanceof Animal); } }
The results are as follows:
truetruetrue
The Implements keyword is used when the class inherits the interface. In this case, the extends keyword cannot be used.
public interface Animal { } public class Mammal implements Animal { } public class Dog extends Mammal { }
You can use the instanceof operator to verify whether the MMAL and dog objects are an instance of the Animal class.
interface Animal { } class Mammal implements Animal { } public class Dog extends Mammal { public static void main(String args[]) { Mammal m = new Mammal(); Dog d = new Dog(); System.out.println(m instanceof Animal); System.out.println(d instanceof Mammal); System.out.println(d instanceof Animal); } }
The operation results are as follows:
truetruetrue
3) Polymorphism
Polymorphism is the ability of the same behavior to have multiple different forms or forms.
Polymorphism is the embodiment of many forms of objects
For example, when I go to the pet store and say "please give me a pet", the waiter can give me a kitten, dog or lizard. We say that the object of "pet" has polymorphism.
example
public interface Vegetarian { } public class Animal { } public class Deer extends Animal implements Vegetarian { }
Because the Deer class has multiple inheritance, it is polymorphic.
The only way to access an object is through a reference variable (compile time variable).
Reference variables can only have one type. Once declared, the type of reference variables cannot be changed.
Reference variables can not only be reset to other objects, provided that these objects are not declared final. You can also reference objects of the same type or compatible with it. It can be declared as a class type or an interface type.
Deer d = new Deer(); Animal a = d; Vegetarian v = d; Object o = d;
All reference variables d,a,v,o point to the same der object in the heap.
Let's look at the following example:
public class Animal { public String name = "Parent class name"; public void move() { System.out.println("Parent class move"); } public void content() { System.out.println("Parent class content"); } }
public class Bird extends Animal { public String name = "Subclass name"; @Override public void move() { // TODO Auto-generated method stub System.out.println("Subclass move"); } public void content() { System.out.println("Subclass content"); } }
public class Test { public static void main(String[] args) { Animal a = new Animal(); System.out.println(a.name); a.move(); a.content(); System.out.println("----------------------"); Animal b = new Bird(); // The upward transformation is automatically completed by the system // Compile time variable runtime variable System.out.println(b.name); b.move(); b.content(); System.out.println("----------------------"); Bird c = new Bird(); System.out.println(c.name); c.move(); c.content(); } }
Operation results:
Parent class name Parent class move Parent class content ----------------------Parent class name Subclass move Subclass content ----------------------Subclass name Subclass move Subclass content
Description: Bird class inherits Animal and rewrites its methods.
Because Animal b = new Bird(), the compile time variable and the run-time variable are different, polymorphism occurs. It can be seen from the final running results that the member variable name of the parent class and the two overridden methods of the child class are called.
As mentioned above, subclasses can call all non private methods and properties of the parent class. Because name is a String object, unlike methods, the domain of the object is not polymorphic. When a variable is referenced to access the instance variables it contains, the system always accesses the variables defined by its compile time type instead of its runtime type.
So the question is, if we change the member variable of Animal to private, will we call the member variable name of Bird class to print out?
That is, the system always accesses the variables defined by the compile time type.
Rewrite definition: the subclass rewrites the implementation process of the accessible methods of the parent class! Neither return value nor formal parameter can be changed. That is, the shell remains unchanged and the core is rewritten!
5. Is String the most basic data type?
String does not belong to the basic type. There are eight basic types: byte, boolean, char, short, int, float, long and double, while string belongs to object.
6,float f=3.4; Is it correct?
Answer: incorrect. 3.4 is a double precision number. Assigning a double to a float is a down casting (also known as narrowing), which will cause precision loss. Therefore, it is necessary to force the type conversion float f =(float)3.4; Or write as float f =3.4F;.
7,short s1 = 1; s1 = s1 + 1; Is there anything wrong? short s1 = 1; s1 += 1; Is there anything wrong?
Answer: for short, S1 = 1; s1 = s1+1; Since 1 is of type int, the result of s1+1 operation is also of type int. the type needs to be cast before it can be assigned to type short. While short S1 = 1; s1+= 1; It can be compiled correctly because s1+= 1; Equivalent to S1 = (short) (s1+1); There is an implicit cast.
8. What's the difference between int and Integer?
A: Java is an almost pure object-oriented programming language, but basic data types are introduced for programming convenience. However, in order to operate these basic data types as objects, Java has introduced the corresponding wrapper class for each basic data type, and the wrapper class of int is Integer. Since Java 5, the automatic boxing / unpacking mechanism has been introduced, so that the two can be converted to each other.
Java provides wrapper types for each primitive type:
- Primitive types: boolean, char, byte, short, int, long, float, double
- Packing type: Boolean, Character, Byte, Short, Integer, Long, Float, Double
class AutoUnboxingTest { public static void main(String[] args) { Integer a = new Integer(3); Integer b = 3; // Automatically boxing 3 to Integer type int c = 3; System.out.println(a == b); // false two references do not refer to the same object System.out.println(a == c); // true a is automatically unpacked into int type, and then compared with c } }
Recently, I also encountered an interview question, which is also related to automatic packing and unpacking. The code is as follows:
public class Test03 { public static void main(String[] args) { Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150; System.out.println(f1 == f2); System.out.println(f3 == f4); } }
If it is not clear, it is easy to think that both outputs are either true or false. First of all, it should be noted that the four variables f1, f2, f3 and f4 are Integer object references, so the following = = operation compares not values but references. What is the essence of packing? When we assign an int value to an Integer object, we will call the static method valueOf of the Integer class. If you look at the source code of valueOf, you will know what happened.
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
IntegerCache is an internal class of Integer. Its code is as follows:
/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
Simply put, if the value of the Integer literal is between - 128 and 127, the new Integer object will not be created, but the Integer object in the constant pool will be directly referenced. Therefore, the result of f1f2 in the above interview question is true, and the result of f3f4 is false.
**Reminder: * * the more seemingly simple the interview questions, the more mysterious they are. The interviewer needs to have quite deep skills.
9. What is the difference between & & and & &?
Similarities: & and & & can be used as operators of logical and to represent logical and.
difference:
(1) & & has the function of short circuit, while & does not have the function of short circuit.
(2) When the result of the expressions on both sides of the & operator is true, the whole operation result is true. When the first expression of the & & operator is false, the result is false and the second expression will not be evaluated.
(3) & can also be used as a bit operator. When the expressions on both sides of the & operator are not boolean type, & indicates bitwise and operation. We usually use 0x0f to perform & operation with an integer to obtain the lowest four bit bits of the integer. For ex amp le, the result of 0x31 & 0x0f is 0x01.
10,Math. What is round (11.5) equal to? Math. What is round (- 11.5) equal to?
Answer: math The return value of round (11.5) is 12, math The return value of round (- 11.5) is - 11. The principle of rounding is to add 0.5 to the parameter and then round it down.
11. Can switch work on byte, long and String?
A: before Java 5, in switch(expr), expr can only be byte, short, char and int. Starting from Java 5, enumeration types have been introduced into Java. Expr can also be enum type. Starting from Java 7, expr can also be String, but long is not allowed in all current versions.
12. Use the most efficient method to calculate 2 times 8?
A: 2 < < 3 (shifting 3 bits left is equivalent to multiplying 2 to the third power, and shifting 3 bits right is equivalent to dividing 2 to the third power).
**Add: * * when we rewrite the hashCode method for the class we write, we may see the following code, In fact, we don't quite understand why we use such multiplication to generate hash codes (hash code), and why is this number a prime number? Why do you usually choose the number 31? You can Baidu the answers to the first two questions. 31 is selected because you can use shift and subtraction instead of multiplication to get better performance. At this point, you may have thought: 31 * num is equivalent to (Num < < 5) - num, Shifting 5 bits to the left is equivalent to multiplying 2 to the 5th power, and then subtracting itself is equivalent to multiplying 31. Now VM S can automatically complete this optimization.
public class PhoneNumber { private int areaCode; private String prefix; private String lineNumber; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + areaCode; result = prime * result + ((lineNumber == null) ? 0 : lineNumber.hashCode()); result = prime * result + ((prefix == null) ? 0 : prefix.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PhoneNumber other = (PhoneNumber) obj; if (areaCode != other.areaCode) return false; if (lineNumber == null) { if (other.lineNumber != null) return false; } else if (!lineNumber.equals(other.lineNumber)) return false; if (prefix == null) { if (other.prefix != null) return false; } else if (!prefix.equals(other.prefix)) return false; return true; } }
13. Does the array have a length() method? Does String have a length() method?
A: there is no length () method for arrays in java, only the length attribute, array Length returns the length of the array. String has a length() method, and str.length() returns the length of the string.
14. In Java, how to jump out of the current multi nested loop?
Scheme 1: use tag
public static void main(String[] args) { System.out.println("Before marking"); ok: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { System.out.println("i=" + i + ",j=" + j); if (j == 5) break ok; } } System.out.println("After marking"); }
Tag is not recommended because it can easily break the execution order of code
Scheme 2: the result of the outer loop condition expression can be controlled by the inner loop body code
public static void main(String[] args) { System.out.println("Before marking"); boolean flag = true; for (int i = 0; i < 10; i++) { for (int j = 0; j < 10 && flag; j++) { System.out.println("i=" + i + ",j=" + j); if (j == 5) flag = false; } } System.out.println("After marking"); }
15. Can a constructor be overridden?
A: Rewriting occurs in subclasses and superclasses. The method name, parameter list, return value, access modifier and exception are the same. First of all, constructors cannot be inherited because each class name is different, and the constructor name is the same as the class name, which is certainly not inheritance. Therefore, since constructors cannot be inherited, they cannot be overridden, but they can be overloaded.
16. Can I inherit String class?
A: the String class is final and cannot be inherited.
**Add: * * inheriting String itself is a wrong behavior. The best way to reuse String types is Association (Has-A) and dependency (Use-A) rather than inheritance (Is-A).
17. What are the classes of operation strings in java? What's the difference between them?
The classes that operate on strings include: String, StringBuffer, and StringBuilder.
The difference between String and StringBuffer and StringBuilder is that String declares immutable objects. Each operation will generate a new String object, and then point the pointer to the new String object. StringBuffer and StringBuilder can operate on the basis of the original object. Therefore, it is best not to use String when the String content is often changed.
The biggest difference between StringBuffer and StringBuilder is that StringBuffer is thread safe and StringBuilder is non thread safe, but the performance of StringBuilder is higher than that of StringBuffer. Therefore, StringBuilder is recommended in single threaded environment and StringBuffer in multi-threaded environment.
Interview question 1 - under what circumstances is the performance of string connection with + operator better than calling the append method of StringBuffer/StringBuilder object?
Interview question 2 - please say the output of the following program.
class StringEqualTest { public static void main(String[] args) { String s1 = "Programming"; String s2 = new String("Programming"); String s3 = "Program"; String s4 = "ming"; String s5 = "Program" + "ming"; String s6 = s3 + s4; System.out.println(s1 == s2); System.out.println(s1 == s5); System.out.println(s1 == s6); System.out.println(s1 == s6.intern()); System.out.println(s2 == s2.intern()); } }
Add: to answer the above interview questions, two points need to be cleared: 1 The intern method of the String object will get the reference of the corresponding version of the String object in the constant pool (if there is a String in the constant pool and the equals result of the String object is true), if there is no corresponding String in the constant pool, the String will be added to the constant pool, and then the reference of the String in the constant pool will be returned; 2. The essence of the + operation of the String is to create a StringBuilder object for append operation, and then use the spliced StringBuilder object with tostri The ng method is treated as a String object, which can be treated with javap - C stringequaltest The class Command obtains the JVM bytecode instruction corresponding to the class file.
18. The difference between Overload and Override
First, overloading and rewriting are two different methods applied to two different scenarios:
Their respective characteristics:
Overload: first, it is located in a class or its subclass and has the same method name, but the method parameters are different, and the return value types can be the same or different.
(1) : method names must be the same
(2) : the parameter list of the method must be different.
(3) : access modifiers and return value types can be the same or different.
In fact, in simple terms: overloading is to write different methods for different situations. For example, in the same class, write different constructors to initialize different parameters.
Here is the code that demonstrates overloading:
public class Animal { public void bark(){ System.out.println("animal can bark"); } public void bark(String s){ System.out.println("animal"+ s +"can bark"); } public void bark(int i){ System.out.println("The animal number "+i+" can bark"); } public static void main(String[] args) { Animal animal=new Animal(); animal.bark(1); } }
override: it generally represents the relationship between subclasses and parent classes. Its main characteristics are: the method names are the same, the parameters are the same, but the specific implementation is different.
Overridden features:
(1) : the method name must be the same, and the return value type must be the same
(2) : the parameter list must be the same
(3) : the access permission cannot be lower than that of the overridden method in the parent class. For example, if a method of the parent class is declared public, overriding the method in the child class cannot be declared protected.
(4) : if the subclass and the parent class are in the same package, the subclass can override all methods of the parent class, except those declared as private and final.
(5) : constructor cannot be overridden,
To put it simply: the specific implementation class is not satisfied with the method implementation of the parent class. It needs to write a method that meets its own requirements.
public class Animal { public void bark() { System.out.println("animal can bark"); } }
public class Dog extends Animal { public void bark() { System.out.println("Dog can bark"); } public static void main(String[] args) { Dog dog = new Dog(); dog.bark(); } }
Rewriting: the subclass is dissatisfied with the specific implementation of the corresponding method of the parent class and needs to implement its own requirements according to its own requirements.
19. Describe the principle and mechanism of loading class files by JVM?
All classes in Java need to be loaded into the JVM by the class loader to run. The class loader itself is also a class, and its job is to read the class file from the hard disk to the memory. When writing programs, we hardly need to care about class loading, because these are implicitly loaded. Unless we have special usage, such as reflection, we need to explicitly load the required classes.
There are two kinds of loading methods:
1. Implicit loading: when the program encounters an object generated by new or other methods during operation, it implicitly calls the class loader to load the corresponding class into the jvm,
2. Explicit loading through class Forname () and other methods to explicitly load the required classes
The loading of Java classes is dynamic. It does not load all classes at one time and then run them. Instead, it ensures that the basic classes (such as base classes) for program operation are fully loaded into the jvm. As for other classes, they are loaded when necessary. This is, of course, to save memory overhead.
There are three Java class loaders, corresponding to the three types of Java:
- Bootstrap Loader: start the class loader, which is part of the virtual machine itself. Be responsible for loading the class libraries stored in the \ lib directory into the virtual machine. It cannot be directly referenced by Java programs. Responsible for loading System classes (refers to built-in classes, such as String, corresponding to the System class in c# and the class in C/C + + Standard Library)
- ExtClassLoader: responsible for loading extension classes (that is, inheritance classes and implementation classes)
- AppClassLoader: it is responsible for loading the class library specified on the user's ClassPath (class customized by the programmer)
Class loading in JVM is implemented by class loader and its subclasses. Class loader in Java is an important Java runtime system component, which is responsible for finding and loading classes in class files at runtime.
Due to the cross platform nature of Java, the compiled Java source program is not an executable program, but one or more class files. When a java program needs to use a class, the JVM ensures that the class has been loaded, connected (verified, prepared, and parsed), and initialized.
Class loading refers to the loading of classes The data in the class file is read into memory, usually by creating a byte array Class file, and then generate the class object corresponding to the loaded class. After loading, the class object is not complete, so the class is not available at this time.
When the class is loaded, it enters the connection phase, which includes
- Verification: to ensure that the information contained in the byte stream of the Class file meets the requirements of the current virtual machine and will not endanger the security of the virtual machine itself.
- Preparation: allocate memory for static variables and set default initial values.
- Resolve: replaces symbol references with direct references.
Finally, the JVM initializes the class, including:
- If the class has a direct parent class and the class has not been initialized, initialize the parent class first;
- If there are initialization statements in the class, they are executed in turn.
Class loading is completed by class loader, which includes BootStrap, Extension and Application class loader.
Starting from Java 2 (JDK 1.2), the class loading process adopts the two parent delegation model (PDM). PDM better ensures the security of the Java platform. In this mechanism, the Bootstrap provided by the JVM is the boot class loader, and other loaders have only one parent class loader. Class loading first requests the parent class loader to load. When the parent class loader is unable to do anything, it will be loaded by its child class loader. The JVM will not provide a reference to the Bootstrap to Java programs.
Parent delegation model: except for the top-level startup class loader, other loaders should have their own parent class loader. The parent-child relationship between class loaders is generally not implemented by inheritance, but reuses the code of the parent loader through composition.
Working process: if a class loader receives a class loading request, it will not try to load the class itself, but delegate the request to the parent class loader to complete.
This is true for class loaders at each level, so all load requests should eventually be sent to the top-level startup class loader,
Only when the parent loader reports that it cannot complete the load request (its search scope does not find the required class), the child loader will try to load by itself.
Why: Java classes have a prioritized hierarchy with their class loaders.
For example, Java Lang.Object, which is stored in rt.jar. No matter which class loader wants to load this class, it is finally delegated to the startup class loader for loading,
Therefore, the Object class is the same class in each class loader environment of the program.
Write a java class with the same name as the existing class in the rt.jar class library. It can be compiled normally, but it cannot be loaded and run.
Meaning of delegation mechanism - prevent multiple copies of the same bytecode in memory
For example, both classes A and B need to load the System class:
If you load your own without delegation, class A will load A System bytecode, and then class B will load A System bytecode, so there are two System bytecodes in memory.
If the delegation mechanism is used, it will recursively look up the parent class, that is, it is preferred to try loading with Bootstrap. If it cannot be found, it will go down again. The System here can be found and loaded in the Bootstrap. If class B also loads the System at this time, it starts from the Bootstrap. At this time, the Bootstrap finds that the System has been loaded, it can directly return to the System in the memory without reloading, so there is only one bytecode of the System in the memory.
Can you write a class called Java lang.System?
Answer: usually not, but alternative methods can be taken to meet this demand.
Explanation: in order to prevent us from writing the System class, the class loading adopts the delegation mechanism, which can ensure that the parent class loader takes priority. For the classes that the parent class loader can find, the child loader has no chance to load. The System class is loaded by the Bootstrap loader. Even if you rewrite it yourself, you always use the System provided by the Java System. The System class you write yourself has no chance to be loaded at all.
However, we can define a class loader to achieve this goal. In order to avoid the two parent delegation mechanism, this class loader must also be special. Since the three class loaders of the system load classes in a specific directory, if our own class loader is placed in a special directory, the system loader cannot be loaded, that is, it is finally loaded by our own loader.
20. Can a Chinese character be stored in a char variable? Why?
- char type variables are used to store Unicode encoded characters. The Unicode encoded character set contains Chinese characters,
- Therefore, of course, Chinese characters can be stored in char variables. However, if a particular Chinese character is not included in
- unicode coded character set, then this special Chinese character cannot be stored in this char type variable. supplement
- Note: unicode encoding takes two bytes, so char type variables also take two bytes.
- Note: Although the latter part of the answer is not a positive answer to the question, it is to show your knowledge and express yourself
- A thorough understanding of the problem can
- Answer some relevant knowledge, so that you know everything and say everything.
public class Test8 { public static void main(String[] args) { char ch = 'in'; System.out.println("char:" + ch); int max = Character.MAX_VALUE; int min = Character.MIN_VALUE; System.out.println(min + "<char<" + max);// 0<char<65535 } }
char indicates a range of 0 – 65535
21. What are the similarities and differences between abstract class and interface?
difference:
- The interface has only method definitions and no specific implementation. The class implementing the interface should implement all methods of the interface; Abstract classes can be defined and implemented;
- Interfaces and classes are implementation relationships, and classes can be implemented in multiple ways; Abstract classes and classes are inheritance relationships, and can only be inherited by one class.
- The members in the interface are all public abstract. There can be or no abstract methods in the class. Abstract methods need to be added
- There are no static methods in the interface, but there can be in the abstract class. "
- Constructors cannot be defined in interfaces, but in abstract classes.
Similarities:
- Can't be instantiated
- Abstract classes and interface types can be used as reference types
- If a class implements an interface or inherits an abstract class, it must implement all abstract methods, otherwise it is still an abstract class.
22. What are the differences between ordinary classes and abstract classes?
- Ordinary classes cannot contain abstract methods, and abstract classes can contain abstract methods.
- Abstract classes cannot be instantiated directly. Ordinary classes can be instantiated directly.
23. Must abstract classes have abstract methods?
No, abstract classes don't have to have abstract methods.
Example code:
abstract class Cat { public static void sayHi() { System.out.println("hi~"); } }
In the above code, the abstract class has no abstract methods, but it can run normally.
24. What is the difference between static nested class and Inner Class?
A: Static Nested Class is an internal class declared as static. It can be instantiated without relying on external class instances. Generally, internal classes can be instantiated only after external classes are instantiated. Its syntax looks strange, as shown below.
/** * Poker (a pair of poker) * */ public class Poker { private static String[] suites = {"spade", "heart", "Grass flower", "block"}; private static int[] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; private Card[] cards; /** * constructor * */ public Poker() { cards = new Card[52]; for(int i = 0; i < suites.length; i++) { for(int j = 0; j < faces.length; j++) { cards[i * 13 + j] = new Card(suites[i], faces[j]); } } } /** * Shuffle (random disorder) * */ public void shuffle() { for(int i = 0, len = cards.length; i < len; i++) { int index = (int) (Math.random() * len); Card temp = cards[index]; cards[index] = cards[i]; cards[i] = temp; } } /** * Licensing * @param index Licensing position * */ public Card deal(int index) { return cards[index]; } /** * Cards (one poker) * [Internal class] * */ public class Card { private String suite; // Decor private int face; // point public Card(String suite, int face) { this.suite = suite; this.face = face; } @Override public String toString() { String faceStr = ""; switch(face) { case 1: faceStr = "A"; break; case 11: faceStr = "J"; break; case 12: faceStr = "Q"; break; case 13: faceStr = "K"; break; default: faceStr = String.valueOf(face); } return suite + faceStr; } } }
Test code:
class PokerTest { public static void main(String[] args) { Poker poker = new Poker(); poker.shuffle(); // shuffle the cards Poker.Card c1 = poker.deal(0); // Deal the first card // For non static inner class Card // A Card object can only be created through its external Class Poker object Poker.Card c2 = poker.new Card("Hearts", 1); // Create a card yourself System.out.println(c1); // The first card after the shuffle System.out.println(c2); // Print: red heart A } }
Interview question - where does the following code produce compilation errors?
class Outer { class Inner {} public static void foo() { new Inner(); } public void bar() { new Inner(); } public static void main(String[] args) { new Inner(); } }
Note: the creation of non static internal class objects in Java depends on their external class objects. In the above interview questions, foo and main methods are static methods. There is no this in the static method, that is, there is no so-called external class object, so it is impossible to create internal class objects. If you want to create internal class objects in static methods, you can do this:
new Outer().new Inner();
25. Is there a memory leak in Java? Please briefly describe it.
Memory leak means that objects or variables that are no longer used are always occupied in memory.
Theoretically, Java has a GC garbage collection mechanism, that is, objects that are no longer used will be automatically recycled by GC and automatically cleared from memory.
However, even so, Java still has memory leaks,
① Memory leaks are likely to occur when long-lived objects hold references to short-lived objects.
Although the short life cycle object is no longer needed, it cannot be recycled because the long life cycle object holds its reference. This is the scenario of memory leakage in Java. Generally speaking, the programmer may create an object and never use it in the future, but the object is always referenced, That is, the object is useless but can not be recycled by the garbage collector. This is a possible memory leak in Java. For example, in the cache system, we load an object into the cache (for example, in a global map object), and then never use it. This object has been referenced by the cache but is no longer used.
Check the memory leak in java. Make sure that the program completely executes all branches until the end of the program, and then see whether an object has been used. If not, it can be determined that the object belongs to memory leak.
If the method of an instance object of an external class returns an instance object of an internal class, the internal class object is referenced for a long time. Even if the external class instance object is no longer used, because the internal class persists the instance object of the external class, the external class object will not be garbage collected, which will also cause memory leakage.
② After an object is stored in the HashSet set, you cannot modify the fields in the object that participate in the calculation of hash value. Otherwise, the hash value of the object after modification is different from the hash value originally stored in the HashSet set. In this case, Even if the contains method uses the current reference of the object as a parameter to retrieve the object in the HashSet collection, it will return the result that the object cannot be found, which will lead to the failure to delete the current object separately from the HashSet collection, resulting in memory leakage.
26. Can abstract methods be static, native, and synchronized at the same time?
A: none. Abstract methods need subclass rewriting, while static methods cannot be rewritten, so the two are contradictory. Local methods are implemented by local code (such as C code), while abstract methods are not implemented, which is also contradictory. synchronized is related to the implementation details of methods. Abstract methods do not involve implementation details, so they are also contradictory.
27. Differences between static variables and instance variables.
In Java, static variables and instance variables can be collectively referred to as member variables. First, understand what static variables are, what instance variables are, and the form they define. Static variables are also called class variables. They are independent of variables other than methods and are decorated with static. Instance variables are also independent of variables other than methods, but there is no static modification.
for instance:
public class StaticTest { private static int staticInt = 2;//Static variable private int random = 2;//Instance variable public StaticTest() { staticInt++; random++; System.out.println("staticInt = "+staticInt+" random = "+random); } public static void main(String[] args) { StaticTest test = new StaticTest(); StaticTest test2 = new StaticTest(); } }
See the above code, you can think about the test results.
The correct answer is published below:
staticInt = 3 random = 3 staticInt = 4 random = 3
Is it what you think? The above example well explains the difference between static variables and instance variables.
Here comes the dry goods. Pay attention to keep them.
The differences are summarized as follows:
An instance variable belongs to the property of an object. An instance object must be created before the instance variable can be allocated space and used. Combined with the example given above. Every time an instance object is created, a random is assigned. The random values between instance objects do not affect each other, so it can explain why the two output random values are the same.
Static variables do not belong to an instance object, but to the whole class. As long as the program loads the bytecode of the class without creating any instance objects, the static variables will be allocated space and can be used. Combined with the examples given above, no matter how many instance objects are created, only one staticInt variable is always allocated, and staticInt will be added every time an instance object is created.
In short, instance variables can only be used through this object after an object is created; Static variables can be referenced directly using the class name (if the instance object exists, it can also be referenced through the instance object).
In fact, this can also explain why static modified methods can not be called after the instance object is created. The method without static modification must be associated with the object. An object must be created before method calls can be made on the object.
28. Can I call a non static method from within a static method?
A: No, static methods can only access static members, because the object must be created before calling non static methods. When calling static methods, the object may not be initialized.
29. How to implement object cloning?
A: there are two ways:
1). Implement the clonable interface and override the clone() method in the Object class;
2). The Serializable interface is implemented to realize cloning through object serialization and deserialization, which can realize real deep cloning. The code is as follows.
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class MyUtil { private MyUtil() { throw new AssertionError(); } @SuppressWarnings("unchecked") public static <T extends Serializable> 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(); // Note: calling the close method of ByteArrayInputStream or ByteArrayOutputStream object has no meaning // These two memory based streams can release resources as long as the garbage collector cleans up objects, which is different from the release of external resources such as file streams } }
Here is the test code:
/** * human beings * */ class Person implements Serializable { private static final long serialVersionUID = -9102017020286042305L; private String name; // full 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 + "]"; } }
/** * Cars * */ 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 + "]"; } }
class 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 attribute of the car object p2 associated with the cloned Person object // The car associated with the original Person object p1 will not be affected // Because when cloning the Person object, its associated car object is also cloned System.out.println(p1); } catch (Exception e) { e.printStackTrace(); } } }
**Note: * * cloning based on serialization and deserialization is not only deep cloning, but more importantly, it can check whether the Object to be cloned supports serialization through generic restriction. This check is completed by the compiler rather than throwing an exception at runtime. This scheme is obviously better than cloning objects using the clone method of Object class. It's always better to expose problems at compile time than to leave them at run time.
30. What is GC? Why GC?
A: GC means garbage collection. Memory processing is a place where programmers are prone to problems. Forgetting or wrong memory recycling will lead to program or system instability or even crash. The GC function provided by java can automatically monitor whether the object exceeds the scope, so as to achieve the purpose of automatic memory recycling, The Java language does not provide a display operation method to free allocated memory. Java programmers don't have to worry about memory management because the garbage collector manages it automatically. To request garbage collection, you can call one of the following methods: system GC () or runtime getRuntime(). GC (), but the JVM can mask the garbage collection calls displayed.
Garbage collection can effectively prevent memory leakage and effectively use available memory. The garbage collector usually runs as a separate low priority thread to clear and recycle the dead or unused objects in the memory heap under unpredictable circumstances. Programmers cannot call the garbage collector to garbage collect an object or all objects in real time. In the early days of the birth of Java, garbage collection was one of the biggest highlights of Java, because server-side programming needed to effectively prevent memory leakage. However, over time, Java's garbage collection mechanism has become something criticized. Mobile intelligent terminal users usually think that iOS system has a better user experience than Android system. One of the deep-seated reasons is the unpredictability of garbage collection in Android system.
**Add: * * there are many garbage collection mechanisms, including generational replication garbage collection, tag garbage collection, incremental garbage collection, etc. Standard Java processes have both stacks and heaps. The stack holds the original local variables, and the heap holds the objects to be created. The basic algorithm for heap memory recycling and reuse in the Java platform is called marking and clearing, but Java has improved it by adopting "generational garbage collection". This method will divide the heap memory into different areas according to the life cycle of Java objects. During garbage collection, objects may be moved to different areas:
- Eden: This is the area where objects were originally born, and for most objects, this is the only area where they have existed.
- Survivor: objects that survive from the garden of Eden will be moved here.
- Tenured: This is the destination of surviving objects old enough. The minor GC process will not touch this place. When the younger generation collection could not put objects in the tenured, a major GC would be triggered. Compression may also be involved here to make enough space for large objects.
JVM parameters related to garbage collection:
- -Xms / -Xmx - initial size of heap / maximum size of heap
- -Xmn - the size of the younger generation in the heap
- -20: - disableexplicitgc - let system GC () has no effect
- -20: + printgcdetails - print GC details
- -20: + printgcdatestamps - print timestamp of GC operation
- -20: Newsize / XX: maxnewsize - set Cenozoic size / maximum Cenozoic size
- -20: Newratio - you can set the ratio of the old generation to the new generation
- -20: Printtenuringdistribution - sets the age distribution of objects in the survivor park after each new generation GC
- -20: Initialtenuringthreshold / - XX: maxtenuringthreshold: sets the initial value and maximum value of the threshold for the elderly generation
- -20: Targetsurvivorratio: sets the target utilization rate of the surviving area
31,String s = new String(“xyz”); How many string objects were created?
A: there are two objects, one is the "xyz" in the static area, and the other is the object created on the heap with new.
32. Can the interface extend the interface? Can the abstract class implement the interface? Can the abstract class inherit the concrete class?
A: interfaces can inherit interfaces and support multiple inheritance. Abstract classes can implement interfaces, and abstract classes can inherit concrete classes or abstract classes.
33. Can a ". java" source file contain multiple classes (not internal classes)? What are the restrictions?
A: Yes, but there can be at most one public class in a source file, and the file name must be completely consistent with the class name of the public class.
34. Can anonymous inner class inherit other classes? Can I implement the interface?
A: you can inherit other classes or implement other interfaces. This method is commonly used in Swing programming and Android development to realize event listening and callback.
35. Can an internal class reference the members of its containing class (external class)? Are there any restrictions?
A: an internal class object can access the members of the external class object that created it, including private members.
36. What are the usages of the final keyword in Java?
A: (1) modifier class: indicates that this class cannot be inherited; (2) Modifier method: indicates that the method cannot be overridden; (3) Modified variable: indicates that the variable can only be assigned once, and the value cannot be modified (constant).
37. Indicate the running results of the following programs.
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"); } } public class Hello { public static void main(String[] args) { A ab = new B(); ab = new B(); } }
Answer: implementation result: 1a2b2b. When the object is created, the calling sequence of the constructor is to initialize the static member first, then call the parent class constructor, then initialize the non static member, and finally call the self constructor.
**Tip: * * if you can't give the correct answer to this question, it means that you haven't fully understood the Java class loading mechanism in question 21. Take a look again quickly.
38. Conversion between data types:
-How do I convert a string to a basic data type?
-How do I convert a basic data type to a string?
Answer:
- Call the method parseXXX(String) or valueOf(String) in the wrapper class corresponding to the basic data type to return the corresponding basic type;
- One method is to connect (+) the basic data type with the empty String ("") to obtain its corresponding String; the other method is to call the valueOf() method in the String class to return the corresponding String
39. How to reverse a string?
Answer: use the reverse() method of StringBuilder or stringBuffer.
Example code:
// StringBuffer reverse StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("abcdefg"); System.out.println(stringBuffer.reverse()); // gfedcba // StringBuilder reverse StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("abcdefg"); System.out.println(stringBuilder.reverse()); // gfedcba
40. How to convert a GB2312 encoded string to an ISO-8859-1 encoded string?
Answer: the code is as follows:
String s1 = "Hello"; String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");
41. Date and time:
-How to get the date, hour, minute and second?
-How to get the number of milliseconds from 0:0:0 on January 1, 1970 to the present?
-How to get the last day of a month?
-How do I format dates?
Answer:
Question 1: create Java util. Calendar instance, call its get() method, pass in different parameters to get the value corresponding to the parameter. Java. Net can be used in Java 8 time. Localdatetimer. The code is as follows.
public class DateTimeTest { public static void main(String[] args) { Calendar cal = Calendar.getInstance(); System.out.println(cal.get(Calendar.YEAR)); System.out.println(cal.get(Calendar.MONTH)); // 0 - 11 System.out.println(cal.get(Calendar.DATE)); System.out.println(cal.get(Calendar.HOUR_OF_DAY)); System.out.println(cal.get(Calendar.MINUTE)); System.out.println(cal.get(Calendar.SECOND)); // Java 8 LocalDateTime dt = LocalDateTime.now(); System.out.println(dt.getYear()); System.out.println(dt.getMonthValue()); // 1 - 12 System.out.println(dt.getDayOfMonth()); System.out.println(dt.getHour()); System.out.println(dt.getMinute()); System.out.println(dt.getSecond()); } }
Question 2: the number of milliseconds can be obtained by the following methods.
Calendar.getInstance().getTimeInMillis(); System.currentTimeMillis(); Clock.systemDefaultZone().millis(); // Java 8
Question 3: the code is shown below.
Calendar time = Calendar.getInstance(); time.getActualMaximum(Calendar.DAY_OF_MONTH);
Question 4: using Java text. The format(Date) method in a subclass of dataformat, such as the SimpleDateFormat class, formats the date. Java. Net can be used in Java 8 time. format. Datetimeformatter to format the time and date. The code is as follows.
import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Date; class DateFormatTest { public static void main(String[] args) { SimpleDateFormat oldFormatter = new SimpleDateFormat("yyyy/MM/dd"); Date date1 = new Date(); System.out.println(oldFormatter.format(date1)); // Java 8 DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd"); LocalDate date2 = LocalDate.now(); System.out.println(date2.format(newFormatter)); } }
Add: Java's time and date API has always been criticized. In order to solve this problem, Java 8 has introduced a new time and date API, including LocalDate, LocalTime, LocalDateTime, Clock, Instant and other classes. The design of these classes uses invariant patterns, so they are thread safe. If you don't understand these contents, you can refer to my other article 2021 latest Java Concurrent Programming interview questions.
42. Print the current time of yesterday.
Answer:
import java.util.Calendar; class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); System.out.println(cal.getTime()); } }
In Java 8, you can use the following code to achieve the same function.
import java.time.LocalDateTime; class YesterdayCurrent { public static void main(String[] args) { LocalDateTime today = LocalDateTime.now(); LocalDateTime yesterday = today.minusDays(1); System.out.println(yesterday); } }
43. Compare Java and Java sciprt.
A: JavaScript and Java are two different products developed by the two companies. Java is an object-oriented programming language launched by the original Sun Microsystems company, which is especially suitable for Internet application development; JavaScript is a product of Netscape company. In order to expand the function of Netscape browser, it is an object-based and event driven explanatory language that can be embedded in Web pages. The predecessor of JavaScript is LiveScript; The predecessor of Java is Oak language.
The similarities and differences between the two languages are compared as follows:
- Object based and object-oriented: Java is a real object-oriented language. Even when developing simple programs, objects must be designed; JavaScript is a scripting language, which can be used to make complex software that has nothing to do with the network and interacts with users. It is an Object-Based and event driven programming language, so it itself provides very rich internal objects for designers to use.
- Interpretation and compilation: Java source code must be compiled before execution. JavaScript is an interpretative programming language. Its source code does not need to be compiled and is interpreted and executed by the browser. (almost all current browsers use JIT (just in time compilation) technology to improve the running efficiency of JavaScript)
- Strongly typed variables and weakly typed variables: Java adopts strongly typed variable checking, that is, all variables must be declared before compilation; Variables in JavaScript are weakly typed, and can not be declared even before using variables. The JavaScript interpreter checks and infers their data types at run time.
- The code format is different.
44. When to use assert ion?
A: assertion is a common debugging method in software development. Many development languages support this mechanism. Generally speaking, assertions are used to ensure the most basic and critical correctness of programs. Assertion checking is usually turned on during development and testing. In order to ensure the efficiency of program execution, assertion checking is usually turned off after software release. An assertion is a statement containing a Boolean expression, which is assumed to be true when executed; If the value of the expression is false, an assertion error is reported. The use of assertions is shown in the following code:
assert(a > 0); // throws an AssertionError if a <= 0
Assertions can take two forms:
assert Expression1;
assert Expression1 : Expression2 ;
Expression1 should always produce a Boolean value.
Expression2 can be any expression that yields a value; This value is used to generate a string message that displays more debugging information.
To enable assertions at run time, you can use the - enableassertions or - ea tag when starting the JVM. To choose to disable assertions at runtime, you can use the - da or - disableassertions flag when starting the JVM. To enable or disable assertions in a system class, use the - esa or - dsa tag. Assertions can also be enabled or disabled on a package basis.
**Note: * * assertions should not change the state of the program in any way. In short, if you want to prevent code execution when certain conditions are not met, you can consider using assertions to prevent it.
45. What is the difference between Error and Exception?
A: first of all, Exception and Error inherit from the Throwable class. In Java, only instances of Throwable type can be thrown or caught. It is the basic component type of Exception handling mechanism.
Exception and Error embody two ways of exception handling in JAVA language.
Exception is a predictable exception in the operation of java programs. We can get this exception and handle it outside the business.
Error is an unexpected exception in the running of java programs. After this exception occurs, it will directly lead to the unhandled or unrecoverable situation of the JVM. Therefore, such exceptions cannot be captured, such as OutOfMemoryError, NoClassDefFoundError, etc.
Exceptions are divided into checking exceptions and non checking exceptions. The two fundamental differences are that checking exceptions must be caught by using try catch (such as IOException Exception) when writing code. Non checking exceptions can ignore capture operations (such as ArrayIndexOutOfBoundsException) when writing code. Such exceptions can be avoided by specification during code writing or use.
46. There is a return statement in try {}. Will the code in finally {} immediately after the try be executed and when, before or after return?
A: it will be executed before the method returns to the caller.
**Note: * * it is not good to change the return value in finally, because if there is a finally code block, the return statement in try will not immediately return the caller, but record the return value. After the finally code block is executed, it will return its value to the caller, and then if the return value is modified in finally, it will return the modified value. Obviously, returning or modifying the return value in finally will cause great trouble to the program. C # directly uses compilation errors to prevent programmers from doing such dirty things. In Java, you can also raise the syntax check level of the compiler to generate warnings or errors. You can set it in Eclipse as shown in the figure, It is strongly recommended that this be set as a compilation error.
47. How to handle exceptions in the Java language? How to use the keywords: throws, throw, try, catch and finally?
A: Java handles exceptions through an object-oriented method, classifies various exceptions, and provides a good interface. In Java, each exception is an object that is an instance of the Throwable class or its subclass. When a method has an exception, it will throw an exception object, which contains exception information. The method calling this object can catch the exception and handle it. Java exception handling is implemented through five Keywords: try, catch, throw, throws and finally. Generally, try is used to execute a program, If the system throws an exception object, you can catch it by its type, or by always executing code blocks (finally) to handle; try is used to specify a program to prevent all exceptions; catch clause immediately after the try block is used to specify the type of exception you want to catch; throw statement is used to explicitly throw an exception; throws is used to declare all kinds of exceptions that a method may throw (of course, moaning without illness is allowed when declaring exceptions); finally, to ensure that a piece of code will be executed no matter what exception occurs; try statements can be nested. Whenever a try statement is encountered, the exception structure will be put into the exception stack until all try statements are completed. If the next level of try statement does not handle an exception, the exception stack will be executed out of the stack Operation until a try statement to handle this exception is encountered or the exception is finally thrown to the JVM.
48. What are the similarities and differences between runtime exceptions and detected exceptions?
A: exception indicates the abnormal state that may occur during program operation. Runtime exception indicates the exception that may be encountered in the normal operation of virtual machine. It is a common operation error. It will not occur as long as the program is designed without problems. The detected exception is related to the context in which the program runs. Even if the program design is correct, it may still be caused by problems in use. The java compiler requires that methods must declare that they throw possible checked exceptions, but it does not require that they declare that they throw uncapped runtime exceptions. Exception, like inheritance, is often abused in object-oriented programming_ Effective Java_ The following guidelines are given for the use of exceptions:
- Do not use exception handling for normal control flow (a well-designed API should not force its callers to use exceptions for normal control flow)
- Use checked exceptions for recoverable situations and run-time exceptions for programming errors
- Avoid unnecessary use of detected exceptions (some state detection methods can be used to avoid exceptions)
- Standard exceptions are preferred
- The exception thrown by each method must be documented
- Maintain abnormal atomicity
- Don't ignore caught exceptions in catch
49. List some common runtime exceptions?
Answer:
- java.lang.NullPointerException. The explanation of this exception is that "the program encounters a null pointer". In short, it calls an uninitialized object or a nonexistent object. This error often occurs in the operations of creating pictures and calling arrays, such as uninitialized pictures or path errors during picture creation.
- java.lang.ClassNotFoundException. The explanation of the exception is "the specified class does not exist". Here, we mainly consider whether the class name and path are correct
- java.lang.ArrayIndexOutOfBoundsException. The explanation of this exception is "array subscript out of bounds". At present, most programs operate on arrays. Therefore, when calling arrays, you must carefully check whether the subscript you call exceeds the range of arrays. Generally speaking, It is not easy to make such errors in display (i.e. using constant as subscript) calls, but it is often wrong in implicit (i.e. using variable as subscript) calls
- java.lang.NoSuchMethodError, the method has no error. This error is thrown when an application attempts to call a method of a class, but the definition of the method does not exist in the definition of the class.
- java.lang.IndexOutOfBoundsException, index out of bounds exception. This exception is thrown when the index value accessing a sequence is less than 0 or greater than or equal to the sequence size.
- java.lang.NumberFormatException, number format exception. This exception is thrown when an attempt is made to convert a String to the specified numeric type, and the String does not meet the format required by the numeric type.
- java.sql.SQLException, Sql statement execution exception
- java.io.IOException, input / output exception
- java.lang.IllegalArgumentException, method parameter error
- java.lang.IllegalAccessException, no access permission exception
50. Explain the difference between final, finally and finalize.
Answer:
- Final: modifier (keyword) there are three uses: if a class is declared as final, it means that it cannot derive new subclasses, that is, it cannot be inherited. Therefore, it is the opposite of abstract. Declaring variables as final can ensure that they will not be changed in use. Variables declared as final must be given initial values at the time of declaration, and can only be read and unmodified in future references . Methods declared as final can also be used only and cannot be overridden in subclasses.
- Finally: usually, the structure behind try... catch... Always executes the code block, which means that the code here can be executed as long as the JVM is not closed, and the code that releases external resources can be written in the finally block.
- Finalize: the method defined in the Object class. In Java, it is allowed to use the finalize() method to do the necessary cleaning work before the garbage collector clears the Object from memory. This method is called by the garbage collector when destroying objects. You can clean up system resources or perform other cleaning work by overriding the finalize() method.
51. Class ExampleA inherits Exception, and class ExampleB inherits ExampleA.
There are the following code snippets:
try { throw new ExampleB("b") } catch(ExampleA e){ System.out.println("ExampleA"); } catch(Exception e){ System.out.println("Exception"); }
What is the output of executing this code?
Answer: output: ExampleA. (according to the Richter substitution principle [where the parent type can be used, the child type must be used], the catch block that grabs the exception of type ExampleA can catch the exception of type ExampleB thrown in the try block)
Interview question - say the running results of the following code. (the source of this topic is the Book Java programming ideas)
class Annoyance extends Exception {} class Sneeze extends Annoyance {} class Human { public static void main(String[] args) throws Exception { try { try { throw new Sneeze(); } catch ( Annoyance a ) { System.out.println("Caught Annoyance"); throw a; } } catch ( Sneeze s ) { System.out.println("Caught Sneeze"); return ; } finally { System.out.println("Hello World!"); } } }
52. Do List, Set and Map inherit from the Collection interface?
A: list and set are yes, but map is not. Map is a key value pair mapping container, which is obviously different from list and set. Set stores scattered elements and does not allow duplicate elements (the same is true for sets in Mathematics). List is a container with linear structure, which is suitable for accessing elements by numerical index.
53. Describe the storage performance and characteristics of ArrayList, Vector and LinkedList.
A: both ArrayList and vector use array to store data. The number of elements in this array is larger than the actual stored data for adding and inserting elements. They both allow direct indexing of elements by sequence number, but inserting elements involves memory operations such as array element movement, so indexing data is fast and inserting data is slow. The methods in vector add synchronized modification, Therefore, vector is a thread safe container, but its performance is worse than ArrayList, so it is already a legacy container in Java. LinkedList uses a two-way linked list for storage (the scattered memory units in the memory are associated through additional references to form a linear structure that can be indexed by serial number. This chained storage mode has higher memory utilization than the continuous storage mode of array). The data indexed by serial number needs to be traversed forward or backward, but only the front and rear items of this item need to be recorded when inserting data, so the data is inserted Faster. Vector is a legacy container (containers provided in earlier versions of Java, in addition, Hashtable, Dictionary, BitSet, Stack and Properties are legacy containers), which are not recommended. However, since ArrayList and LinkedListed are non thread safe, if multiple threads operate on the same container, they can be synchronized through the synchronizedList method in tool class Collections Convert it into a thread safe container and then use it (this is an application of decoration mode. An existing object is passed into the constructor of another class to create a new object to enhance the implementation).
**Add: * * the properties class and Stack class in the legacy container have serious design problems. Properties is a special key value pair mapping in which both keys and values are strings. In design, it should be associated with a Hashtable and set its two generic parameters to String type. However, the properties in the Java API directly inherit the Hashtable, which is obviously an abuse of inheritance. The way of reusing code here should be the Has-A relationship rather than the Is-A relationship. On the other hand, containers belong to tool classes. Inheriting tool classes is a wrong practice, The best way to use tool classes is the Has-A relationship (Association) or Use-A relationship (dependency). Similarly, Stack class inherits Vector is also incorrect. Engineers of Sun company will also make this low-level mistake, which makes people sigh.
54. What is the difference between Collections and Collections?
A: Collection is an interface, which is the parent interface of containers such as Set and List; Collections is a tool class that provides a series of static methods to assist container operations, including container search, sorting, thread safety, and so on.
55. What are the characteristics of List, Map and Set when accessing elements?
A: List accesses elements with a specific index, and there can be duplicate elements. Set cannot store duplicate elements (use the equals() method of the object to distinguish whether the elements are duplicate). Map stores the key value pair mapping. The mapping relationship can be one-to-one or many to one. Set and map containers have two implementation versions based on Hash storage and sorting tree. The theoretical access time complexity of the version based on Hash storage is O(1), The implementation based on the sorting tree version will form a sorting tree according to the element or element key when inserting or deleting elements, so as to achieve the effect of sorting and de duplication.
56. How do TreeMap and TreeSet compare elements when sorting? How do the sort() method in the Collections tool class compare elements?
A: TreeSet requires that the class of the stored object must implement the Comparable interface, which provides the compareTo() method of comparing elements. When inserting elements, it will call back this method to compare the size of elements. TreeMap requires that the stored key value pair and the mapped key must implement the Comparable interface to sort the elements according to the key. The sort method of Collections tool class has two overloaded forms. The first requires the comparison of objects stored in the passed in container to be sorted to implement the Comparable interface to realize the comparison of elements; The second non mandatory requirement is that the elements in the container must be Comparable, but the second parameter is required, The parameter is a subtype of the Comparator interface (the compare method needs to be rewritten to compare elements). It is equivalent to a temporarily defined sorting rule. In fact, it is to inject an algorithm to compare the size of elements through the interface, and it is also an application of the callback mode (support for functional programming in Java).
Example 1:
public class Student implements Comparable<Student> { private String name; // full name private int age; // Age public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int compareTo(Student o) { return this.age - o.age; // Compare ages (ascending order of ages) } }
import java.util.Set; import java.util.TreeSet; class Test01 { public static void main(String[] args) { Set<Student> set = new TreeSet<>(); // Diamond syntax of Java 7 (no need to write type in angle brackets after constructor) set.add(new Student("Hao LUO", 33)); set.add(new Student("XJ WANG", 32)); set.add(new Student("Bruce LEE", 60)); set.add(new Student("Bob YANG", 22)); for(Student stu : set) { System.out.println(stu); } // Output results: // Student [name=Bob YANG, age=22] // Student [name=XJ WANG, age=32] // Student [name=Hao LUO, age=33] // Student [name=Bruce LEE, age=60] } }
Example 2:
public class Student { private String name; // full name private int age; // Age public Student(String name, int age) { this.name = name; this.age = age; } /** * Get student name */ public String getName() { return name; } /** * Get student age */ public int getAge() { return age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; class Test02 { public static void main(String[] args) { List<Student> list = new ArrayList<>(); // Diamond syntax of Java 7 (no need to write type in angle brackets after constructor) list.add(new Student("Hao LUO", 33)); list.add(new Student("XJ WANG", 32)); list.add(new Student("Bruce LEE", 60)); list.add(new Student("Bob YANG", 22)); // Pass in a Comparator interface object through the second parameter of the sort method // This is equivalent to passing an algorithm to compare the size of the object into the sort method // Because there are no such concepts as function pointer, imitation function and delegate in Java // Therefore, the only option to pass an algorithm into a method is to callback through the interface Collections.sort(list, new Comparator<Student> () { @Override public int compare(Student o1, Student o2) { return o1.getName().compareTo(o2.getName()); // Compare student names } }); for(Student stu : list) { System.out.println(stu); } // Output results: // Student [name=Bob YANG, age=22] // Student [name=Bruce LEE, age=60] // Student [name=Hao LUO, age=33] // Student [name=XJ WANG, age=32] } }
57. Both the sleep() method of the Thread class and the wait() method of the object can pause the Thread. What's the difference between them?
A: the sleep() method (sleep) is a static method of the Thread class (Thread). Calling this method will make the current Thread suspend execution for the specified time and give the execution opportunity (CPU) to other threads, but the lock of the Object remains. Therefore, it will automatically resume after the sleep time is over (the Thread returns to the ready state, please refer to the Thread state transition diagram in question 66) Is the method of the Object class, Calling the wait() method of the Object causes the current Thread to give up the lock of the Object (the Thread suspends execution) and enter the wait pool of the Object. Only when calling the notify() method (or notifyAll() method) of the Object can the Thread in the wait pool wake up and enter the lock pool. If the Thread regains the lock of the Object, it can enter the ready state.
**Add: * * many people may be vague about what is a process and what is a thread, and they don't particularly understand why multi-threaded programming is needed. In short: a process is a program with certain independent functions. It is a running activity on a data set. It is an independent unit for resource allocation and scheduling by the operating system; Thread is an entity of a process. It is the basic unit of CPU scheduling and dispatching. It is a smaller basic unit that can run independently than a process. The dividing scale of threads is smaller than that of processes, which makes multithreaded programs have high concurrency; Processes usually have independent memory units when executing, and threads can share memory. Multithreaded programming can usually bring better performance and user experience, but multithreaded programs are not friendly to other programs because it may occupy more CPU resources. Of course, it is not that the more threads, the better the performance of the program, because the scheduling and switching between threads will also waste CPU time. It's very fashionable nowadays Node.js It adopts the working mode of single thread asynchronous I/O.
58. What is the difference between the sleep() method and the yield() method of a thread?
Answer:
① When the sleep() method gives other threads a chance to run, it does not consider the priority of the thread, so it will give low priority threads a chance to run; The yield() method will only give threads with the same priority or higher priority the chance to run;
② The thread enters the blocked state after executing the sleep() method, and enters the ready state after executing the yield() method;
③ The sleep() method declares to throw InterruptedException, while the yield() method does not declare any exception;
④ The sleep() method is more portable than the yield() method (related to operating system CPU scheduling).
59. When A thread enters the synchronized method A of an object, can other threads enter the synchronized method B of this object?
A: No. Other threads can only access the asynchronous methods of the object, and synchronous methods cannot enter. Because the synchronized modifier on a non static method requires that the lock of the object be obtained when the method is executed. If the object lock has been removed after entering method a, the thread trying to enter method B can only wait for the lock of the object in the wait lock pool (note that it is not the wait pool).
60. Please describe the methods related to thread synchronization and thread scheduling.
Answer:
- wait(): put a thread in a waiting (blocking) state and release the lock of the held object;
- sleep(): it is a static method to make a running thread sleep. Calling this method will handle the InterruptedException exception;
- notify(): wake up a thread in a waiting state. Of course, when this method is called, it cannot wake up a thread in a waiting state exactly, but the JVM determines which thread to wake up, regardless of priority;
- notityAll(): wakes up all threads in the waiting state. This method does not lock the object to all threads, but lets them compete. Only the thread that obtains the lock can enter the ready state;
**Tip: * * I suggest you read another article about Java multithreading and concurrent programming 2021 latest Java Concurrent Programming interview questions.
Add: Java 5 provides an explicit lock mechanism through the Lock interface to enhance flexibility and thread coordination. The Lock interface defines methods of locking (lock()) and unlocking (unlock()), and also provides a newCondition() method to generate a Condition object for communication between threads; In addition, Java 5 also provides a semaphore mechanism, which can be used to limit the number of threads accessing a shared resource. Before accessing the resource, the thread must obtain the permission of the semaphore (call the acquire() method of the semaphore object); After accessing the resource, the thread must return the permission to the semaphore (call the release() method of the semaphore object).
The following example demonstrates the execution of 100 threads depositing 1 yuan into a bank account at the same time without using the synchronization mechanism and using the synchronization mechanism.
- Bank account type:
/** * bank account * */ public class Account { private double balance; // Account balance /** * deposit * @param money Deposit amount */ public void deposit(double money) { double newBalance = balance + money; try { Thread.sleep(10); // Simulating this service takes a period of processing time } catch(InterruptedException ex) { ex.printStackTrace(); } balance = newBalance; } /** * Obtain account balance */ public double getBalance() { return balance; } }
- Save thread class:
/** * Saving thread * */ public class AddMoneyThread implements Runnable { private Account account; // Deposit account private double money; // Deposit amount public AddMoneyThread(Account account, double money) { this.account = account; this.money = money; } @Override public void run() { account.deposit(money); } }
- Test class:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test01 { public static void main(String[] args) { Account account = new Account(); ExecutorService service = Executors.newFixedThreadPool(100); for(int i = 1; i <= 100; i++) { service.execute(new AddMoneyThread(account, 1)); } service.shutdown(); while(!service.isTerminated()) {} System.out.println("Account balance: " + account.getBalance()); } }
When there is no synchronization, the execution result usually shows that the account balance is less than 10 yuan. The reason for this situation is that when one thread A attempts to deposit 1 yuan, another thread B can also enter the deposit method. The account balance read by thread B is still the account balance before thread A deposits 1 yuan, Therefore, the operation of adding 1 yuan to the original balance 0 is also done. Similarly, thread C will do similar things. Therefore, at the end of the last 100 threads, the expected account balance was 100 yuan, However, the actual result is usually less than 10 yuan (probably 1 yuan). The solution to this problem is synchronization. When A thread deposits money in A bank account, it needs to lock the account and allow other threads to operate after its operation is completed. The code has the following adjustment schemes:
- Synchronize the keyword on the deposit method of the bank account
/** * bank account * */ public class Account { private double balance; // Account balance /** * deposit * @param money Deposit amount */ public synchronized void deposit(double money) { double newBalance = balance + money; try { Thread.sleep(10); // Simulating this service takes a period of processing time } catch(InterruptedException ex) { ex.printStackTrace(); } balance = newBalance; } /** * Obtain account balance */ public double getBalance() { return balance; } }
- Synchronize the bank account when the thread calls the deposit method
/** * Saving thread * */ public class AddMoneyThread implements Runnable { private Account account; // Deposit account private double money; // Deposit amount public AddMoneyThread(Account account, double money) { this.account = account; this.money = money; } @Override public void run() { synchronized (account) { account.deposit(money); } } }
- Create a lock object for each bank account through the lock mechanism displayed in Java 5, and lock and unlock the deposit operation
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * bank account * * */ public class Account { private Lock accountLock = new ReentrantLock(); private double balance; // Account balance /** * deposit * * @param money * Deposit amount */ public void deposit(double money) { accountLock.lock(); try { double newBalance = balance + money; try { Thread.sleep(10); // Simulating this service takes a period of processing time } catch (InterruptedException ex) { ex.printStackTrace(); } balance = newBalance; } finally { accountLock.unlock(); } } /** * Obtain account balance */ public double getBalance() { return balance; } }
After modifying the code in the above three ways, rewrite and execute the test code Test01, and you will see that the final account balance is 100 yuan. Of course, you can also use Semaphore or CountdownLatch to achieve synchronization.
61. How many ways to write multithreaded programs?
A: before Java 5, there were two ways to implement multithreading: one is to inherit the Thread class; The other is to implement the Runnable interface. Both methods define the behavior of threads by overriding the run() method. The latter is recommended because inheritance in Java is single inheritance. A class has a parent class. If you inherit the Thread class, you can no longer inherit other classes. Obviously, it is more flexible to use the Runnable interface.
Add: there is a third way to create threads after Java 5: implement the Callable interface. The call method in this interface can generate a return value at the end of thread execution. The code is as follows:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; class MyTask implements Callable<Integer> { private int upperBounds; public MyTask(int upperBounds) { this.upperBounds = upperBounds; } @Override public Integer call() throws Exception { int sum = 0; for(int i = 1; i <= upperBounds; i++) { sum += i; } return sum; } } class Test { public static void main(String[] args) throws Exception { List<Future<Integer>> list = new ArrayList<>(); ExecutorService service = Executors.newFixedThreadPool(10); for(int i = 0; i < 10; i++) { list.add(service.submit(new MyTask((int) (Math.random() * 100)))); } int sum = 0; for(Future<Integer> future : list) { // while(!future.isDone()) ; sum += future.get(); } System.out.println(sum); } }
62. Usage of synchronized keyword?
The synchronized keyword is mainly used in the following three ways:
- Modify the instance method to lock the current instance. Obtain the lock of the current instance before entering the synchronization code
- Modify the static method to lock the current class object. Obtain the lock of the current class object before entering the synchronization code
- Modify the code block, specify the locked object, lock the given object, and obtain the lock of the given object before entering the synchronization code base.
(1) synchronized acts on instance methods
The so-called instance object lock is to modify the instance method in the instance object with synchronized. Note that the instance method does not include static methods, as follows:
public class AccountingSync implements Runnable { // Shared resources (critical resources) static int i = 0; /** * synchronized Modify instance method */ public synchronized void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { AccountingSync instance = new AccountingSync(); Thread t1 = new Thread(instance); Thread t2 = new Thread(instance); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } /** * Output result: 2000000 */ }
In the above code, we start two threads to operate the same shared resource, i.e. variable I, because I + +; The operation is not atomic. The operation reads the value first and then writes back A new value, which is equivalent to adding 1 to the original value. It is completed in two steps. If the second thread reads the domain value of I during the first thread reading the old value and writing back the new value, the second thread will see the same value together with the first thread and execute the operation of adding 1 to the same value, This leads to thread safety failure. Therefore, the synchronize modifier must be used for the increase method to ensure thread safety. At this time, we should note that synchronized modifies the instance method increase. In this case, the lock of the current thread is the instance object instance. Note that the thread synchronization lock in Java can be any object. From the code execution results, it is indeed correct. If we do not use the synchronized keyword, the final output result is likely to be less than 2000000, which is the function of the synchronized keyword. Here, we also need to realize that when A thread is accessing the synchronized instance method of an object, other threads cannot access other synchronized methods of the object. After all, an object has only one lock. When A thread obtains the lock of the object, other threads cannot obtain the lock of the object, Therefore, other synchronized instance methods of the object cannot be accessed, but other threads can still access other non synchronized methods of the instance object. Of course, if thread A needs to access synchronized method F1 of instance object obj1 (the current object lock is obj1), Another thread B needs to access the synchronized method F2 of the instance object obj2 (the current object lock is obj2), which is allowed because the two instance object locks are different and the same. At this time, if the operation data of the two threads are not shared, the thread safety is guaranteed. Unfortunately, if the operation data of the two threads are shared, Then thread safety may not be guaranteed. The following code will demonstrate this phenomenon:
public class AccountingSyncBad implements Runnable{ static int i=0; public synchronized void increase(){ i++; } @Override public void run() { for(int j=0;j<1000000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException { //New new instance Thread t1=new Thread(new AccountingSyncBad()); //New new instance Thread t2=new Thread(new AccountingSyncBad()); t1.start(); t2.start(); //Meaning of join: the current thread A cannot start from thread until the thread terminates Join() returns t1.join(); t2.join(); System.out.println(i); } }
The difference between the above code and the previous code is that we create two new instances of AccountingSyncBad at the same time, and then start two different threads to operate on the shared variable i. unfortunately, the operation result is 1452317 instead of the expected result of 2000000, because the above code makes a serious error, although we use synchronized to modify the increase method, However, two different instance objects are new, which means that there are two different instance object locks, so t1 and t2 will enter their own object locks, that is, t1 and t2 threads use different locks, so thread safety cannot be guaranteed. The way to solve this dilemma is to apply synchronized to the static increase method. In this way, the object lock is the current class object. No matter how many instance objects are created, there is only one class object. In this case, the object lock is unique. Let's take a look at how to use the increase method that applies synchronized to the static state.
(2) synchronized acts on static methods
When synchronized acts on A static method, its lock is the class object lock of the current class. Because static members do not belong to any instance object, they are class members. Therefore, the concurrency of static members can be controlled through class object locks. It should be noted that if thread A calls the non static synchronized method of an instance object and thread B needs to call the static synchronized method of the class to which the instance object belongs, it is allowed and mutual exclusion will not occur, because the lock occupied by accessing the static synchronized method is the class object of the current class, The lock occupied by accessing the non static synchronized method is the current instance object lock. See the following code:
public class AccountingSyncClass implements Runnable{ static int i=0; /** * Acting on static methods, the lock is the current class object, that is * AccountingSyncClass Class object corresponding to class */ public static synchronized void increase(){ i++; } /** * Non static, the lock is different when accessing, and mutual exclusion will not occur */ public synchronized void increase4Obj(){ i++; } @Override public void run() { for(int j=0;j<1000000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException { //New new instance Thread t1=new Thread(new AccountingSyncClass()); //new is worried Thread t2=new Thread(new AccountingSyncClass()); //Start thread t1.start();t2.start(); t1.join();t2.join(); System.out.println(i); } }
Because the synchronized keyword modifies the static increase method, unlike the instance method, its lock object is the class object of the current class. Note that the increase4Obj method in the code is an instance method, and its object lock is the current instance object. If other threads call this method, mutual exclusion will not occur. After all, the lock objects are different, but we should be aware that thread safety problems may be found in this case (shared static variable I is operated).
(3) synchronized code block
In addition to modifying instance methods and static methods with keywords, synchronous code blocks can also be used. In some cases, the method body we write may be relatively large, and there may be some time-consuming operations, and only a small part of the code needs to be synchronized. If we synchronize the whole method directly, the gain may not be worth the loss, At this time, we can wrap the code to be synchronized by synchronizing the code block, so there is no need to synchronize the whole method. The usage example of synchronizing the code block is as follows:
public class AccountingSync implements Runnable{ static AccountingSync instance=new AccountingSync(); static int i=0; @Override public void run() { //Omit other time-consuming operations //Use the synchronization code block to synchronize the variable i, and the lock object is instance synchronized(instance){ for(int j=0;j<1000000;j++){ i++; } } } public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start();t2.start(); t1.join();t2.join(); System.out.println(i); } }
It can be seen from the code that synchronized is applied to a given instance object instance, that is, the current instance object is the lock object. Every time a thread enters the code block wrapped by synchronized, it will require the current thread to hold the instance object lock. If another thread currently holds the object lock, the new thread must wait, This ensures that only one thread executes i + + at a time; Operation. Of course, in addition to instance as the object, we can also use this object (representing the current instance) or the class object of the current class as the lock, as shown in the following code:
//this, the current instance object lock synchronized(this){ for(int j=0;j<1000000;j++){ i++; } } //class object lock synchronized(AccountingSync.class){ for(int j=0;j<1000000;j++){ i++; } }
63. Give examples of synchronous and asynchronous.
A: if there are critical resources in the system (resources with less resources than the number of threads competing for resources), for example, the data being written may be read by another thread later, or the data being read may have been written by another thread, then these data must be accessed synchronously (exclusive locks in database operations are the best example). When an application calls a method that takes a long time to execute on an object and does not want the program to wait for the return of the method, asynchronous programming should be used. In many cases, it is more efficient to use the asynchronous approach. In fact, the so-called synchronization refers to blocking operations, not asynchronous Non blocking operation.
64. Whether to call the run() or start() method to start a thread?
A: to start a thread is to call the start() method to make the virtual processor represented by the thread runnable, which means that it can be scheduled and executed by the JVM, which does not mean that the thread will run immediately. The run() method is the method to call back after the thread is started.
65. What is a thread pool?
A: in object-oriented programming, creating and destroying objects takes a lot of time, because creating an object requires memory resources or more resources. This is especially true in Java, where the virtual machine will try to track each object so that it can garbage collect after the object is destroyed. Therefore, a means to improve the efficiency of service programs is to reduce the number of object creation and destruction as much as possible, especially the creation and destruction of some resource consuming objects, which is the reason for the emergence of "pooled resources" technology. As the name suggests, a thread pool is to create several executable threads in advance and put them into a pool (container). When necessary, the threads obtained from the pool do not need to be created by themselves. After use, the threads do not need to be destroyed, but put them back into the pool, so as to reduce the cost of creating and destroying Thread objects.
The Executor interface in Java 5 + defines a tool for executing threads. Its subtype, the thread pool interface, is ExecutorService. It is complex to configure a thread pool, especially when the principle of thread pool is not very clear. Therefore, some static factory methods are provided on the tool class Executors to generate some common thread pools, as shown below:
- Newsinglethreadexecution: create a single threaded thread pool. This thread pool has only one thread working, which is equivalent to a single thread executing all tasks in series. If the only thread ends abnormally, a new thread will replace it. This thread pool ensures that all tasks are executed in the order they are submitted.
- newFixedThreadPool: creates a fixed size thread pool. Each time a task is submitted, a thread is created until the thread reaches the maximum size of the thread pool. Once the size of the thread pool reaches the maximum, it will remain unchanged. If a thread ends due to execution exception, the thread pool will supplement a new thread.
- newCachedThreadPool: create a cacheable thread pool. If the size of the thread pool exceeds the threads required to process the task, Then some idle threads (not executing tasks for 60 seconds) will be recycled. When the number of tasks increases, this thread pool can intelligently add new threads to process tasks. This thread pool does not limit the size of the thread pool, and the size of the thread pool completely depends on the maximum thread size that the operating system (or JVM) can create.
- newScheduledThreadPool: create an unlimited thread pool. This thread pool supports the need to execute tasks regularly and periodically.
- Newsinglethreadexecution: create a single threaded thread pool. This thread pool supports the need to execute tasks regularly and periodically.
The example in question 60 demonstrates the code of creating a thread pool through the Executors tool class and using the thread pool to execute threads. If you want to use a thread pool on the server, it is strongly recommended to use the newFixedThreadPool method to create a thread pool for better performance.
66. The basic state of the thread and the relationship between the States?
Answer:
**Note: * * where Running indicates Running status, Runnable indicates ready status (everything is ready, only CPU is owed), Blocked indicates blocking status, and there are many kinds of blocking status, which may be due to calling wait() method to enter the waiting pool, or executing synchronization method or synchronization code block to enter the lock pool, Either the sleep() method or the join() method is called to wait for sleep or other threads to end, or because an I/O interrupt has occurred.
67. Briefly describe synchronized and Java util. concurrent. locks. The similarities and differences between lock?
A: Lock is a new API introduced after Java 5. Compared with the keyword synchronized, it has the main similarities: Lock can complete all the functions realized by synchronized; Main differences: Lock has more precise thread semantics and better performance than synchronized, and it is not mandatory to obtain a Lock. Synchronized will automatically release the Lock, and the Lock must be released manually by the programmer, and it is best to release it in the finally block (this is the best place to release external resources).
68. What is the significance of how to implement serialization in Java?
A: serialization is a mechanism for processing object streams. The so-called object stream is to stream the contents of objects. You can read and write the streamed objects, or transfer the streamed objects between networks. Serialization is to solve the problems that may be caused when reading and writing an object stream (if serialization is not performed, there may be a problem of data out of order).
To realize serialization, a class needs to implement the Serializable interface, which is an identifying interface that indicates that the class object can be serialized, Then an output stream is used to construct an object output stream, and the implementation object can be written out through the writeObject(Object) method (that is, save its state); if deserialization is required, you can use an input stream to establish an object input stream, and then read the object from the stream through the readObject method. Serialization can not only realize the persistence of the object, but also be used for deep cloning of the object (refer to question 29).
69. How many types of streams are there in Java?
A: byte stream and character stream. Byte stream inherits from InputStream and OutputStream, and character stream inherits from Reader and Writer. In Java There are many other streams in the IO package, mainly to improve performance and ease of use. There are two points to note about Java I/O: one is two kinds of symmetry (input and output symmetry, byte and character symmetry); the other is two design modes (adapter mode and decoration mode). In addition, the flow in Java is different from C# in that it has only one dimension and one direction.
Interview questions - programming file copy. (this topic often appears in the written examination. The following code gives two implementation schemes)
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public final class MyUtil { private MyUtil() { throw new AssertionError(); } public static void fileCopy(String source, String target) throws IOException { try (InputStream in = new FileInputStream(source)) { try (OutputStream out = new FileOutputStream(target)) { byte[] buffer = new byte[4096]; int bytesToRead; while((bytesToRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } } } } public static void fileCopyNIO(String source, String target) throws IOException { try (FileInputStream in = new FileInputStream(source)) { try (FileOutputStream out = new FileOutputStream(target)) { FileChannel inChannel = in.getChannel(); FileChannel outChannel = out.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(4096); while(inChannel.read(buffer) != -1) { buffer.flip(); outChannel.write(buffer); buffer.clear(); } } } } }
**Note: * * the above uses Java 7 TWR. After using TWR, you don't need to release external resources in finally, so as to make the code more elegant.
70. Write a method, enter a file name and a string, and count the number of times this string appears in this file.
Answer: the code is as follows:
import java.io.BufferedReader; import java.io.FileReader; public final class MyUtil { // The methods in the tool class are accessed statically, so the constructor is private and object creation is not allowed (absolutely good habit) private MyUtil() { throw new AssertionError(); } /** * Counts the number of occurrences of a given string in a given file * * @param filename file name * @param word character string * @return The number of times the string appears in the file */ public static int countWordInFile(String filename, String word) { int counter = 0; try (FileReader fr = new FileReader(filename)) { try (BufferedReader br = new BufferedReader(fr)) { String line = null; while ((line = br.readLine()) != null) { int index = -1; while (line.length() >= word.length() && (index = line.indexOf(word)) >= 0) { counter++; line = line.substring(index + word.length()); } } } } catch (Exception ex) { ex.printStackTrace(); } return counter; } }
71. How to list all files in a directory with Java code?
Answer:
If only the files under the current folder are required to be listed, the code is as follows:
import java.io.File; class Test12 { public static void main(String[] args) { File f = new File("/Users/Hao/Downloads"); for(File temp : f.listFiles()) { if(temp.isFile()) { System.out.println(temp.getName()); } } } }
If you need to continue expanding the folder, the code is as follows:
import java.io.File; class Test12 { public static void main(String[] args) { showDirectory(new File("/Users/Hao/Downloads")); } public static void showDirectory(File f) { _walkDirectory(f, 0); } private static void _walkDirectory(File f, int level) { if(f.isDirectory()) { for(File temp : f.listFiles()) { _walkDirectory(temp, level + 1); } } else { for(int i = 0; i < level - 1; i++) { System.out.print("\t"); } System.out.println(f.getName()); } } }
NiO can be used in Java 7 2 API to do the same thing. The code is as follows:
class ShowFileTest { public static void main(String[] args) throws IOException { Path initPath = Paths.get("/Users/Hao/Downloads"); Files.walkFileTree(initPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println(file.getFileName().toString()); return FileVisitResult.CONTINUE; } }); } }
72. Implement a multithreaded echo server with Java socket programming.
Answer:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class EchoServer { private static final int ECHO_SERVER_PORT = 6789; public static void main(String[] args) { try(ServerSocket server = new ServerSocket(ECHO_SERVER_PORT)) { System.out.println("The server has started..."); while(true) { Socket client = server.accept(); new Thread(new ClientHandler(client)).start(); } } catch (IOException e) { e.printStackTrace(); } } private static class ClientHandler implements Runnable { private Socket client; public ClientHandler(Socket client) { this.client = client; } @Override public void run() { try(BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter pw = new PrintWriter(client.getOutputStream())) { String msg = br.readLine(); System.out.println("received" + client.getInetAddress() + "Sent: " + msg); pw.println(msg); pw.flush(); } catch(Exception ex) { ex.printStackTrace(); } finally { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
**Note: * * the above code uses the TWR syntax of Java 7. Since many external resource classes indirectly implement the autoclosable interface (single method callback interface), you can use the TWR syntax to automatically call the close() method of the external resource class by callback at the end of the try to avoid writing lengthy finally code blocks. In addition, the above code uses a static internal class to realize the function of threads. Using multithreading can avoid the interruption caused by a user's I/O operation and affect the access of other users to the server. In short, the input operation of one user will not cause the obstruction of other users. Of course, the above code can get better performance by using thread pool, because the overhead caused by frequent creation and destruction of threads can not be ignored.
The following is an echo client test code:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class EchoClient { public static void main(String[] args) throws Exception { Socket client = new Socket("localhost", 6789); Scanner sc = new Scanner(System.in); System.out.print("Please enter the content: "); String msg = sc.nextLine(); sc.close(); PrintWriter pw = new PrintWriter(client.getOutputStream()); pw.println(msg); pw.flush(); BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); System.out.println(br.readLine()); client.close(); } }
If you want to implement the server with NIO's multiplexed socket, the code is as follows. Although NIO operations bring better performance, some operations are relatively low-level and difficult for beginners to understand.
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; public class EchoServerNIO { private static final int ECHO_SERVER_PORT = 6789; private static final int ECHO_SERVER_TIMEOUT = 5000; private static final int BUFFER_SIZE = 1024; private static ServerSocketChannel serverChannel = null; private static Selector selector = null; // Multiplexer private static ByteBuffer buffer = null; // buffer public static void main(String[] args) { init(); listen(); } private static void init() { try { serverChannel = ServerSocketChannel.open(); buffer = ByteBuffer.allocate(BUFFER_SIZE); serverChannel.socket().bind(new InetSocketAddress(ECHO_SERVER_PORT)); serverChannel.configureBlocking(false); selector = Selector.open(); serverChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (Exception e) { throw new RuntimeException(e); } } private static void listen() { while (true) { try { if (selector.select(ECHO_SERVER_TIMEOUT) != 0) { Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); it.remove(); handleKey(key); } } } catch (Exception e) { e.printStackTrace(); } } } private static void handleKey(SelectionKey key) throws IOException { SocketChannel channel = null; try { if (key.isAcceptable()) { ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); channel = serverChannel.accept(); channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { channel = (SocketChannel) key.channel(); buffer.clear(); if (channel.read(buffer) > 0) { buffer.flip(); CharBuffer charBuffer = CharsetHelper.decode(buffer); String msg = charBuffer.toString(); System.out.println("received" + channel.getRemoteAddress() + "Message:" + msg); channel.write(CharsetHelper.encode(CharBuffer.wrap(msg))); } else { channel.close(); } } } catch (Exception e) { e.printStackTrace(); if (channel != null) { channel.close(); } } } }
import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; public final class CharsetHelper { private static final String UTF_8 = "UTF-8"; private static CharsetEncoder encoder = Charset.forName(UTF_8).newEncoder(); private static CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder(); private CharsetHelper() { } public static ByteBuffer encode(CharBuffer in) throws CharacterCodingException{ return encoder.encode(in); } public static CharBuffer decode(ByteBuffer in) throws CharacterCodingException{ return decoder.decode(in); } }
73. How many forms do XML document definitions take? What is the essential difference between them? What are the ways to parse XML documents?
Answer: XML document is defined in two ways: dtd document type definition and schema schema.
Essential difference: schema itself is XML and can be parsed by XML parser (this is also the fundamental purpose of developing schema from DTD)
General differences:
- schema is an open content model, which is extensible and functional, while DTD has poor scalability.
- shema supports rich data types, while DTD does not support the data types of elements, and the type definition of attributes is also very limited.
- schema supports namespace mechanism, but DTD does not.
- schema can validate the whole XML document or part of the document according to different situations; DTD lacks this flexibility.
- schema fully complies with XML specification and XML syntax. It can be used in combination with DOM and has powerful functions; DTD syntax itself has its own syntax and requirements, which is difficult to learn.
How to parse XML documents:
- DOM parsing: the full name of DOM is Document Object Model, that is, Document Object Model. In the application, DOM Based XML parser transforms an XML document into a collection of object models (usually called DOM tree), the application program operates the XML document data through the operation of this object model. Through the DOM interface, the application program can access any part of the data in the XML document at any time. Therefore, this mechanism using the DOM interface is also called random access mechanism.
- SAX parsing: the full name of SAX is Simple APIs for XML, that is, XML simple application program interface. Unlike DOM, the access mode provided by SAX is a sequential mode, which is a way to quickly read and write XML data. When using SAX analyzer to analyze XML documents, a series of events will be triggered and the corresponding event handling functions will be activated. Applications can access XML documents through these event handling functions. Therefore, SAX interface is also called event driven interface.
- JDOM parsing: JDOM uses the Collection architecture in Java to encapsulate collections, which is a pattern more familiar to Java enthusiasts
- DOM4J parsing: the xml parser loads the entire xml Document into memory at one time, and then constructs a Document object tree in memory. Through the Document object, the node object on the tree is obtained, and the content of the xml Document is accessed (operated) through the node object
74. Where did you use XML in the project?
A: XML has two main functions: data exchange and information configuration. During data exchange, XML assembles the data with tags, then compresses, packs and encrypts the data and transmits it to the receiver through the network. After receiving, decrypting and decompressing, it restores the relevant information from the XML file for processing. XML used to be the de facto standard for data exchange between heterogeneous systems, However, this function has almost been replaced by JSON (JavaScript Object Notation). Of course, at present, many software still use XML to store configuration information. In many projects, we usually write hard code as configuration information in XML files. Many frameworks in Java do the same, and these frameworks are selected dom4j As a tool for processing XML, Sun's official API is not very easy to use.
**Add: * * now many fashionable software (such as Sublime) have begun to write configuration files in JSON format. We have a strong feeling that another function of XML will be gradually abandoned by the industry.
75. Describe the steps of JDBC operating the database.
A: the following code takes connecting the local Oracle database as an example to demonstrate the steps of JDBC operating the database.
- Load the driver.
Class.forName("oracle.jdbc.driver.OracleDriver");
- Create a connection.
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");
- Create a statement.
PreparedStatement ps = con.prepareStatement("select * from emp where sal between ? and ?"); ps.setInt(1, 1000); ps.setInt(2, 3000);
- Execute the statement.
ResultSet rs = ps.executeQuery();
- Processing results.
while(rs.next()) { System.out.println(rs.getInt("empno") + " - " + rs.getString("ename")); }
- Close the resource.
finally { if(con != null) { try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } }
**Tip: * * the order of closing external resources should be opposite to the order of opening, that is, close ResultSet first, then Statement, and then Connection. The above code only closes the Connection. Although the Statement created on the Connection and the open cursor are usually closed when the Connection is closed, it cannot be guaranteed that this is always the case, so they should be closed in the order just mentioned. In addition, the first step loading driver can be omitted in JDBC 4.0 (automatically load drivers from the classpath), but we recommend keeping them.
76. What is the difference between a Statement and a PreparedStatement? Which performance is better?
The relationship and difference between Statement and PreparedStatement
Relationship: PreparedStatement inherits from Statement and is an interface
Difference: PreparedStatement can use placeholders and is precompiled. Batch processing is more efficient than Statement
Detailed explanation:
(1) PreparedStatement: an object that represents a precompiled SQL statement.
The SQL statement is precompiled and stored in the PreparedStatement object. You can then use this object to execute the statement multiple times efficiently.
Note: setting method for setting IN parameter value (setShort, setString, etc.) you must specify a type compatible with the defined SQL type of the input parameter. For example, if the IN parameter has SQL type INTEGER, you should use the setInt method, and you should pay attention to the position of the question mark, because the position of the first question mark is 1, the position of the second question mark is 2, and so on.
If any parameter type conversion is required, the target SQL type should be used as its parameter when using the setObject method.
In the following example of setting parameters, con represents an active connection:
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SALARY = ? WHERE ID = ?"); pstmt.setBigDecimal(1, 1533.00) pstmt.setInt(2, 1102) pstmt.execute()//Note that there can be no more sql statements when submitting, which is different from the statement
Demo code:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; public class PreparedStatementTest { public static void main(String[] args) { test_autoCommit(); } public static void test_autoCommit() { String driver = "oracle.jdbc.driver.OracleDriver"; String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user = "admin"; String password = "admin"; Connection conn = null; PreparedStatement ps = null; try { // 1. Register driver Class.forName(driver); // 2. Get connection conn = DriverManager.getConnection(url, user, password); // System.out.println(conn); // 3. Create prepareStatement object String sql = "insert into lover values(?,?,?)"; ps = conn.prepareStatement(sql); // 4. Execute sql statement ps.setInt(1, 21);// Delegate set to first? The value of position 21 is of type Int ps.setString(2, "suwu150");// Delegate set to the second? The value of the position number is suwu150 of type String java.util.Date utilDate = new java.util.Date();// Type conversion, from util type date to sql type date ps.setDate(3, new java.sql.Date(utilDate.getTime())); // ps.execute();// implement System.out.println(ps.execute());// The execution table outputs the returned result, which is false because there is no returned result set // 5. Processing result set } catch (Exception e) { e.printStackTrace(); } finally { // 6. Close resource try { if (ps != null) ps.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
Results after insertion
ID | NAME | BIRTHDAY |
---|---|---|
21 | suwu150 | June October 16 |
(2) Statement: an object used to execute a static SQL statement and return the results it generates.
By default, only one ResultSet object can be opened per Statement object at a time. Therefore, if reading one ResultSet object crosses another, the two objects must be generated by different Statement objects. If there is an open current ResultSet object for a Statement, all execution methods in the Statement interface implicitly close it.
Do the following: create a statement object
Statement stat=conn.createStatement(); String sql="insert into lover values(6,'xiaohong',to_date('21-9-2016','dd-mm-yyyy'))"; stat.execute(sql);//There should be an sql statement when submitting, which is different from Preparedstatement
Let's take a look at the actual use:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class StatementTest { public static void main(String[] args) { test_autoCommit(); } public static void test_autoCommit() { String driver = "oracle.jdbc.driver.OracleDriver"; String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user = "admin"; String password = "admin"; Connection conn = null; Statement stat = null; try { // 1. Register driver Class.forName(driver); // 2. Get connection conn = DriverManager.getConnection(url, user, password); conn.setAutoCommit(false); // System.out.println(conn); // 3. Create statement object stat = conn.createStatement(); // 4. Execute sql statement String sql = "insert into lover values(22,'xiaohong',to_date('21-9-2016','dd-mm-yyyy'))"; // Note format // stat.execute(sql); System.out.println(stat.execute(sql)); // The return value is false because there is also no ResultSet return set conn.commit(); // 5. Processing result set } catch (Exception e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { // 6. Close resource try { if (stat != null) stat.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
Results after insertion:
ID | NAME | BIRTHDAY |
---|---|---|
22 | xiaohong | 21-september-16 |
21 | suwu150 | June October 16 |
77. How to improve the performance of reading data when using JDBC to operate the database? How to improve the performance of updating data?
A: to improve the performance of reading data, you can specify the number of records captured each time through the setFetchSize() method of the result set object (typical space for time strategy); to improve the performance of updating data, you can use the PreparedStatement statement statement to build a batch and execute several SQL statements in one batch.
78. What is the role of connection pool in database programming?
A: because there is a lot of overhead in creating and releasing connections (especially when the database server is not local, three TCP handshakes are required every time the connection is established, and four TCP handshakes are required to release the connection, which can not be ignored). In order to improve the performance of the system accessing the database, several connections can be created in advance and placed in the connection pool. If necessary, they can be obtained directly from the connection pool, and the connection pool can be returned at the end of use There is no need to close the connection, so as to avoid the overhead caused by frequent creation and release of connections, This is a typical strategy of exchanging space for time (it wastes space to store connections, but saves the time to create and release connections). Pooling technology is very common in java development. The same is true for creating thread pools when using threads. Java based open source database connection pools mainly include: C3P0,Proxool,DBCP,BoneCP,Druid Wait.
**Supplement: * * in computer system, time and space are irreconcilable contradictions. Understanding this is very important to design algorithms that meet performance requirements. A key to the performance optimization of large websites is to use caching, which is very similar to the connection pool principle mentioned above. It is also a strategy of using space for time. Hotspot data can be placed in the cache. When users query these data, they can get them directly from the cache, which is faster than querying in the database anyway. Of course, the replacement strategy of cache will also have an important impact on the system performance. The discussion on this issue is beyond the scope to be described here.
79. What is DAO mode?
Answer: DAO As its name implies, Data Access Object is an object that provides an abstract interface for database or other persistence mechanisms. It provides various data access operations without exposing the implementation details of the underlying persistence scheme. In actual development, all access operations to data sources should be abstracted and encapsulated in a public API. In programming language , is to establish an interface that defines all transaction methods that will be used in this application. In this application, when you need to interact with the data source, you use this interface, and write a separate class to implement this interface. Logically, this class corresponds to a specific data store. DAO mode actually includes two modes: Data Accessor and Data Object. The former solves the problem of how to access data, while the latter solves the problem of how to encapsulate data with objects.
80. What is the ACID of a transaction?
Answer:
- Atomicity: all operations in a transaction can be done or not done. The failure of any operation will lead to the failure of the whole transaction;
- Consistency: the system state is consistent after the transaction ends;
- Isolated: concurrent transactions cannot see each other's intermediate state;
- Durable: all changes made after the transaction is completed will be persisted, even if there is a catastrophic failure. Log and synchronous backup can rebuild data after failure.
**Add: * * about affairs, the probability of being asked in the interview is very high, and there are many questions to ask. The first thing to know is that transactions are required only when concurrent data access exists. When multiple transactions access the same data, there may be five types of problems, including three types of data reading problems (dirty reading, non repeatable reading and phantom reading) and two types of data update problems (type 1 missing update and type 2 missing update).
Dirty Read: transaction A reads the uncommitted data of transaction B and operates on it. If transaction B rolls back, the data read by transaction A is dirty data.
time | Transfer transaction A | Withdrawal transaction B |
---|---|---|
T1 | Start transaction | |
T2 | Start transaction | |
T3 | The query account balance is 1000 yuan | |
T4 | Withdraw 500 yuan and change the balance to 500 yuan | |
T5 | Query the account balance of 500 yuan (dirty reading) | |
T6 | The balance of cancelled transactions is restored to 1000 yuan | |
T7 | Remit 100 yuan and change the balance to 600 yuan | |
T8 | Commit transaction |
Unrepeatable Read: transaction A re reads the previously read data and finds that the data has been modified by another committed transaction B.
time | Transfer transaction A | Withdrawal transaction B |
---|---|---|
T1 | Start transaction | |
T2 | Start transaction | |
T3 | The query account balance is 1000 yuan | |
T4 | The query account balance is 1000 yuan | |
T5 | Take out 100 yuan and modify the balance to 900 yuan | |
T6 | Commit transaction | |
T7 | The balance of the query account is 900 yuan (not repeatable) |
Phantom Read: transaction A re executes A query, returns A series of rows that meet the query criteria, and finds that the row submitted by transaction B is inserted.
time | Statistics amount transaction A | Transfer transaction B |
---|---|---|
T1 | Start transaction | |
T2 | Start transaction | |
T3 | According to statistics, the total deposit is 10000 yuan | |
T4 | Add a new deposit account to deposit 100 yuan | |
T5 | Commit transaction | |
T6 | Again, the total deposit is 10100 yuan (unreal reading) |
Type 1 missing updates: when transaction A cancels, the updated data of committed transaction B is overwritten.
time | Withdrawal transaction A | Transfer transaction B |
---|---|---|
T1 | Start transaction | |
T2 | Start transaction | |
T3 | The query account balance is 1000 yuan | |
T4 | The query account balance is 1000 yuan | |
T5 | 100 yuan was remitted, and the modified balance was 1100 yuan | |
T6 | Commit transaction | |
T7 | Withdraw 100 yuan and change the balance to 900 yuan | |
T8 | Undo transaction | |
T9 | The balance is restored to 1000 yuan (lost update) |
Type 2 missing updates: transaction A overwrites the data submitted by transaction B, resulting in the loss of operations done by transaction B.
time | Transfer transaction A | Withdrawal transaction B |
---|---|---|
T1 | Start transaction | |
T2 | Start transaction | |
T3 | The query account balance is 1000 yuan | |
T4 | The query account balance is 1000 yuan | |
T5 | Withdraw 100 yuan and change the balance to 900 yuan | |
T6 | Commit transaction | |
T7 | Remit 100 yuan and modify the balance to 1100 yuan | |
T8 | Commit transaction | |
T9 | The query account balance is 1100 yuan (missing update) |
The problems caused by concurrent data access may be allowed in some scenarios, but may be fatal in some scenarios. The database usually solves the problem of concurrent data access through the locking mechanism. It can be divided into table level locks and row level locks according to different locking objects; According to the locking relationship of concurrent transactions, it can be divided into shared locks and exclusive locks. You can refer to the data for details.
Using locks directly is very troublesome. Therefore, the database provides users with an automatic locking mechanism. As long as the user specifies the transaction isolation level of the session, the database will analyze SQL statements and add appropriate locks to the resources accessed by transactions. In addition, the database will maintain these locks and improve the system performance by various means, These are transparent to users (that is, you don't need to understand, in fact, I don't know). ANSI/ISO SQL 92 standard defines four levels of transaction isolation, as shown in the following table:
Isolation level | Dirty reading | Non repeatable reading | Unreal reading | Type I missing updates | Type 2 missing updates |
---|---|---|---|---|---|
READ UNCOMMITED | allow | allow | allow | not allow | allow |
READ COMMITTED | not allow | allow | allow | not allow | allow |
REPEATABLE READ | not allow | not allow | allow | not allow | not allow |
SERIALIZABLE | not allow | not allow | not allow | not allow | not allow |
It should be noted that the transaction isolation level is opposite to the concurrency of data access. The higher the transaction isolation level, the worse the concurrency. Therefore, there is no universal principle to determine the appropriate transaction isolation level according to the specific application.
81. How to process transactions in JDBC?
A: Connection provides a transaction processing method. You can set manual transaction submission by calling setAutoCommit(false); When the transaction is completed, explicitly commit the transaction with commit(); If an exception occurs during transaction processing, the transaction is rolled back through rollback(). In addition, the concept of Savepoint is introduced from JDBC 3.0, which allows you to set the Savepoint through code and roll back the transaction to the specified Savepoint.
82. Can JDBC handle blobs and clobs?
Answer: Blob refers to Binary Large Object, while Clob refers to large character object (Character Large Objec), so Blob is designed to store large binary data, while Clob is designed to store large text data. JDBC PreparedStatement and ResultSet provide corresponding methods to support Blob and Clob operations. The following code shows how to use JDBC to operate LOB:
Next, take MySQL database as an example to create a user table with three fields, including number (id), name (name) and photo. The table creation statement is as follows:
create table tb_user ( id int primary key auto_increment, name varchar(20) unique not null, photo longblob );
The following Java code inserts a record into the database:
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; class JdbcLobTest { public static void main(String[] args) { Connection con = null; try { // 1. Load the driver (Java version 6 or above can be omitted) Class.forName("com.mysql.jdbc.Driver"); // 2. Establish connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456"); // 3. Create statement object PreparedStatement ps = con.prepareStatement("insert into tb_user values (default, ?, ?)"); ps.setString(1, "hzy"); // Replace the first placeholder in the SQL statement with a string try (InputStream in = new FileInputStream("test.jpg")) { // TWR for Java 7 ps.setBinaryStream(2, in); // Replace the second placeholder in the SQL statement with a binary stream // 4. Issue SQL statement to obtain the number of affected rows System.out.println(ps.executeUpdate() == 1 ? "Insert successful" : "Insert failed"); } catch(IOException e) { System.out.println("Failed to read photos!"); } } catch (ClassNotFoundException | SQLException e) { // Multi exception capture in Java 7 e.printStackTrace(); } finally { // Code that releases external resources should be placed in finally to ensure that it can be executed try { if(con != null && !con.isClosed()) { con.close(); // 5. Release database connection con = null; // Indicates that the garbage collector can recycle the object } } catch (SQLException e) { e.printStackTrace(); } } } }
83. Briefly describe regular expressions and their uses.
A: when writing a program to process strings, you often need to find strings that meet some complex rules. Regular expressions are tools for describing these rules. In other words, regular expressions are code that records text rules.
**Note: * * at the beginning of the birth of the computer, almost all the information processed by the computer was numeric, but time has changed. Today, the information processed by the computer is more often not numeric but string. Regular expression is the most powerful tool for string matching and processing. Most languages provide support for regular expression.
84. How does Java support regular expression operations?
A: the String class in Java provides methods that support regular expression operations, including matches(), replaceAll(), replaceFirst(), and split(). In addition, the Pattern class can be used to represent regular expression objects in Java. It provides rich API s for various regular expression operations. Please refer to the code of the interview question below.
Interview question: - if you want to intercept the string before the first English left parenthesis from the string, such as Beijing (Chaoyang District) (Xicheng District) (Haidian District), the interception result is: Beijing, how do you write the regular expression?
import java.util.regex.Matcher; import java.util.regex.Pattern; class RegExpTest { public static void main(String[] args) { String str = "Beijing(Chaoyang District)(Xicheng District)(Haidian District)"; Pattern p = Pattern.compile(".*?(?=\\()"); Matcher m = p.matcher(str); if(m.find()) { System.out.println(m.group()); } } }
**Note: * * lazy matching and forward-looking are used in the above regular expressions. If you are not clear about these contents, it is recommended to read the famous ones on the Internet Regular expression 30 minute tutorial.
85. What are the ways to obtain the class object of a class?
Answer:
- Method 1: type Class, for example: string class
- Method 2: object Getclass(), for example: "hello" getClass()
- Method 3: class Forname(), for example: class forName(“java.lang.String”)
86. How to create objects through reflection?
Answer:
- Method 1: call newinstance () method through class object, for example: string class. newInstance()
- Method 2: obtain the Constructor object through the getConstructor() or getdeclaraedconstructor () method of the class object and call its newInstance() method to create the object, for example: string class. getConstructor(String.class). newInstance(“Hello”);
87. How to obtain and set the value of the private field of an object through reflection?
A: you can use the getdeclaraedfield() method of the class object to access the Field object, and then set it accessible through setAccessible(true) of the Field object. Then you can get/set the value of the Field through the get/set method. The following code implements a reflective tool class, in which two static methods are used to obtain and set the value of private fields respectively. Fields can be basic types or object types, and support multi-level object operations, such as reflectionutil get(dog, “owner.car.engine.id”); You can get the ID number of the engine of the owner's car of the dog object.
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; /** * Reflection tool class * */ public class ReflectionUtil { private ReflectionUtil() { throw new AssertionError(); } /** * Get the value of the specified field (property) of the object through reflection * @param target Target object * @param fieldName The name of the field * @throws If the value of the specified field of the object cannot be obtained, an exception is thrown * @return The value of the field */ public static Object getValue(Object target, String fieldName) { Class<?> clazz = target.getClass(); String[] fs = fieldName.split("\\."); try { for(int i = 0; i < fs.length - 1; i++) { Field f = clazz.getDeclaredField(fs[i]); f.setAccessible(true); target = f.get(target); clazz = target.getClass(); } Field f = clazz.getDeclaredField(fs[fs.length - 1]); f.setAccessible(true); return f.get(target); } catch (Exception e) { throw new RuntimeException(e); } } /** * Assign a value to the specified field of the object by reflection * @param target Target object * @param fieldName Name of the field * @param value value */ public static void setValue(Object target, String fieldName, Object value) { Class<?> clazz = target.getClass(); String[] fs = fieldName.split("\\."); try { for(int i = 0; i < fs.length - 1; i++) { Field f = clazz.getDeclaredField(fs[i]); f.setAccessible(true); Object val = f.get(target); if(val == null) { Constructor<?> c = f.getType().getDeclaredConstructor(); c.setAccessible(true); val = c.newInstance(); f.set(target, val); } target = val; clazz = target.getClass(); } Field f = clazz.getDeclaredField(fs[fs.length - 1]); f.setAccessible(true); f.set(target, value); } catch (Exception e) { throw new RuntimeException(e); } } }
88. How to call object methods through reflection?
A: please see the following code:
import java.lang.reflect.Method; class MethodInvokeTest { public static void main(String[] args) throws Exception { String str = "hello"; Method m = str.getClass().getMethod("toUpperCase"); System.out.println(m.invoke(str)); // HELLO } }
89. Briefly describe the object-oriented "six principles and one law".
Answer:
- Single responsibility principle: a class does only what it should do. (what the principle of single responsibility wants to express is "high cohesion". The ultimate principle of writing code is only six words "high cohesion and low coupling", just as the central idea of sunflower Scripture or anti evil sword spectrum is eight words "if you want to practice this skill, you must first come to the palace" , the so-called high cohesion means that a code module only completes one function. In object-oriented, if only one class completes what it should do without involving fields unrelated to it, it practices the principle of high cohesion, and this class has only one responsibility. We all know a saying called "because of focus, so professional". If an object undertakes too many responsibilities, it is doomed to do nothing well. Any good thing in the world has two characteristics. One is that it has a single function. A good camera is definitely not the kind sold in TV shopping. A machine has more than 100 functions. It can only take pictures basically; The other is modularization. A good bicycle is an assembly vehicle. All parts, from shock fork, brake to transmission, can be disassembled and reassembled. A good table tennis racket is not a finished racket. It must be that the bottom plate and rubber can be disassembled and self-assembled. It is a good software system, Each functional module in it should also be easily available for use in other systems, so as to achieve the goal of software reuse.)
- Opening and closing principle: software entities should be open to extensions and closed to modifications. (in an ideal state, when we need to add new functions to a software system, we only need to derive some new classes from the original system without modifying any line of original code. There are two key points to open and close: ① abstraction is the key, and if there is no abstract class or interface in a system, the system has no extension point; ② encapsulate variability and integrate it into the system Various variable factors of are encapsulated into an inheritance structure. If multiple variable factors are mixed together, the system will become complex and disordered. If it is not clear how to encapsulate variability, please refer to the chapter on the explanation of bridge mode in the book detailed interpretation of design mode.)
- Dependency Inversion Principle: interface oriented programming. (this principle is straightforward and specific. When declaring the parameter type, return type and reference type of a method, use the abstract type instead of the concrete type as much as possible, because the abstract type can be replaced by any of its subtypes. Please refer to the Richter replacement principle below.)
Richter substitution principle: you can replace the parent type with a subtype at any time. (Ms. Barbara Liskov's description of the Richter substitution principle is much more complicated than this, but simply put, where the parent type can be used, the child type can be used. The Richter substitution principle can check whether the inheritance relationship is reasonable. If an inheritance relationship violates the Richter substitution principle, the inheritance relationship must be wrong and the code needs to be modified restructure. For example, it is wrong to let the cat inherit the dog, or the dog inherit the cat, or the square inherit the rectangle, because you can easily find the scene that violates the Richter substitution principle. It should be noted that the subclass must increase the ability of the parent class rather than reduce the ability of the parent class, because the subclass has more ability than the parent class. It is of course no problem to use objects with more ability as objects with less ability.) - Interface isolation principle: the interface should be small and specialized, and must not be large and complete. (a bloated interface pollutes the interface. Since the interface represents capability, an interface should only describe one capability, and the interface should also be highly cohesive. For example, piano, chess, calligraphy and painting should be designed as four interfaces instead of four methods in one interface, because if they are designed as four methods in one interface, the interface is difficult to use, After all, there are still a few people who are proficient in piano, chess, calligraphy and painting. If four interfaces are designed, several interfaces will be implemented for several items. In this way, each interface is highly likely to be reused. Interfaces in Java represent capabilities, conventions and roles. Whether interfaces can be used correctly must be an important indicator of programming level.)
- Composite aggregation Reuse Principle: give priority to using aggregation or composite relationship reuse code. (reusing code through inheritance is the most abused thing in object-oriented programming, because all textbooks advocate inheritance without exception, which misleads beginners. In short, there are three relationships between classes: Is-A relationship, Has-A relationship and Use-A relationship, which represent inheritance, association and dependency respectively. Among them, the association relationship is based on its Association Strength can be further divided into association, aggregation and synthesis, but to put it bluntly, it is the Has-A relationship. The principle of synthetic aggregation reuse wants to express that the Has-A relationship is given priority rather than the Is-A relationship to reuse code. Why? You can find 10000 reasons on Baidu. It should be noted that there are many examples of abusing inheritance even in the Java API, For example, the Properties class inherits the Hashtable class and the Stack class inherits the Vector class. These inheritance is obviously wrong. A better way is to place a member of the Hashtable type in the Properties class and set its key and value as a string to store data. The design of the Stack class should also put a Vector object in the Stack class to store data. Remember: do not inherit tool classes at any time. Tools can be owned and used, not inherited.)
- Dimitri's Law: Dimitri's law is also called the principle of least knowledge. An object should know as little as possible about other objects. (Dimitri's law simply means how to achieve "low coupling" , the facade model and the mediator model are the practice of Dimitri's law. For the facade model, you can take a simple example. When you go to a company to negotiate business, you don't need to know how the company operates internally. You can even know nothing about the company. When you go, you just need to find the front desk beauty at the entrance of the company, tell her what you want to do, and they will find the right person to contact you, The beauty at the front desk is the facade of the company's system. No matter how complex the system is, it can provide users with a simple facade. Isn't Servlet or Filter as the front-end controller in Java Web development a facade? The browser knows nothing about the operation mode of the server, but the front-end controller can get the corresponding services according to your request. The mediator mode can also be illustrated by a simple example. For example, a computer, CPU, memory, hard disk, graphics card and sound card need to cooperate with each other to work well. However, if these things are directly connected together, the wiring of the computer will be extremely complex. In this case, the motherboard appears as a mediator, It connects various devices together without directly exchanging data between each device, which reduces the coupling and complexity of the system, as shown in the figure below. Dimitri's law, in popular words, is not to deal with strangers. If you really need it, find your own friend and let him deal with strangers for you.)
90. Briefly describe the design patterns you know.
A: the so-called design pattern, It is the summary of a set of repeatedly used code design experience (a proven solution to a problem in a situation). Design patterns are used to reuse code, make it easier for others to understand and ensure code reliability. Design patterns enable people to reuse successful designs and architectures more easily and conveniently. Expressing proven technologies into design patterns will also make it easier for new system developers to understand their design Plan ideas.
In GoF's design patterns: elements of reusable object oriented software, there are 23 design patterns (creation type [abstraction of class instantiation process], structural type [description of how to combine classes or objects to form a larger structure], and behavioral type [abstraction of dividing responsibilities and algorithms between different objects]), including Abstract Factory Abstract factory mode, Builder mode, Factory Method mode, Prototype mode, Singleton mode, Facade mode, Adapter mode, Bridge mode, Composite mode, Decorator mode, Flyweight mode, Proxy mode (agent mode); Command mode, Interpreter mode, Visitor mode, Iterator mode, Mediator mode, memo mode, Observer mode, State mode, Strategy mode, Template Method (Template Method mode), Chain Of Responsibility mode.
When you are asked about the knowledge of design patterns in the interview, you can pick the most commonly used answers, such as:
- Factory pattern: factory classes can generate different subclass instances according to conditions. These subclasses have a common abstract parent class and implement the same methods, However, these methods perform different operations (polymorphic methods) for different data. When the subclass instance is obtained, developers can call the methods in the base class without considering which subclass instance is returned.
- Proxy mode: provide a proxy object to an object, and the proxy object controls the reference of the original object. In actual development, according to different purposes, agents can be divided into: remote agent, virtual agent, protection agent, Cache agent, firewall agent, synchronization agent and intelligent reference agent.
- Adapter pattern: transform the interface of a class into another interface expected by the client, so that classes that cannot be used together due to interface mismatch can work together.
- Template method pattern: provide an abstract class, implement some logic in the form of concrete methods or constructors, and then declare some abstract methods to force subclasses to implement the remaining logic. Different subclasses can implement these abstract methods (polymorphic Implementation) in different ways, so as to realize different business logic.
In addition, you can also talk about the facade mode, bridge mode, singleton mode, decoration mode mentioned above (decoration mode is used in Collections tools and I/O systems). Anyway, the basic principle is to choose the answers you are most familiar with and use most, so as not to lose more words.
91. Write a singleton class in Java.
Answer:
- Hungry Han style single case
public class Singleton { private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance(){ return instance; } }
- Lazy single case
public class Singleton { private static Singleton instance = null; private Singleton() {} public static synchronized Singleton getInstance(){ if (instance == null) instance = new Singleton(); return instance; } }
**Note: * * there are two points to note when implementing a singleton: ① keep the constructor private and do not allow the outside world to create objects through the constructor; ② Returns a unique instance of a class to the outside world through an exposed static method. Here's a question to consider: Spring's IoC container can create singletons for ordinary classes. How does it do that?
92. What is UML?
A: UML is a unified modeling language (Unified Modeling Language), which was published in 1997, integrates the existing object-oriented modeling language, methods and processes at that time. It is a graphical language that supports modeling and software system development, and provides modeling and visualization support for all stages of software development. Using UML can help communication and communication, assist application design and document generation It can also explain the structure and behavior of the system.
93. What are the commonly used diagrams in UML?
Answer: UML defines a variety of graphical symbols to describe some or all of the static and dynamic structures of the software system, It includes: use case diagram, class diagram, sequence diagram, collaboration diagram, state diagram, activity diagram, component diagram and deployment diagram Among these graphical symbols, three kinds of diagrams are the most important, namely: use case diagram (used to capture requirements and describe the functions of the system, through which you can quickly understand the functional modules and their relationships of the system), class diagram (describing classes and the relationship between classes, through which you can quickly understand the system), and sequence diagram (describe the interaction relationship and execution order between objects when performing a specific task. Through this figure, you can understand the messages that the object can receive, that is, the services that the object can provide to the outside world).
Use case diagram:
Class diagram:
Sequence diagram:
94. Write a bubble sort in Java.
A: almost all programmers can write bubble sorting, but not everyone can do it during the interview. Here is a reference code:
import java.util.Comparator; /** * Sorter interface (policy pattern: encapsulate algorithms into separate classes with common interfaces so that they can replace each other) * */ public interface Sorter { /** * sort * @param list Array to be sorted */ public <T extends Comparable<T>> void sort(T[] list); /** * sort * @param list Array to be sorted * @param comp Comparator that compares two objects */ public <T> void sort(T[] list, Comparator<T> comp); }
import java.util.Comparator; /** * Bubble sorting * * */ public class BubbleSorter implements Sorter { @Override public <T extends Comparable<T>> void sort(T[] list) { boolean swapped = true; for (int i = 1, len = list.length; i < len && swapped; ++i) { swapped = false; for (int j = 0; j < len - i; ++j) { if (list[j].compareTo(list[j + 1]) > 0) { T temp = list[j]; list[j] = list[j + 1]; list[j + 1] = temp; swapped = true; } } } } @Override public <T> void sort(T[] list, Comparator<T> comp) { boolean swapped = true; for (int i = 1, len = list.length; i < len && swapped; ++i) { swapped = false; for (int j = 0; j < len - i; ++j) { if (comp.compare(list[j], list[j + 1]) > 0) { T temp = list[j]; list[j] = list[j + 1]; list[j + 1] = temp; swapped = true; } } } } }
95. Write a half search in Java.
A: half search, also known as binary search and binary search, is a search algorithm for finding a specific element in an ordered array. The search process starts from the middle element of the array. If the middle element is exactly the element to be searched, the search process ends; If a specific element is greater than or less than the intermediate element, it is searched in the half of the array that is greater than or less than the intermediate element, and the comparison starts from the intermediate element as at the beginning. If the array is empty in a step, the specified element cannot be found. Each comparison of this search algorithm reduces the search scope by half, and its time complexity is O(logN).
import java.util.Comparator; public class MyUtil { public static <T extends Comparable<T>> int binarySearch(T[] x, T key) { return binarySearch(x, 0, x.length- 1, key); } // Binary lookup using loop implementation public static <T> int binarySearch(T[] x, T key, Comparator<T> comp) { int low = 0; int high = x.length - 1; while (low <= high) { int mid = (low + high) >>> 1; int cmp = comp.compare(x[mid], key); if (cmp < 0) { low= mid + 1; } else if (cmp > 0) { high= mid - 1; } else { return mid; } } return -1; } // Binary search using recursion private static<T extends Comparable<T>> int binarySearch(T[] x, int low, int high, T key) { if(low <= high) { int mid = low + ((high -low) >> 1); if(key.compareTo(x[mid])== 0) { return mid; } else if(key.compareTo(x[mid])< 0) { return binarySearch(x,low, mid - 1, key); } else { return binarySearch(x,mid + 1, high, key); } } return -1; } }
**Note: * * the above code gives two versions of half search, one using recursion and the other using loop. It should be noted that (high+ low) / 2 should not be used when calculating the middle position, because the addition operation may cause the integer to cross the boundary. Here, one of the following three methods should be used: low + (high - low) / 2 or low + (high – low) > > 1 or (low + high) > > > 1 (> > > is a logical right shift and a right shift without sign bit)
Pay attention to the official account, update more interview questions regularly, and update the interview questions all on the official account.