[2021] java interview questions from scratch (java Basics)

Posted by irishjohnny24 on Sat, 19 Feb 2022 09:20:39 +0100

preface

*** I think the basic boss can leave early. Take time to update this column after work
 

java Foundation

1. What is object-oriented?

  object oriented is to pay more attention to the participants (objects) of things and what they need to do. (process oriented, paying more attention to every step and sequence of things) its four characteristics are as follows:

  • Encapsulation: the meaning of encapsulation is to clearly identify all member functions and data items allowed for external use (internal details are transparent to external calls, and external calls do not need to be modified or care about internal implementation)
  • Inheritance: inherit the methods of the base class (parent class) and make their own changes and / or extensions (the common methods or attributes of subclasses directly use those of the parent class without redefining themselves, but only extend their own personalized methods)
  • Polymorphism: Based on the different classes of objects, the actual logic of external calls to the same method is different. (inheritance and interfaces can be polymorphic)
  • Abstraction: extract key related features (attributes and methods) to form objects, and simulate real-world objects with program method logic and data structure attributes. (all objects are described by classes, but conversely, not all classes are used to describe objects. If a class does not contain enough information to describe a specific object, such a class is an abstract class.)

 

2.JDK JRE JVM

  • JDK: Java Development Kit (development tools required by programmers, including JRE JVM, etc.)
  • JRE: java runtime environment (running java programs)
  • JVM: java Virtual Machine java virtual machine (only after compiling and interpreting. class files can the operating system execute)

 

3. = = compare with equals

==: the comparison is the value in the stack, the basic data type is the variable value, and the reference type is the address of the memory object in the heap
Equals: the default in object is = = comparison (usually developers have to rewrite it themselves and compare the attribute content instead)
ps: beginners may not notice this. They usually use String to compare the content, and they don't rewrite it at all. In fact, the equals method has been overridden for us in the String class.
Let's take an example:

/**
 * @author wook
 * @date 2021/4/23 21:35
 */
public class WookTest {
    private Integer id;
    private String name;
    public WookTest(Integer id,String name){
        this.id = id;
        this.name = name;
    }
    public static void main(String[] args) {
        WookTest wook = new WookTest(1, "wook");
        WookTest wook2 = new WookTest(1, "wook");
        System.out.println(wook.equals(wook2)); 
    }
}

According to the concept at the beginning, all classes inherit Object, and the equals of Object adopts = = to compare the memory address, so the result here is: false. What if you want the result to return: true?

   @Override
   public boolean equals(Object o) {
       if (this == o) return true;
       if (o == null || getClass() != o.getClass()) return false;
       WookTest wookTest = (WookTest) o;
       return Objects.equals(id, wookTest.id) &&
               Objects.equals(name, wookTest.name);
    }

Just rewrite equals in WookTest (shortcut key ctrl + insert, select equals...).
ps: careful students must have found that equals and hashCode usually appear in pairs. Equals understands. What does hashCode do? Don't worry, I'll talk about it later. (in a hurry, please turn to point 9 =.)

 

4. Why can local inner classes and anonymous inner classes only access local final variables?

First, review the situation that final modifies basic type data and reference type data

  • If it is a variable of basic data type, its value cannot be changed after initialization;
  • If it is a variable of reference type, it can no longer point to another object after its initialization. However, the referenced value is variable.
  public static void main() {
        final int[] iArr = {1, 2, 3, 4};
        iArr[2] = -3;//legitimate
        iArr = null;//Illegal, cannot re assign value to iArr (cannot re point)
        final Person p = new Person(25);
        p.setAge(24);//legitimate
        p = null;//illegal
    }

Back to the topic, why can local inner classes and anonymous inner classes only access local final variables?

/**
 * @author wook
 * @date 2021/4/23 22:35
 */
public class Test {
    //Local final variables a,b
    //jdk8 is optimized here (syntax sugar). final is not required, but it is also available. Parameters a and B cannot be modified in the internal class
    public void test(final int b) {
        final int a = 10;
        //Anonymous Inner Class 
        new Thread() {
            public void run() {
                System.out.println(a);
                System.out.println(b);
            }
        }.start();
    }
}

class OutClass {
    private int age = 12;
    public void outPrint(final int x) {
        //Local inner class
        class InClass {
            public void InPrint() {
                System.out.println(x);
                System.out.println(age);
            }
        }
        new InClass().InPrint();
    }
}

ps: there are 4 files after the program is compiled (the class generated by the internal class is the original class name + $1... 2... 3)

  • Test.class , Test$1.class
    • ps: if there is another anonymous inner class, it is test $2 class)
  • OutClass.class , OutClass$1InClass.class
    • ps: if there is another local internal class, it is OutClass . Other internal class names

First of all, we need to know that the internal class and external class are at the same level. The internal class will not be destroyed as the method is executed because it is defined in the method (for example, open the thread to run the anonymous internal class).

Here comes the problem:

  • When the method of the external class ends, the local variable (a) will be destroyed, but the internal class object may still exist (it will die only if no one references it again). There is a contradiction here: the internal class object accesses a non-existent variable. In order to solve this problem, a copy of the local variable is copied as the member variable of the internal class, so that when the local variable dies, the internal class can still access it, and the actual access is the "copy" of the local variable. This is like extending the life cycle of local variables.
  • When copying a local variable into a member variable of an internal class, we must ensure that the two variables are the same, that is, if we modify the member variable in the internal class, the local variable in the method must also change. How to solve the problem?
    • Set the local variable to final. After initializing it, I won't let you modify this variable, which ensures the consistency between the member variables of the internal class and the local variables of the method. This is actually a compromise. Make the local variable consistent with the copy established in the internal class.

A: because the internal class copies a member variable as the internal class, in order to ensure that the copied value is consistent with the original value, we can only compromise and use final modification instead of being modified by others.

 

5.String,StringBuffer,StringBuilder

  • String is final modified and immutable. Each operation will produce a new string object
  • Both StringBuffer and StringBuilder operate on the original object
    • StringBuffer is thread safe (all methods are decorated with synchronized)
    • StringBuilder thread unsafe

Performance: StringBuilder > StringBuffer > string

Scenario: when it is often necessary to change the string content, the latter two are used. StringBuilder is preferred, and StringBuffer is used when multithreading uses shared variables.

 

6. The difference between overloading and rewriting

Overload: occurs in the same class. The method name must be the same. The parameter types, numbers and order are different. The method return value and access modifier can be different. It occurs at compile time.
Override: occurs in parent-child classes. The method name and parameter list must be the same. The return value range is less than or equal to the parent class, the exception range thrown is less than or equal to the parent class, and the access modifier range is greater than or equal to the parent class; If the method access modifier of the parent class is private, the subclass cannot override the method.

public int add(int a,String b)
//Compilation error (non overloading)
public String add(int a,String b)

 

7. Difference between interface and abstract class

  • Ordinary member functions can exist in abstract classes, while only public abstract methods can exist in interfaces.
  • Member variables in abstract classes can be of various types, while member variables in interfaces can only be of public static final type.
  • Abstract classes can only inherit one, and interfaces can implement multiple.

Detailed description: (in a hurry, you can know the above three points)
   the design purpose of the interface is to restrict the behavior of classes (more accurately, it is a "yes" constraint, because the interface cannot specify what behavior classes cannot have), that is, to provide a mechanism that can force different classes to have the same behavior. It only restricts whether the behavior exists or not, but does not limit how to realize the behavior.

  abstract classes are designed for code reuse. When different classes have some of the same behaviors (recorded as behavior set A) and some of the behaviors are implemented in the same way (the true subset of a, recorded as b), these classes can be derived from an abstract class. B is implemented in this abstract class to avoid all subclasses realizing B, which achieves the purpose of code reuse. The part of a minus B is left to each subclass to implement. It is precisely because A-B is not implemented here that abstract classes are not allowed to be instantiated (otherwise, they cannot be executed when called to a-b).
ps: a true subset is an element in one set, all of which are elements in another set.

Explain the abstract class:

  • ① Both class A and class B have action() methods, but the implementation is different
  • ② Both class A and class B have fun() methods, and the implementation is the same
  • ③ The fun() method of class A and B can be extracted to abstract classes C, a and B to inherit C
  • ④ action, as an abstract method of class C, is rewritten by A and B

Summary:
   abstract class is the abstraction of the essence of class, which expresses the relationship between is and A. for example, BMW is a car. Abstract classes contain and implement the general characteristics of subclasses, abstract the differentiated characteristics of subclasses, and hand them over to subclasses for implementation.
  while the interface is the abstraction of behavior and expresses the relationship of like a. For example, birds can fly like aircraft, but they are essentially a bird. The core of the interface is to define the behavior, that is, what the implementation class can do. The interface doesn't care who the implementation class subject is and how it is implemented.
Usage scenario: when you focus on the essence of a thing, use abstract classes; When you focus on an operation, use the interface.
ps: abstract classes are much more powerful than interfaces, but defining abstract classes is expensive. Because for high-level languages (as for actual design), each class can only inherit one class. In this class, you must inherit or write all the commonalities of all its subclasses. Although the interface will weaken a lot in function, it is only a description of an action. And you can implement multiple interfaces in a class at the same time. It will reduce the difficulty in the design stage. (Java 8 interface default method is not discussed)

 

8. Difference between list and Set

  • List: in order, the objects are saved in the order they enter. It can be repeated. Multiple Null element objects are allowed. You can use Iterator to take out all elements. After traversing one by one, you can also use get(int index) to get the elements with the specified subscript
  • Set: unordered and non repeatable. At most one Null element object is allowed. When taking elements, you can only use the Iterator interface to get all elements, and traverse each element one by one (there is no get method)

 

9.hashCode and equals

hashCode introduction:
   hashCode() is used to obtain hash code, also known as hash code; It actually returns an int integer. The function of this hash code is to determine the index position of the object in the hash table. Hashcode () is defined in the object. Of JDK In Java, any class in java contains the hashcode () function.

   hash table stores key value pairs. Its feature is that it can quickly retrieve the corresponding "value" according to the "key (index)". This makes use of hash code! (you can quickly find the required object)

PS: the main function of hashcode method is to cooperate with hash based sets to operate normally. Such hash sets include HashSet, HashMap and HashTable.

Take "how HashSet checks for duplicates" as an example to illustrate why hashCode is required:
   when an object is added to a HashSet, the HashSet will first calculate the hashcode value of the object to determine the location where the object is added and see if the location has a value. If not, the HashSet will think that the object does not appear repeatedly. However, if a value is found (hash conflict), the equals () method will be called to check whether the two objects are really the same. If the two are the same, HashSet will not make its join operation successful. If it is different, it will be re hashed to other locations. In this way, the number of equals is greatly reduced (equals performance is poor), and the execution speed is greatly improved accordingly.

  • If two objects are equal, the hashcode must be the same
  • If the two objects are equal, calling the equals method on the two objects will return true
  • Two objects have the same hashcode value, and they are not necessarily equal
  • If the equals method is overridden, the hashCode method must also be overridden
  • The default behavior of hashCode() is to generate unique values for objects on the heap. If hashCode() is not overridden, the two objects of the class will not be equal in any case (even if the two objects point to the same data (content))

The theory is clear, and the following is explained by code:
ps: refer to Haizi boss for code https://www.cnblogs.com/dolphin0520/p/3681042.html

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
 
class People{
    private String name;
    private int age;
 
    public People(String name,int age) {
        this.name = name;
        this.age = age;
    }  
 
    public void setAge(int age){
        this.age = age;
    }
 
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return this.name.equals(((People)obj).name) && this.age== ((People)obj).age;
    }
}
 
public class Main {
 
    public static void main(String[] args) {
 
        People p1 = new People("Jack", 12);
        System.out.println(p1.hashCode());
 
        HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
        hashMap.put(p1, 1);
 
        System.out.println(hashMap.get(new People("Jack", 12)));
    }
}

Here I only rewrite the equals method, that is, if two People objects have the same name and age, they are considered to be the same person.

The original intention of this code is to output "1", but in fact, it outputs "null". Why? The reason is that you forget to rewrite the hashCode method while rewriting the equals method.

Although two objects with the same logical name and age are determined to be equal by overriding the equals method (similar to the String class), you should know that by default, the hashCode method maps the storage address of the object. It is not surprising that the output of the above code is "null". The reason is very simple. p1 points to the object and system out. println(hashMap.get(new People(“Jack”, 12))); The new people ("Jack", 12) in this sentence generates two objects, and their storage addresses must be different. The following is the specific implementation of the get method of HashMap:

Therefore, when hashmap performs the get operation, because the obtained hashcdoe values are different (note that the above code may get the same hashcode value in some cases, but this probability is relatively small, because although the storage addresses of the two objects are different, they may also get the same hashcode value), so the for loop in the get method will not execute and directly return null.

Therefore, if you want the output result of the above code to be "1", it is very simple. You only need to rewrite the hashCode method to make the equals method and hashCode method always logically consistent.

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
 
class People{
    private String name;
    private int age;
 
    public People(String name,int age) {
        this.name = name;
        this.age = age;
    }  
 
    public void setAge(int age){
        this.age = age;
    }
 
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return name.hashCode()*37+age;
    }
 
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return this.name.equals(((People)obj).name) && this.age== ((People)obj).age;
    }
}
 
public class Main {
 
    public static void main(String[] args) {
 
        People p1 = new People("Jack", 12);
        System.out.println(p1.hashCode());
 
        HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
        hashMap.put(p1, 1);
 
        System.out.println(hashMap.get(new People("Jack", 12)));
    }
}

In this way, the output will be "1".

"Design hashCode()The most important factor is: whenever you call the same object hashCode()Should produce the same value. If you're talking about an object put()Add into HashMap Generate a hashCdoe Value instead of get()When it was taken out, another one was produced hashCode Value, then the object cannot be obtained. So if your hashCode The method depends on the changeable data in the object, so the user should be careful, because when the data changes, hashCode()Method generates a different hash code.
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
 
class People{
    private String name;
    private int age;
 
    public People(String name,int age) {
        this.name = name;
        this.age = age;
    }  
 
    public void setAge(int age){
        this.age = age;
    }
 
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return name.hashCode()*37+age;
    }
 
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return this.name.equals(((People)obj).name) && this.age== ((People)obj).age;
    }
}
 
public class Main {
 
    public static void main(String[] args) {
 
        People p1 = new People("Jack", 12);
        System.out.println(p1.hashCode());
 
        HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
        hashMap.put(p1, 1);
 
        p1.setAge(13);
 
        System.out.println(hashMap.get(p1));
    }
}

The output result of this code is "null". Presumably, we all know the reason.

Therefore, when designing hashCode method and equals method, if the data in the object is changeable, it is better not to rely on this field in equals method and hashCode method.

Topics: Java Programming Interview