2021 latest Java interview questions (java basic interview questions)

1. What are the characteristics of object-oriented?
Answer: object oriented features mainly include the following aspects:

  • Abstraction: abstraction is the process of summarizing the common characteristics of a class of objects to construct a class, including data abstraction and behavior abstraction. Abstraction only focuses on the attributes and behaviors of objects, not the details of these behaviors.
  • Inheritance: inheritance is the process of obtaining inheritance information from an existing class and creating a new class. Classes that provide inheritance information are called parent classes (superclasses and base classes); classes that get inheritance information are called subclasses (derived classes). Inheritance gives a certain continuity to the changing software system. At the same time, inheritance is also an important means to encapsulate variables in programs (if you can't understand it, please read Dr. Yan Hong's Java and patterns or design pattern interpretation) Section on bridge mode in).
  • Encapsulation: encapsulation is generally considered to bind data and methods of operating data, and access to data can only be through defined interfaces. The essence of object-oriented is to describe the real world as a series of completely autonomous and closed objects. The method we write in the class is a kind of encapsulation of implementation details; We write a class that encapsulates data and data operations. It can be said that packaging is to hide all things that can be hidden and only provide the simplest programming interface to the outside world (think about the difference between ordinary washing machines and full-automatic washing machines. Obviously, full-automatic washing machines are better packaged and therefore easier to operate; the smart phones we use now are well packaged enough because they can handle everything with a few buttons).
  • Polymorphism: polymorphism means that objects of different subtypes are allowed to respond differently to the same message. To put it simply, you call the same method with the same object reference, but do different things. Polymorphism is divided into compile time polymorphism and run-time polymorphism. If the method of an object is regarded as A service provided by the object to the outside world, the runtime polymorphism can be explained as: when system A accesses the services provided by system B, system B has many ways to provide services, But everything is transparent to system A (just as the electric razor is system A, its power supply system is system B. system B can use battery power or AC power, or even solar energy. System A only calls the power supply method through class B objects, but does not know what the underlying implementation of the power supply system is and how to obtain power). Method overload (overload) implements compile time polymorphism (also known as pre binding), while method override implements runtime polymorphism (also known as post binding). Runtime polymorphism is the essence of object-oriented. Two things need to be done to realize polymorphism: 1) Method override (the subclass inherits the parent class and overrides the existing or abstract methods in the parent class); 2) Object modeling (using A parent type reference to reference A subtype object, so that the same reference calls the same method will show different behavior according to different subclass objects).

2. What is the difference between the access modifiers public,private,protected, and not writing (default)?
Answer:

Modifier Current classSame packageSubclassOther 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.

3. Is String the most basic data type?
A: No. There are only 8 basic data types in Java: byte, short, int, long, float, double, char, boolean; In addition to the primitive type, the rest are reference types. The enumeration type introduced after Java 5 is also a special reference type.

4,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;.

5,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.

6. Does Java have goto?
A: goto is a reserved word in Java, which is not used in the current version of Java. (according to The Java Programming Language written by James Gosling (the father of Java) The appendix of the book gives a list of Java keywords, including goto and const, which are currently unavailable keywords. Therefore, they are called reserved words in some places. In fact, the word reserved words should have a broader meaning, because programmers familiar with C language know it, Words with special meanings or combinations of words used in the system class library are regarded as reserved words)

7. 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.

8. What is the difference between & & and & &?
Answer: the & operator has two uses: (1) bitwise AND; (2) Logic and&& The operator is a short circuit and operation. The difference between logic and short circuit and is very great, although both require the Boolean values at the left and right ends of the operator to be true, and the value of the whole expression is true&& It is called short circuit operation because if && the value of the expression on the left is false, the expression on the right will be directly short circuited and will not be operated. Many times, we may need to use & & instead of &. For ex amp le, when verifying the user's login, it is determined that the user name is not null and not an empty string. It should be written as: username= null &&! username. Equals (""), the order of the two cannot be exchanged, and the & operator cannot be used, because if the first condition is not true, the equals comparison of strings cannot be carried out at all, otherwise a NullPointerException exception will be generated. Note: the same is true for the difference between logical or operator (|) and short circuit or operator (|).

**Add: * * if you are familiar with JavaScript, you may feel the power of short-circuit operation more. If you want to be a master of JavaScript, start playing with short-circuit operation first.

9. Explain the usage of stack, heap and method area in memory.
A: usually, we define a variable of basic data type, a reference to an object, and the on-site saving of function calls all use the stack space in the JVM; The objects created through the new keyword and constructor are placed in the heap space. The heap is the main area managed by the garbage collector. Since the current garbage collectors adopt the generational collection algorithm, the heap space can also be divided into the new generation and the old generation. More specifically, it can be divided into Eden Survivor (also divided into From Survivor and To Survivor) and Tenured; the method area and heap are memory areas shared by each thread, which are used to store class information, constants, static variables, code compiled by JIT compiler and other data that have been loaded by JVM; the literal in the program is such as 100 and "hello" written directly And constants are placed in the constant pool, which is part of the method area,. The stack space is the fastest to operate, but the stack is very small. Usually, a large number of objects are placed in the heap space. The size of the stack and heap can be adjusted through the startup parameters of the JVM. When the stack space is used up, StackOverflowError will be caused, while insufficient heap and constant pool space will cause OutOfMemoryError.

String str = new String("hello");

In the above statement, the variable str is placed on the stack, the string object created with new is placed on the heap, and the literal "hello" is placed in the method area.

**Supplement 1: * * in the newer version of Java (starting with an update of Java 6), due to the development of JIT compiler and the gradual maturity of "escape analysis" technology, optimization technologies such as on stack allocation and scalar replacement make it not so absolutely right that objects must be allocated on the heap.

Supplement 2: the runtime constant pool is equivalent to the Class file constant pool, which is dynamic. The Java language does not require that constants must be generated only during compilation. New constants can also be put into the pool during runtime, such as the intern() method of String Class.

Take a look at the execution results of the following code and compare whether the previous and future running results of Java 7 are consistent.

String s1 = new StringBuilder("go")
	.append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja")
	.append("va").toString();
System.out.println(s2.intern() == s2);

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: the array does not have a length() method, but has a length attribute. String has a length() method. In JavaScript, the length of the string is obtained through the length attribute, which is easy to be confused with Java.

14. In Java, how to jump out of the current multi nested loop?
A: add a mark such as a before the outermost cycle, and then use break A; You can jump out of multiple loops. (Java supports labeled break and continue statements, which are a bit similar to goto statements in C and C + +, but just like goto, you should avoid using labeled break and continue because it won't make your program more elegant and even has the opposite effect in many cases, so this syntax is actually not better.)

15. Can a constructor be overridden?
A: constructors cannot be inherited, so they cannot be overridden, but they can be overloaded.

16. Two objects have the same value (x.equals(y) == true), but they can have different hash code s, right?
A: No, if two objects X and y satisfy x.equals(y) == true, their hash codes should be the same. Java stipulates the eqauls method and hashCode method as follows: (1) if two objects are the same (the equals method returns true), their hashCode values must be the same; (2) if the hashcodes of two objects are the same, they are not necessarily the same. Of course, you don't have to follow the requirements, but if you violate the above principles, you will find that when using the container, the same object can appear in the Set set, and the efficiency of adding new elements will be greatly reduced (for systems using hash storage, frequent hash code conflicts will lead to a sharp decline in access performance).

**Add: * * many Java programs know about the equals and hashCode methods, but many people just know them. In Joshua Bloch's masterpiece Effective Java (many software companies, Effective Java, Java programming ideas and Refactoring: improving the quality of existing code), Java programmers must read books. If you haven't read them, go quickly Amazon The equals method is introduced as follows: first, the equals method must satisfy reflexivity (x.equals(x) must return true), symmetry (when x.equals(y) returns true, y.equals(x) must also return true), transitivity (when x.equals(y) and y.equals(z) both return true), x.equals(z) must also return true) and consistency (when the Object information referenced by X and Y is not modified, calling x.equals(y) multiple times should get the same return value), and x.equals(null) must return false for any reference x with non null value. The tips to achieve high-quality equals methods include: 1 Use the = = operator to check whether the parameter is a reference to this Object; 2. Use the instanceof operator to check whether the parameter is of the correct type; 3. For the key attribute in the class, check whether the attribute of the parameter passed in Object matches it; 4. After writing the equals method, ask yourself whether it meets symmetry, transitivity and consistency; 5. Always rewrite hashCode when rewriting equals; 6. Do not replace the Object object in the equals method parameter with other types, and do not forget the @ Override annotation when overriding.

17. 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).

18. When an object is passed as a parameter to a method, the method can change the properties of the object and return the changed results. Is this value transfer or reference transfer?
A: it is value transfer. Method calls in the Java language only support parameter value passing. When an object instance is passed to a method as a parameter, the value of the parameter is a reference to the object. The properties of the object can be changed during the call, but the change of the object reference will not affect the caller. In C + + and C #, you can change the value of the passed in parameter by passing reference or output parameter. The following code can be written in c# but not in Java.

using System;

namespace CS01 {
	
	class Program {
		public static void swap(ref int x, ref int y) {
			int temp = x;
			x = y;
			y = temp;
		}

		public static void Main (string[] args) {
			int a = 5, b = 10;
			swap (ref a, ref b);
			// a = 10, b = 5;
			Console.WriteLine ("a = {0}, b = {1}", a, b);
		}
	}
}

Note: it is very inconvenient not to pass references in Java, which has not been improved in Java 8, That's why a large number of Wrapper classes appear in the code written in Java (put the references that need to be modified through method calls into a Wrapper class, and then pass the Wrapper object into the method). This will only make the code bloated, especially for developers who are transforming from C and C + + to Java programmers.

19. What is the difference between String, StringBuilder and StringBuffer?
A: the Java platform provides two types of strings: String and StringBuffer/StringBuilder, which can store and manipulate strings. Where String is a read-only String, which means that the String content referenced by String cannot be changed. The String object represented by the StringBuffer/StringBuilder class can be modified directly. StringBuilder is introduced in Java 5. Its method is exactly the same as that of StringBuffer. The difference is that it is used in a single threaded environment. Because all aspects of it are not synchronized, its efficiency is also higher than that of StringBuffer.

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.

20. The difference between Overload and Override. Can overloaded methods be distinguished according to the return type?
A: method overloading and rewriting are ways to achieve polymorphism. The difference is that the former implements compile time polymorphism, while the latter implements run-time polymorphism. Overloading occurs in a class, If a method with the same name has different parameter lists (different parameter types, different number of parameters, or both), it is regarded as overloaded; rewriting occurs between a child class and a parent class. Rewriting requires that the child class rewritten method and the parent class rewritten method have the same return type, which is better accessible than the parent class rewritten method, and cannot declare more exceptions than the parent class rewritten method (Richter substitution principle). Overloads have no special requirements for return types.

**Interview question: * * Huawei once asked such a question in the interview question - "why can't overloads be distinguished according to the return type". Tell your answer quickly!

21. Describe the principle and mechanism of loading class files by JVM?
A: 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 will ensure that the class has been loaded connect (verification, preparation and parsing) and initialization. Class loading refers to reading the data in the class's. Class file into memory, usually creating a byte array, reading it into the. Class file, and then generating 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 is the stage Section includes three steps: verification, preparation (allocating memory for static variables and setting default initial values) and parsing (replacing symbolic references with direct references). Finally, the JVM initializes the class, including: 1) if the class has a direct parent and the class has not been initialized, initialize the parent class first; 2) If there are initialization statements in the class, they are executed in turn.
Class loading is done by the class loader, Class loaders include: root loader (bootstrap), Extension loader (Extension), System loader (System) and user-defined class loader (subclass of java.lang.ClassLoader). Starting from Java 2 (JDK 1.2), the class loading process adopts the parent delegation mechanism (PDM). PDM better ensures the security of the Java platform. In this mechanism, the bootstrap provided by the JVM is the root 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 bootstrap to Java programs. Below Here is a description of several class loaders:

  • Bootstrap: it is generally implemented with local code and is responsible for loading the JVM basic core class library (rt.jar);
  • Extension: from Java Load the class library in the directory specified by the ext.dirs system attribute, and its parent loader is Bootstrap;
  • System: also known as application class loader, its parent class is Extension. It is the most widely used class loader. It starts from the environment variable classpath or the system attribute Java class. The class recorded in the directory specified by path is the default parent loader of the user-defined loader.

22. Can a Chinese character be stored in a char variable? Why?
A: char type can store a Chinese character, because the encoding used in Java is Unicode (without selecting any specific encoding, it is the only way to directly use the number of characters in the character set), and a char type takes up 2 bytes (16 bits), so it is no problem to put a Chinese character.

**Add: * * using Unicode means that characters have different forms inside and outside the JVM, and are Unicode inside the JVM, When this character is transferred from inside the JVM to outside (for example, stored in the file system), encoding conversion is required. Therefore, there are byte stream and character stream in Java, and conversion streams that convert between character stream and byte stream, such as InputStreamReader and OutputStreamReader. These two classes are adapter classes between byte stream and character stream, which undertake the task of encoding conversion; for C programmers, they need to complete such encoding I'm afraid the code conversion depends on the characteristics of the shared memory of the union.

23. What are the similarities and differences between abstract class and interface?
A: abstract classes and interfaces cannot be instantiated, but references to abstract classes and interface types can be defined. If a class inherits an abstract class or implements an interface, it needs to implement all the abstract methods in it, otherwise the class still needs to be declared as an abstract class. Interfaces are more abstract than abstract classes, because constructors, abstract methods and concrete methods can be defined in abstract classes, while constructors cannot be defined in interfaces, and all methods are abstract methods. Members in an abstract class can be private, default, protected, or public, while all members in an interface are public. Member variables can be defined in abstract classes, while member variables defined in interfaces are actually constants. Classes with abstract methods must be declared as abstract classes, and abstract classes do not necessarily have abstract methods.

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.
A: theoretically, Java will not have memory leakage due to the garbage collection mechanism (GC) (which is also an important reason why Java is widely used in server-side programming); however, in actual development, there may be useless but reachable objects that cannot be recycled by GC, so memory leakage will also occur. For example, Hibernate Session The objects in the (L1 cache) are persistent, and the garbage collector will not recycle these objects. However, there may be useless garbage objects in these objects. If the L1 cache is not close d or flush ed in time, it may lead to memory leakage. The code in the following example will also lead to memory leakage.

import java.util.Arrays;
import java.util.EmptyStackException;

public class MyStack<T> {
	private T[] elements;
	private int size = 0;
	
	private static final int INIT_CAPACITY = 16;
	
	public MyStack() {
		elements = (T[]) new Object[INIT_CAPACITY];
	}
	
	public void push(T elem) {
		ensureCapacity();
		elements[size++] = elem;
	}
	
	public T pop() {
		if(size == 0) 
			throw new EmptyStackException();
		return elements[--size];
	}
	
	private void ensureCapacity() {
		if(elements.length == size) {
			elements = Arrays.copyOf(elements, 2 * size + 1);
		}
	}
}

The above code implements a stack (first in and last out) (FILO)) structure, at first glance, seems to have no obvious problems. It can even pass various unit tests you write. However, the pop method has the problem of memory leakage. When we pop an object in the stack with the pop method, the object will not be treated as garbage collection, even if the program using the stack no longer references these objects, because the internal memory of this method is maintained in the stack Expired references to some objects (obsolete reference). In languages that support garbage collection, memory leakage is very hidden. This kind of memory leakage is actually unconscious object retention. If an object reference is unconsciously retained, the garbage collector will not process this object or other objects referenced by the object, even if there are only a few such objects It may cause many objects to be excluded from garbage collection, which will have a significant impact on performance. In extreme cases, it will cause Disk Paging (data exchange between physical memory and virtual memory of hard disk), and even OutOfMemoryError.

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. Explain the difference between static variables and instance variables.
A: a static variable is a variable modified by the static modifier, also known as a class variable. It belongs to a class and does not belong to any object of the class. No matter how many objects a class creates, the static variable has and only has one copy in memory; The instance variable must depend on an instance. You need to create an object first, and then access it through the object. Static variables allow multiple objects to share memory.

**Supplement: * * in Java development, there are usually a large number of static members in context classes and tool classes.

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 and replace strings?
A: there are many methods. You can write and implement them yourself, or use the methods in String or StringBuffer/StringBuilder. A very common interview question is to use recursion to realize String inversion. The code is as follows:

public static String reverse(String originStr) {
		if(originStr == null || originStr.length() <= 1) 
			return originStr;
		return reverse(originStr.substring(1)) + originStr.charAt(0);
}

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 Summary and Reflection on Java Concurrent Programming.

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.

**Add: * * the four points listed above are the so-called standard answers circulated on the Internet. In fact, the most important difference between Java and JavaScript is that one is a static language and the other is a dynamic language. At present, the development trend of programming language is functional language and dynamic language. In Java, a class is a first-class citizen, while in JavaScript, a function is a first-class citizen. Therefore, JavaScript supports functional programming and can use Lambda functions and closures (closure). Of course, Java 8 also began to support functional programming, providing support for Lambda expressions and functional interfaces. For such questions, it is better to answer them in your own language during the interview, which will be more reliable. Don't recite the so-called standard answers on the Internet.

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: Error refers to system level errors and exceptions that need not be handled by the program. It is a serious problem when recovery is not impossible but very difficult; For example, memory overflow, it is impossible to expect the program to handle such a situation; Exception refers to the exception that needs to be caught or handled by the program. It is a design or implementation problem; In other words, it means that if the program works normally, it will never happen.

Interview question: in the interview of Motorola in 2005, I once asked the question "If a process reports a stack overflow run-time error, what's the most possible cause?", Four options are given: a. lack of memory; b. write on an invalid memory space; c. recursive function calling; d. array index out of boundary. Java programs may also encounter StackOverflowError when running. This is an unrecoverable error. You can only modify the code again. The answer to this interview question is C. If you write a recursion that cannot converge quickly, it is likely to cause a stack overflow error, as shown below:

class StackOverflowErrorTest {

	public static void main(String[] args) {
		main(null);
	}
}

**Tip: * * when writing programs with recursion, you must keep two points in mind: 1 Recursive formula; 2. Convergence condition (when to stop recursion).

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:

  • ArithmeticException (arithmetic exception)
  • ClassCastException (class conversion exception)
  • IllegalArgumentException (illegal parameter exception)
  • IndexOutOfBoundsException (subscript out of bounds exception)
  • NullPointerException (null pointer exception)
  • SecurityException (security 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 Summary and Reflection on Java Concurrent Programming.

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?
A: the synchronized keyword can mark an object or method as synchronized to achieve mutually exclusive access to objects and methods. You can define synchronized code blocks with synchronized (object) {...}, or use synchronized as a modifier of the method when declaring the method. The usage of the synchronized keyword has been shown in the example of question 60.

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?
A: XML document definitions are divided into two forms: DTD and Schema. Both are constraints on XML syntax. The essential difference is that Schema itself is also an XML file, which can be parsed by XML parser, and can define types for data carried by XML. The constraint ability is more powerful than DTD. XML parsing mainly includes DOM (Document Object Model), Sax (Simple API for XML) and StAX (the new method of parsing XML introduced in Java 6, Streaming API for XML), in which the performance of DOM processing large files is very degraded. This problem is caused by the large memory occupied by DOM tree structure, and the DOM parsing method must load the whole document into memory before parsing the file, which is suitable for random access to XML (a typical strategy of exchanging space for time); Sax is an event driven XML parsing method. It reads XML files sequentially without loading all the files at once. When encountering events such as the beginning of the file, the end of the document, or the beginning and end of the label, it will trigger an event. Users can process XML files through event callback code, which is suitable for sequential access to XML; As the name suggests, StAX focuses on streams. In fact, the essential difference between StAX and other parsing methods is that applications can process XML as an event stream. The idea of treating XML as a set of events is not novel (SAX does that), but the difference is that StAX allows application code to pull these events out one by one without providing a handler to receive events from the parser at the convenience of the parser.

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?
A: compared with Statement, ① the PreparedStatement interface represents precompiled statements, Its main advantage is that it can reduce SQL compilation errors and increase SQL security (reduce the possibility of SQL injection attack); ② the SQL statements in PreparedStatement can take parameters, avoiding the trouble and insecurity of splicing SQL statements with string connection; ③ when batch processing SQL or frequently executing the same query, PreparedStatement has obvious performance advantages, because the database can cache the compiled and optimized SQL statements for execution next time It will be very fast when the statements with the same structure are executed (there is no need to compile and generate the execution plan again).

**Supplement: * * in order to provide calls to stored procedures, the JDBC API also provides a CallableStatement interface. Stored Procedure is a set of SQL statements in the database to complete specific functions. It is compiled and stored in the database. Users specify the name of the Stored Procedure and give parameters (if the Stored Procedure has parameters) to execute it. Although calling the Stored Procedure will gain a lot of benefits in network overhead, security and performance, there will be a lot of trouble if the underlying database is migrated, because there are many differences in the writing of the Stored Procedure of each database.

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.

timeTransfer transaction AWithdrawal transaction B
T1Start transaction
T2Start transaction
T3The query account balance is 1000 yuan
T4Withdraw 500 yuan and change the balance to 500 yuan
T5Query the account balance of 500 yuan (dirty reading)
T6The balance of cancelled transactions is restored to 1000 yuan
T7Remit 100 yuan and change the balance to 600 yuan
T8Commit transaction

Unrepeatable Read: transaction A re reads the previously read data and finds that the data has been modified by another committed transaction B.

timeTransfer transaction AWithdrawal transaction B
T1Start transaction
T2Start transaction
T3The query account balance is 1000 yuan
T4The query account balance is 1000 yuan
T5Take out 100 yuan and modify the balance to 900 yuan
T6Commit transaction
T7The 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.

timeStatistics amount transaction ATransfer transaction B
T1Start transaction
T2Start transaction
T3According to statistics, the total deposit is 10000 yuan
T4Add a new deposit account to deposit 100 yuan
T5Commit transaction
T6Again, 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.

timeWithdrawal transaction ATransfer transaction B
T1Start transaction
T2Start transaction
T3The query account balance is 1000 yuan
T4The query account balance is 1000 yuan
T5100 yuan was remitted, and the modified balance was 1100 yuan
T6Commit transaction
T7Withdraw 100 yuan and change the balance to 900 yuan
T8Undo transaction
T9The 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.

timeTransfer transaction AWithdrawal transaction B
T1Start transaction
T2Start transaction
T3The query account balance is 1000 yuan
T4The query account balance is 1000 yuan
T5Withdraw 100 yuan and change the balance to 900 yuan
T6Commit transaction
T7Remit 100 yuan and modify the balance to 1100 yuan
T8Commit transaction
T9The 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 levelDirty readingNon repeatable readingUnreal readingType I missing updatesType 2 missing updates
READ UNCOMMITEDallowallowallownot allowallow
READ COMMITTEDnot allowallowallownot allowallow
REPEATABLE READnot allownot allowallownot allownot allow
SERIALIZABLEnot allownot allownot allownot allownot 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)

Keywords: Java Interview

Added by altumdesign on Sat, 25 Dec 2021 11:24:09 +0200