Complete Works of Java Interview Questions(6)

Complete Works of Java Interview Questions(6)

Baiyu IT haha

51. The class ExampleA inherits Exception, and the 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 subtype must be used], the catch block that grabs the ExampleA type exception can catch the ExampleB type exception thrown in the try block)

Interview Question-Tell the result of the code below. (The source of this question is the book "Java Programming Thoughts")


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 Collection interface?

Answer: List and Set are yes, but Map is not. Map is a key-value 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 a linear structure and is suitable for numerical values. Index access to the element.

53. Explain the storage performance and characteristics of ArrayList, Vector, LinkedList.

Answer: Both ArrayList and Vector use arrays to store data. The number of elements in this array is greater than the actual data stored in order to add and insert 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 method in Vector is a thread-safe container due to the synchronized modification, but its performance is worse than that of ArrayList, so it is already a legacy container in Java. LinkedList uses a doubly linked list to achieve storage (associate the scattered memory cells in the memory through additional references to form a linear structure that can be indexed by sequence number. Compared with the continuous storage of arrays, this chained storage method has a memory utilization rate. Higher), indexing data by sequence number requires forward or backward traversal, but when inserting data, you only need to record the preceding and following items of this item, so the insertion speed is faster. Vector belongs to legacy containers (containers provided in early versions of Java. In addition, Hashtable, Dictionary, BitSet, Stack, and Properties are all legacy containers), and it is no longer recommended, but because ArrayList and LinkedListed are both non-thread-safe, If you encounter a scenario where multiple threads operate the same container, you can use the synchronizedList method in the tool collections to convert it into a thread-safe container before using it (this is the application of the decoration mode, and the existing objects are passed into another Create new objects in the constructor of a class to enhance the implementation).

Supplement: The Properties class and Stack class in the legacy container have serious design problems. Properties is a special key-value pair mapping whose key and value are both strings. The design should be to associate a Hashtable and two The generic parameter is set to the String type, but the Properties in the Java API directly inherits Hashtable, which is obviously an abuse of inheritance. The way to reuse code here should be the Has-A relationship instead of the Is-A relationship. On the other hand, the container belongs to the tool class. Inheriting the tool class itself is a wrong approach. The best way to use the tool class is the Has-A relationship. (Association) or Use-A relationship (dependency). For the same reason, it is incorrect for the Stack class to inherit Vector. Sun's engineers also make such low-level mistakes, which makes people embarrassed.

54. What is the difference between Collection and Collections?

Answer: Collection is an interface, which is the parent interface of Set, List and other containers; Collections is a tool class that provides a series of static methods to assist container operations. These methods include container search, sorting, thread safety, etc. Wait.

55. What are the characteristics of each of the three interfaces of List, Map, and Set when accessing elements?

Answer: List accesses elements with a specific index, and there can be repeated elements. Set cannot store repeated elements (use the equals() method of the object to distinguish whether the elements are repeated). Map stores key-value pair mapping, and 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 access time complexity of the version theory based on hash storage is O(1), while the implementation based on the sorting tree version is when inserting or deleting elements The sorting tree will be constructed according to the element or the key of the element to achieve the effect of sorting and de-duplication.

56. How do TreeMap and TreeSet compare elements when sorting? How does the sort() method in the Collections utility class compare elements?

Answer: TreeSet requires that the class to which the stored object belongs must implement the Comparable interface. This interface provides a compareTo() method for comparing elements. When an element is inserted, this method will be called back to compare the size of the element. TreeMap requires that the keys stored in the key-value pair mapping must implement the Comparable interface to sort elements according to the key. The sort method of the Collections tool class has two overloaded forms. The first requires that the objects stored in the incoming container to be sorted implement the Comparable interface to achieve element comparison; the second is not mandatory to require the elements in the container It must be comparable, but the second parameter is required to be passed in. The parameter is a subtype of the Comparator interface (the compare method needs to be rewritten to achieve element comparison), which is equivalent to a temporarily defined sorting rule, in fact, the size of the comparison element is injected through the interface Algorithm is also the application of callback mode (the support of functional programming in Java).
Example 1:


public class Student implements Comparable<Student> {
    private String name;        // 姓名
    private int 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; // 比较年龄(年龄的升序)
    }
}

import java.util.Set;
import java.util.TreeSet;
class Test01 {
    public static void main(String[] args) {
   // Java 7的钻石语法(构造器后面的尖括号中不需要写类型)
        Set<Student> set = new TreeSet<>();  
        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);
        }
//      输出结果: 
//      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;    // 姓名
    private int age;        // 年龄
    public Student(String name, int age) {
        this.name = name;
        this.age = age;    }    /**     * 获取学生姓名     */
    public String getName() {
        return name;
    }
    /**     * 获取学生年龄     */
    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<>();     // Java 7的钻石语法(构造器后面的尖括号中不需要写类型)
        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));
        // 通过sort方法的第二个参数传入一个Comparator接口对象
        // 相当于是传入一个比较对象大小的算法到sort方法中
        // 由于Java中没有函数指针、仿函数、委托这样的概念
        // 因此要将一个算法传入一个方法中唯一的选择就是通过接口回调
        Collections.sort(list, new Comparator<Student> () {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getName().compareTo(o2.getName());    // 比较学生姓名
            }
        });
        for(Student stu : list) {
            System.out.println(stu);
        }
//      输出结果: 
//      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 make the thread suspend execution. What is the difference between them?

Answer: The sleep() method (sleep) is a static method of the thread class (Thread). Calling this method will cause the current thread to suspend execution for a specified time and give the execution opportunity (CPU) to other threads, but the object lock is still maintained. Therefore, it will automatically resume after the sleep time expires (the thread returns to the ready state, please refer to the thread state transition diagram in question 66). wait() is a 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 enters the wait pool of the object. Only the notify() method (or notifyAll) of the object is called () method) can wake up the threads in the waiting pool to enter the lock pool (lock pool), if the thread reacquires the lock of the object, it can enter the ready state.

Supplement: Many people may still be vague about what is a process and what is a thread, and they do not particularly understand why multi-threaded programming is needed. Simply put: a process is a program with a certain independent function about a running activity on a certain data set, an independent unit of the operating system for resource allocation and scheduling; a thread is an entity of the process, which is the basic of CPU scheduling and dispatching A unit is a basic unit that is smaller than a process and can run independently. The division scale of threads is smaller than that of processes, which makes multithreaded programs have high concurrency; processes usually have independent memory units during execution, and threads can share memory. Multi-threaded programming usually can bring better performance and user experience, but multi-threaded programs are not friendly to other programs because it may take up 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. Nowadays, the very fashionable Node.js adopts the single-threaded asynchronous I/O working mode.

58. What is the difference between thread sleep() method and yield() method?

Answer:
① The sleep() method does not consider the priority of the thread when giving other threads the opportunity to run, so it will give the low-priority thread a chance to run; the yield() method will only give the thread with the same priority or higher priority Take the chance to run;
② The thread turns into blocked state after executing sleep() method, and turns into ready state after executing yield() method;
③The sleep() method statement throws InterruptedException, and yield() The method does not declare any exceptions;
④ The sleep() method has better portability than the yield() method (related to the operating system CPU scheduling).

59. After a thread enters the synchronized method A of an object, can other threads enter the synchronized method B of this object?

Answer: No. Other threads can only access the non-synchronized method of the object, and the synchronized method cannot enter. Because the synchronized modifier on the non-static method requires the lock of the object to be obtained when the method is executed, if it has entered the A method to indicate that the object lock has been taken away, then the thread trying to enter the B method can only wait for the lock pool (note that it is not waiting The lock of the waiting object in the pool.

60. Please tell me 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 object it holds;
  • sleep(): Make a running thread sleep, it is a static method, calling this method to deal with InterruptedException;
  • notify(): Wake up a thread in a waiting state. Of course, when calling this method, it cannot exactly wake up a thread in a waiting state, but the JVM determines which thread to wake up, and it has nothing to do with priority;
  • notityAll(): wake up all threads in the waiting state. This method does not give the object's lock to all threads, but allows them to compete. Only the thread that obtains the lock can enter the ready state;

Tip: Regarding Java multithreading and concurrent programming, I suggest you read my other article "Summary and Thinking on Java Concurrent Programming".
Supplement: Java 5 provides an explicit lock mechanism (explicit lock) through the Lock interface, which enhances flexibility and coordination of threads. The Lock interface defines methods for locking (lock()) and unlocking (unlock()). It also provides a newCondition() method to generate a Condition object for communication between threads; in addition, Java 5 also provides signals Semaphore, the semaphore can be used to limit the number of threads that access 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 completing the access to 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 synchronization mechanism and using synchronization mechanism.
Bank account category:


/** * 银行账户 * @author 骆昊 * */
public class Account {
    private double balance;     // 账户余额
    /**     * 存款     * @param money 存入金额     */
    public void deposit(double money) {
        double newBalance = balance + money;
        try {
            Thread.sleep(10);   // 模拟此业务需要一段处理时间
        }
        catch(InterruptedException ex) {
            ex.printStackTrace();
        }
        balance = newBalance;
    }

    /**     * 获得账户余额     */
    public double getBalance() {
        return balance;
    }
}

Saving thread class:


/** * 存钱线程 * @author 骆昊 * */
public class AddMoneyThread implements Runnable {
    private Account account;    // 存入账户
    private double money;       // 存入金额
    public AddMoneyThread(Account account, double money) {
        this.account = account;
        this.money = money;
    }
    @Override
    public void run() {
        account.deposit(money);
    }
}

Test category:


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.getBalance());
    }
}

In the absence of synchronization, the execution result usually shows that the account balance is below 10 yuan. The reason for this situation is that when a thread A tries 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, so it also adds 1 yuan to the original balance 0. Similarly, thread C will do similar things. So when the execution of the last 100 threads ends, the account balance is expected to be 100 yuan, but the actual result is usually less than 10 yuan (most likely 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 only allow other threads to operate after its operation is completed. The code has the following adjustment schemes:

  • The synchronized keyword on the deposit method of the bank account

/** * 银行账户 * @author 骆昊 * */
public class Account {
    private double balance;     // 账户余额
    /**     * 存款     * @param money 存入金额     */
    public synchronized void deposit(double money) {
        double newBalance = balance + money;
        try {
            Thread.sleep(10);   // 模拟此业务需要一段处理时间
        }
        catch(InterruptedException ex) {
            ex.printStackTrace();
        }
        balance = newBalance;
    }
    /**     * 获得账户余额     */
    public double getBalance() {
        return balance;
    }
}

Synchronize bank accounts when the thread calls the deposit method


/** * 存钱线程 * @author 骆昊 * */
public class AddMoneyThread implements Runnable {
    private Account account;    // 存入账户
    private double money;       // 存入金额
    public AddMoneyThread(Account account, double money) {
        this.account = account;
        this.money = money;
    }
    @Override
    public void run() {
        synchronized (account) {
            account.deposit(money); 
        }
    }
}

Through the lock mechanism shown in Java 5, a lock object is created for each bank account, and the lock and unlock operations are performed during the deposit operation


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/** * 银行账户 * * @author 骆昊 * */
public class Account {
    private Lock accountLock = new ReentrantLock();
    private double balance; // 账户余额
    /**     * 存款     *     * @param money     *            存入金额     */
    public void deposit(double money) {
        accountLock.lock();
        try {
            double newBalance = balance + money;
            try {
                Thread.sleep(10); // 模拟此业务需要一段处理时间
            }
            catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            balance = newBalance;
        }
        finally {
            accountLock.unlock();
        }
    }
    /**     * 获得账户余额     */
    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.

Guess you like

Origin blog.51cto.com/15061944/2593369