Welcome to Java Learning the Class and Object classes in Java

Table of Contents

  • Class and usage in Java

    • Class Class principle

    • How do I get a Class object

    • Use an object of Class to generate an instance of the target Class

  • Object class

    • Class constructor public Object();

    • RegisterNatives () method;

    • The Clone() method implements shallow copies

    • GetClass () method

    • The equals () method

    • HashCode () method;

    • The toString () method

    • wait() notify() notifAll()

    • The finalize () method

  • The relationship between CLass and Object classes

  • Refer to the article

Class and usage in Java

At runtime, the Java runtime system consistently identifies all objects with what is called runtime type identification, or RTTI.

This information records the class to which each object belongs. The virtual machine usually uses runtime type information to select the correct method to execute, and the Class used to hold this type information is the Class Class. The Class Class encapsulates the state of an object and interface at runtime. When a Class is loaded, objects of Class type are created automatically.

To put it bluntly:

The Class Class is also a Class, but the name and the Class keyword are highly similar. Java is a case sensitive language.

The object content of the Class Class is the type information of the Class you create. For example, if you create a Shapes Class, Java generates an object whose content is the Shapes Class

Objects of the Class Class cannot be created as new Shapes () like normal classes, and its objects can only be created by the JVM because the Class has no public constructor

    /* * Private constructor. Only the Java Virtual Machine creates Class objects. * This constructor is not used and prevents the default constructor being * generated. */
     // Private constructor that can only be instantiated by the JVM
    private Class(ClassLoader loader) {
        // Initialize final field for classLoader. The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
    }
Copy the code

The purpose of the Class Class is to provide or obtain the type information of an object at runtime, similar to the typeid() function in C++. This information can also be used for reflection.

Class Class principle

Take a look at some of the source code for the Class Class

// The Class Class encapsulates various types of information. In the JVM, all information about each Java Class is obtained through an instance of the Class Class.

public class Classclass{
    Class aClass = null;

// private EnclosingMethodInfo getEnclosingMethodInfo() {
// Object[] enclosingInfo = getEnclosingMethod0();
// if (enclosingInfo == null)
// return null;
// else {
// return new EnclosingMethodInfo(enclosingInfo);
/ /}
/ /}

    /** Supports Atomic operations. */
// private static class Atomic {
// // initialize Unsafe machinery here, since we need to call Class.class instance method
// // and have to avoid calling it in the static initializer of the Class class...
// private static final Unsafe unsafe = Unsafe.getUnsafe();
// // offset of Class.reflectionData instance field
// private static final long reflectionDataOffset;
// // offset of Class.annotationType instance field
// private static final long annotationTypeOffset;
// // offset of Class.annotationData instance field
// private static final long annotationDataOffset;
//
// static {
// Field[] fields = Class.class.getDeclaredFields0(false); // bypass caches
// reflectionDataOffset = objectFieldOffset(fields, "reflectionData");
// annotationTypeOffset = objectFieldOffset(fields, "annotationType");
// annotationDataOffset = objectFieldOffset(fields, "annotationData");
/ /}

        // Provide reflection information
    // reflection data that might get invalidated when JVM TI RedefineClasses() is called
// private static class ReflectionData
      
        {
      
// volatile Field[] declaredFields;
// volatile Field[] publicFields;
// volatile Method[] declaredMethods;
// volatile Method[] publicMethods;
// volatile Constructor
      
       [] declaredConstructors;
      
// volatile Constructor
      
       [] publicConstructors;
      
// // Intermediate results for getFields and getMethods
// volatile Field[] declaredPublicFields;
// volatile Method[] declaredPublicMethods;
// volatile Class
      [] interfaces;
//
// // Value of classRedefinedCount when we created this ReflectionData instance
// final int redefinedCount;
//
// ReflectionData(int redefinedCount) {
// this.redefinedCount = redefinedCount;
/ /}
/ /}
        // Array of methods
// static class MethodArray {
// // Don't add or remove methods except by add() or remove() calls.
// private Method[] methods;
// private int length;
// private int defaults;
//
// MethodArray() {
// this(20);
/ /}
//
// MethodArray(int initialSize) {
// if (initialSize < 2)
// throw new IllegalArgumentException("Size should be 2 or more");
//
// methods = new Method[initialSize];
// length = 0;
// defaults = 0;
/ /}

    // Annotate information
    // annotation data that might get invalidated when JVM TI RedefineClasses() is called
// private static class AnnotationData {
// final Map
      
       , Annotation> annotations;
      >
// final Map
      
       , Annotation> declaredAnnotations;
      >
//
// // Value of classRedefinedCount when we created this AnnotationData instance
// final int redefinedCount;
//
// AnnotationData(Map
      
       , Annotation> annotations,
      >
// Map
      
       , Annotation> declaredAnnotations,
      >
// int redefinedCount) {
// this.annotations = annotations;
// this.declaredAnnotations = declaredAnnotations;
// this.redefinedCount = redefinedCount;
/ /}
/ /}
}
Copy the code

We know that all Java classes inherit from the Object class, and in the Object class there is a method: getClass (). This method is used to get a reference to an object of Class that has been instantiated. This reference refers to an object of Class.

We cannot generate a Class object ourselves (the constructor is private). The Class objects are created automatically by the Java virtual machine when classes are called in, or by the defineClass method in the Class loader.

// This method is used to dynamically convert bytecode to a Class object
protected finalClass<? > defineClass(String name,byte[] b, int off, int len)
    throws ClassFormatError
{
    return defineClass(name, b, off, len, null);
}
Copy the code

Every object we generate will have a field that records the location of the object’s CLass in the CLass object. As shown below:

[imG-zFMjtZO4-1569074134147] (dl.iteye.com/upload/pict…

How do I get a Class object

Note that these methods are values, referring to the different ways we get a reference to a Class object after the corresponding Class object has been generated in the heap. DefineClass is the method that actually loads the bytecode into the VIRTUAL machine, generating a new Class object in the heap.

The first is the Class forName function

public class shapes{} Class obj= Class.forName(“shapes”); The second way is to use the object’s getClass() function

public class shapes{} shapes s1=new shapes(); Class obj=s1.getClass(); Class obj1=s1.getSuperclass(); // This function fetches the types of the shapes class’s parent

Third, use literal-like constants

Class obj=String.class; Class obj1=int.class; Note that using this approach to generate Class objects does not cause the JVM to automatically load the Class (such as the String Class). == the other method causes the JVM to initialize the class. = =

Use an object of Class to generate an instance of the target Class

Generate an imprecise object instance

After obtaining an object of Class, newInstance() is used to generate an instance of the target Class. However, this function does not directly generate instances of the target class, only instances of the Object class ==

Class obj=Class.forName(“shapes”); Object ShapesInstance=obj.newInstance(); Generate a typed target instance using a generalized Class reference

Class obj=shapes.class; shapes newShape=obj.newInstance(); Because of type restrictions, object references using the generalized Class syntax cannot point to other classes.

Class obj1=int.class;
Class<Integer> obj2=int.class;
obj1=double.class;
//obj2=double.class; This line of code is illegal, and obj2 cannot be redirected to another classHowever, there is a flexible usage that allows you to use Class objects to point to any subclass of the base Class. Class<? extends Number> obj=int.class;
obj=Number.class;
obj=double.class; Thus, the Class object generated by the following syntax can point to any Class. Class<? > obj=int.class;
obj=double.class; obj=shapes.class; The last odd usage is that you must use the following special syntax when using this generic syntax to build the base of an object of Class that you already havepublic class shapes{}
class round extends shapes{}
Class<round> rclass=round.class;
Class<? super round> sclass= rclass.getSuperClass();
//Class<shapes> sclass=rclass.getSuperClass();We know that the base Class of round is shapes, but we cannot declare Class < Shapes > directly. We must use the special Class <?super round >
Copy the code

Just remember that.

Object class

This part of the main reference ihenu.iteye.com/blog/223324…

The Object class is the ancestor of all other classes in Java. Without the Object class, Java Object orientation is impossible. The properties and behaviors of Object, the base class of all other classes, are the thinking behind the design of the Java language.

The Object class resides in the java.lang package, which contains Java’s most basic and core classes and is automatically imported at compile time. The Object class has no defined attributes. There are 13 methods. Not all of them are accessible by subclasses.

Let me give you an overview of these methods

1. Clone method protection method, the realization of a shallow copy of object, only implements the Cloneable interface to invoke the method, otherwise throw CloneNotSupportedException anomalies.2. GetClass methodfinalMethod to get the runtime type.3. ToString method this method is used a lot, usually subclasses have overrides.4. Finalize method This method is used to release resources. This method is rarely used because it is impossible to determine when it will be called.5. Equals method This method is a very important one. Equals and == are different in general, but in Object they are the same. Subclasses typically override this method.6. HashCode method which is used for hash lookup, overrides equals and generally overrides hashCode. This method is used in some collections that have hash capabilities. Obj1.equals (obj2)== must generally be satisfiedtrue. Obj1.hash-code ()== obj2.hashcode (), but hashCode equality does not necessarily satisfy equals. For efficiency, however, you should try to make the above two conditions nearly equivalent.7. The wait method causes the current thread to wait for the lock on the object. The current thread must be the owner of the object. The wait() method waits until the lock is acquired or interrupted. wait(longTimeout) sets a timeout interval and returns if the lock has not been acquired within the specified time. This method is called and the current thread goes to sleep until the following event occurs. (1Other threads called notify on this object. (2) Other threads call notifyAll on this object. (3Other threads call interrupt to interrupt the thread. (4) The interval is up. The thread can then be scheduled, throwing an InterruptedException if it is interrupted.8. Notify method This method wakes up a thread waiting on the object.9. NotifyAll Method This method wakes up all threads waiting on the object.Copy the code

Class constructor public Object();

In most cases, Java passes the form new A(args..) Form creates an object of that type. Where A is the class name, A(args..) The corresponding constructor in such a definition. Objects created in this form are done through constructors in the class.

In order to reflect this feature, Java provides that: in the process of class definition, there will be a default constructor without parameters for the class that does not define a constructor. As the base class of all classes, the Object class naturally reflects this feature. In the source code, there is no definition of the Object class constructor, but in fact, this constructor exists.

Of course, not all classes are built this way, and naturally, not all class constructors are public.

RegisterNatives () method;

private static native void registerNatives();

RegisterNatives function is preceded by native keyword modification. In Java, the function modified with native keyword indicates that the implementation of this method is not completed in Java, but by C/C++, and compiled into. DLL, which is called by Java.

The concrete implementation body of the method is in the DLL file, for different platforms, its concrete implementation should be different. This method needs to be provided by using the native notation, that is, the operating system, and Java itself needs to be used.

In terms of the registerNatives() method itself, the main function is to map the METHODS in C/C++ to the native methods in Java, realizing the decoupling of method naming.

In this case, one might ask that the registerNatives() modifier is private and has not been implemented, how can this be achieved? In fact, in Java source code, the declaration of this method is followed by a static code block:

private static native void registerNatives(a);  
static {  
     registerNatives();  
}  
Copy the code

The Clone() method implements shallow copies

protected native Object clone(a) throwsCloneNotSupportedException;
Copy the code

The Clone () method is not native to Java, but is implemented in C/C++. The purpose of clone is to create and return a copy of this object.

Just to be clear, there’s a Cruze. You look good. You want the exact same. You can conjure up an identical Cruze by calling this method. Same configuration, same look. But from now on, if the original Cruze gets a new makeover, it won’t have anything to do with the cruze you cloned.

The object you clone doesn’t change at all depending on whether or not you do anything to the cruze you clone. In Java terms, the clone function returns a reference to the new Clone object, which occupies a different heap space from the original object.

Now that you understand what clone means, let’s look at how to call the clone() function object.

Take a look at the following example:

package com.corn.objectsummary;  
  
import com.corn.Person;  
  
public class ObjectTest {  
  
    public static void main(String[] args) {  
  
        Object o1 = new Object();  
        // The method clone() from the type Object is not visible  Object clone = o1.clone(); }}Copy the code

Clone () : The method clone() from The type Object is not visible

why? According to the tip, the first reaction is that the Oject object defined in the ObjectTest class cannot access its Clone () method. Going back to the definition of the Clone () method in the Object class, you can see that it is declared protected. This is where the problem arises. Protected attributes or methods indicate that they are accessible within the same package or subclasses of different packages.

Obviously, class Object and ObjectTest class are in a different package, but Class ObjectTest is derived from Class Object and is a subclass of Class Object. As a result, there are subclasses that cannot access protected methods through Object references. The reason is that “subclasses in different packages are accessible” is not understood correctly.

“Subclasses in different packages can access protected members (properties/methods) of a subclass that inherits from the subclass and whose caller is a reference to the subclass, if the two classes are not in the same package. Within subclasses, members of this protected modifier are not accessible when the caller is a reference to the parent class. ! (except the super keyword)

Therefore, the above example is changed to the following form, we find that the normal compilation:

    public class clonemethods{
    public static void main(String[] args) {}public void test1(a) {

        User user = new User();
// User copy = user.clone();
    }
    public void test2(a) {
        User user = new User();
// User copy = (User)user.clone();}}Copy the code

Yes, because at this point the theme is already a reference to a subclass.

The above code will be thrown in the process of running “Java. Lang. CloneNotSupportedException”, suggests that clone () method is not completed correctly, the cause of the problem in the Java syntax rules:

Clone () call is right to implement Cloneable interface, if does not implement the Cloneable interface, Object class and subclass directly call the clone () method, which will throw CloneNotSupportedException anomalies.

The Cloneable interface is simply a presentation interface. The interface itself contains no methods to indicate that Object.clone() can be legally called by subclass references.

Thus, the above code is changed to the following form to correctly specify the clone() method for cloning.

public class User implements Cloneable{
public int id;
public String name;
public UserInfo userInfo;

public static void main(String[] args) {
    User user = new User();
    UserInfo userInfo = new UserInfo();
    user.userInfo = userInfo;
    System.out.println(user);
    System.out.println(user.userInfo);
    try {
        User copy = (User) user.clone();
        System.out.println(copy);
        System.out.println(copy.userInfo);
    } catch(CloneNotSupportedException e) { e.printStackTrace(); }}// The copied User instance is different from the original, which is two objects.
// com.javase.class and object.object methods. The class used is.User@4dc63996
// com.javase.class and object.object methods. The class used is.UserInfo@d716361
        // The userinfo reference object of the copied object is the same.
    // So this is a shallow copy
// com.javase.class and object.object methods. The class used is.User@6ff3c5b5
// com.javase.class and object.object methods. The class used is.UserInfo@d716361
}
Copy the code

Summary: The Clone method implements a shallow copy, which only copies the current object and allocates new space in the heap for the copied object. But objects that contain children of other classes will not be copied to the new object.

== Difference between deep copy and shallow copy ==

Shallow copy A shallow copy is a bitwise copy of an object. It creates a new object with an exact copy of the original object’s property values. If the property is of a primitive type, the value of the primitive type is copied. If the property is a memory address (reference type), the memory address is copied, so if one object changes the address, the other object will be affected.

Deep copy Deep copy copies all attributes and dynamically allocated memory to which the attributes point. Deep copy occurs when an object is copied along with the object it references. Deep copy is slower and more expensive than shallow copy. Now, to make a deep copy of a Clone object, the Clonable interface must override and implement the Clone method, calling the Clone method in the parent class to get the new object and clone out the reference variables in the class. If you just use the default clone method in Object, it will be a shallow copy.

So what are the similarities and differences between these two approaches?

The new operator is intended to allocate memory. When executing the new operator, the program first looks at the type after the new operator, because knowing the type is the only way to know how much memory to allocate.

After allocating memory, the constructor is called to fill the fields of the object. This step is called the initialization of the object. After the constructor returns, an object is created and its reference (address) can be published externally, where the object can be manipulated with this reference.

The first step of Clone is similar to new in that it allocates memory. When calling the Clone method, the allocated memory is the same as that of the source object (that is, the object calling the Clone method), and then the corresponding fields of the original object are used to fill the fields of the new object.

When the clone method returns, a new identical object is created and the reference to the new object can also be published externally.

== That is, after a shallow copy of an object, only a copy of the object is placed in another part of the heap space, but if a member variable has a reference to another object, that reference refers to the same object as the reference in the copied object. Of course, the base data types are copied again. = =

GetClass () method

4.public final native Class<? > getClass();

GetClass () is also a native method that returns the Object’s Class/runtime Class<? >. The effect is the same as object.class.

First, explain the concept of a “class object” : in Java, a class is an abstraction that describes an instance that has a set of the same characteristics or behaviors, and an object is a concrete instance of that class describing the characteristics or behaviors.

As conceptual hierarchies, classes themselves have some common characteristics, such as class names, class loaders to load, packages, parent classes, attributes and methods.

Java defines a Class, Class, to describe the properties of other classes, so that classes themselves are objects of Class. To distinguish it from objects in the usual sense, it is called “class objects”.

public class getClassmethods{
    public static void main(String[] args) {
        User user = new User();
        // The getClass method is a native method that can fetch a Class
      
        object unique to the heap
      Class<? > aClass = user.getClass(); Class bClass = User.class;try {
            Class cClass = Class.forName("Com.javase.class and object.object methods. The class to use.User");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(aClass);
        System.out.println(bClass);
// Class com.javase. class and object.object methods. The class used.user
// Class com.javase. class and object.object methods. The class used.user
        try {
            User a = (User) aClass.newInstance();

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch(IllegalAccessException e) { e.printStackTrace(); }}}Copy the code

A lot of reflection in Java is involved here

The equals () method

5.public boolean equals(Object obj);

Equals and equals are commonly used in Java, and everyone knows the difference between equals and equals:

== means that the variable values are identical (for base types, addresses store values, and reference types store addresses pointing to the actual object);

Equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals

In fact, the above statement is not exact and is more common in the String class. First look at the definition of equals() in the Object class:

public boolean equals(Object obj) {  
     return (this == obj);  
}  
Copy the code

Thus, Object’s native equals() method internally calls ==, which has the same meaning as ==. So why define the equals() method?

The equals() method is used to determine whether two objects are equal. So what’s the scale of equality?

As above, in the Object class, this ruler is ==. Of course, this ruler is not fixed, and the meaning of this ruler can be redefined in other classes as needed. In the String class, the definition of this ruler is redefined based on whether the contents of the String are equal. This increases the functionality of the class and the flexibility of the actual coding. Of course, if the custom class does not override equals() to redefine this ruler, then the default is its parent’s equals(), up to the Object base class.

The actual service requirements in the following scenarios are as follows: For the User bean, it can be seen from the actual service requirements that the same attribute UID represents the same User, that is, two User objects are equal. You can override equals to redefine the ruler of equality for the User object.

The ttest on ObjectTest prints true because the equals() method is overridden in the definition of the User class. This is easy to understand. It is likely that Zhang SAN is a person’s first name and Zhang Sanfeng is his first name.

Overriding equals looks like it might work, but it doesn’t. Because it breaks the convention in Java: overriding equals() requires overriding hasCode().

HashCode () method;

  1. public native int hashCode()

The hashCode() method returns an integer value representing the hash value of the object.

HashCode () has the following convention:

1). Multiple calls to the hashCode() method on the same object during the execution of a Java application program return the same hashCode, provided that the ruler information used to compare the objects to equals has not been modified. The hashCode returned by hashCode() of the same object need not be consistent from one execution of a Java application to another;

2). If two objects are equal (according to: calling equals()), then the hashCode returned by calling hashCode() must also be equal;

3). Conversely, a call to hasCode() returns an equal hash code for two objects, and the two objects are not necessarily equal.

The strict mathematical logic is that two objects are equal <=> equals() equals => hashCode() equals. Therefore, overriding the equlas() method must override the hashCode() method to ensure that this logic is strictly true and that it can be inferred that hasCode() is not equal => equals () is not equal <=> Two objects are not equal. One might wonder: if the only condition (and imperative condition) for comparing whether two objects are equal is equals, then why bother to make a hashCode() and make such a convention? In fact, this is mainly reflected in the use of the hashCode() method, which is used to enhance the performance of hash tables. In the Set class, take Set as an example. When a new object is added, it is necessary to determine whether there are already objects equal to this object in the existing Set. If there is no hashCode() method, it is necessary to traverse the Set once and use equals() method to determine whether the two objects are equal one by one. By means of hasCode method, first calculate the hash code of the object to be added, and then calculate the position of the object according to the hash algorithm, and directly determine whether there is an object in this position. (Note: The underlying Set is implemented using the principle of Map.)Copy the code

One misunderstanding needs to be corrected here: the object’s hashCode() does not return the physical memory address of the object. It may not even be the logical address of the object. Two objects that are identical in hashCode() are not necessarily equal. In other words, two objects that are not equal may return the same hashCode.

So, in the code above, after overriding equals(), you need to override hashCode().

public class equalsandhashcodemethods{
    @Override
    // The hashCode method must be modified at the same time as equals, otherwise it will have problems as a key
    public boolean equals(Object obj) {
        return (this == obj);
    }
    
    @Override
    // The same object must have the same HashCode; different objects may have the same Hashcode
    public int hashCode(a) {
        return hashCode() >> 2; }}Copy the code

The toString () method

7.public String toString();

The toString() method returns a string representation of the object. Let's look at the concrete method body in Object:public String toString(a) {  
    return getClass().getName() + "@" + Integer.toHexString(hashCode());  
}  
Copy the code

The toString() method is probably used a lot, even if it’s not called explicitly, but is internally implemented by toString() when we use system.out.println (obj).

GetClass () returns the class object of the object, and getClassName() returns the name of the class object (including the package name) as a String. Integer.tohexstring (hashCode()) returns the string representation of the hashCode as a hexadecimal unsigned Integer, taking the hashCode of the object as an argument.

In the example above u1 hash code is 638, then the corresponding hexadecimal 27 e, call the toString () method returns the results as follows: com. Corn. Objectsummary. User @ 27 e.

Thus: toString() is uniquely determined by the type of the object and its hash code. Two separate calls to toString() of the same type, but not equal, may return the same result.

wait() notify() notifAll()

8/9/10/11/12. wait(…) / notify() / notifyAll()

When it comes to wait (…). / notify () | notifyAll () methods, the first think of the thread. Indeed, these methods are primarily used for collaboration between Java multithreads. First look at the main meaning of these methods:

Wait () : The current thread calling this method waits until notify()/notifyAll() of the method’s main call (an object) is called on another thread.

Wait (long timeout)/wait(long timeout, int nanos) : The current thread in which the method is called waits until the notisfy()/notisfyAll() methods of the method’s main call (an object) are called on another thread, or the specified amount of timeout is exceeded.

Notify ()/notifyAll() : Wakes up a single thread/all threads waiting on the monitor of this object.

wait(…) / notify () | notifyAll () is generally used. Here’s a simple example:

This is a producer-consumer model, except that only flags are used to identify which thread needs to work

public class waitandnotify {
    // Volatile ensures thread visibility
    volatile static int flag = 1;
    // Object is used as a lock object for threads to use wait and notify
    volatile static Object o = new Object();
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                // Wait and notify can only be used within synchronized code blocks
                synchronized (o) {
                    while (true) {
                        if (flag == 0) {
                            try {
                                Thread.sleep(2000);
                                System.out.println("thread1 wait");
                                // Release the lock, the thread suspends and enters the object wait queue
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println("thread1 run");
                        System.out.println("notify t2");
                        flag = 0;
                        // Notify a thread waiting on the queue to acquire the lock
                        o.notify();
                    }
                }
            }
        }).start();
        // Same as above
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                while (true) {
                    synchronized (o) {
                        if (flag == 1) {
                            try {
                                Thread.sleep(2000);
                                System.out.println("thread2 wait");
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println("thread2 run");
                        System.out.println("notify t1");
                        flag = 1;
                        o.notify();
                    }
                }
            }
        }).start();
    }

    // The output is
// thread1 run
// notify t2
// thread1 wait
// thread2 run
// notify t1
// thread2 wait
// thread1 run
// notify t2
// loop
}
Copy the code

The following conclusions can be drawn from the output of the above examples:

1, wait (…). The current thread blocks immediately after the method is called and the lock in the synchronized code block it holds is appropriate until it is woken up or timed out or interrupted and the lock is acquired again.

2. After the notify()/notifyAll() methods are called, the thread does not release the lock until the code in the synchronized code block is completed. Therefore, if there is code after the synchronized code block, the execution of the lock depends on the thread scheduling of the JVM.

In Java source code, wait() is defined as follows:

public final void wait(a) throws InterruptedException {  
     wait(0);  
}  
Copy the code

And the wait(long timeout, int nanos) method definition is essentially completed by calling wait(Long timeout). Wait (long timeout) is a native method. Thus, wait (…). Methods are essentially native implementations.

Notify ()/notifyAll() methods are also native methods.

Thread in Java has many knowledge points, is a relatively large and important knowledge point. There will be a later blog post that will summarize the details of Java multithreading. I will not go into details here.

The finalize () method

  1. protected void finalize();

Finalize method is mainly related to Java garbage collection mechanism. It’s also known as the 16th-century Object method.

protected void finalize(a) throws Throwable {}Copy the code

We find that finalize method in Object class is defined as an empty method. Why is it defined like this? What is the call time of Finalize method?

First of all, the finalize method defined in Object indicates that every Object in Java will have finalize behavior. The specific call time will be called before THE JVM is ready to garbage collect the memory space occupied by the image. As you can see, this method is not actively invoked (although it can be, just like any custom method).

The relationship between CLass and Object classes

The Object Class has no direct relationship to the Class Class.

The Object class is the parent of all Java classes. Ordinary Java classes inherit the Object class by default, even if they are not declared. Typically, you can use the toString() method of the Object class.

The Class Class is used for Java reflection. All Java classes have a corresponding Class object, which is a final Class. An instance of the Class Class represents the classes and interfaces in a running Java application.

Turn a zhihu interesting question www.zhihu.com/question/30…

In the Java object model:1All classes are instances of Class. Object is a Class, so Object is an instance of Class.2All classes ultimately inherit from the Object Class. If Class is a Class, then Class also inherits from Object.3This is a chicken-and-egg situation. How does the JVM work in practice?Copy the code

In this case, the first assumption is wrong: Java.lang. Object is a Java Class, but not an instance of java.lang.Class. The latter is simply a type that describes Java classes and interfaces to support reflection operations. In this respect Java differs from some of the purer object-oriented languages, such as Python and Ruby.

The second assumption is correct: java.lang.Class is a derived Class from java.lang.Object, and the former inherits from the latter. Although the first assumption is incorrect, the “egg problem” remains: in a Java Object system that has been started up and ready to use, there must be an instance of java.lang.Class corresponding to the java.lang.Object Class; Java.lang. Class is a derived Class of java.lang.Object, and the former should be initialized after the latter.

The fact is, these interdependent core types can all be initialized in one go in “chaos”, and then the state of the object system can be called “bootstrap” and then run according to the general rules of the Java object system. JVM, JavaScript, Python, Ruby, and so on all have such bootstrap procedures at runtime.

In a “boostrap” process, the JVM allocates memory for some of the most important core types in the object system, leaving them in the “allocated” but “not fully initialized” state. These objects have been allocated space but are not yet available because their state is incomplete.

The allocated space is then used to string together the reference relationships between these core types. So far all the action has been done by the JVM and no Java bytecode has been executed. These core types then enter the fully initialized state, and the object system can begin to run on its own, that is, to execute Java bytecode to further initialize the Java system.

Refer to the article

www.cnblogs.com/congsg2016/… www.jb51.net/article/125… Blog.csdn.net/dufufd/arti… Blog.csdn.net/farsight1/a… Blog.csdn.net/xiaomingdet…