美文网首页
Java Class — Object

Java Class — Object

作者: QuantRuu | 来源:发表于2017-08-07 14:06 被阅读0次

    Object class is present in java.lang package. Every class in Java is directly or indirectly derived from the Object class. If a Class does not extend any other class then it is direct child class of Object and if extends other class then it is an indirectly derived. Therefore the Object class methods are available to all Java classes. Hence Object class acts as a root of inheritance hierarchy in any Java Program.

    Methods in Object class

    //1
    private static native void registerNatives();
        static {
            registerNatives();
        }
    
    //2 Returns the runtime class of this Object.
    public final native Class<?> getClass();
    
    //3 Returns a hash code value for the object.
    public native int hashCode();
    
    //4 Indicates whether some other object is "equal to" this one.
    public boolean equals(Object obj) {
            return (this == obj);
        }
    
    //5 Creates and returns a copy of this object
    protected native Object clone() throws CloneNotSupportedException;
    
    //6 Returns a string representation of the object.
    public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
    
    //7 Wakes up a single thread that is waiting on this object's monitor.
    public final native void notify();
    
    //8 Wakes up all threads that are waiting on this object's monitor.
    public final native void notifyAll();
    
    //9 Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
    public final native void wait(long timeout) throws InterruptedException;
    
    //10 Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.
    public final void wait(long timeout, int nanos) throws InterruptedException {
            if (timeout < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
            if (nanos < 0 || nanos > 999999) {
                throw new IllegalArgumentException("nanosecond timeout value out of range");
            }
            if (nanos > 0) {
                timeout++;
            }
            wait(timeout);
        }
    
    //11 Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object
    public final void wait() throws InterruptedException {
            wait(0);
        }
    
    //12 Called by the garbage collector on an object when garbage collection determines that there are no more references to the object
    protected void finalize() throws Throwable { }
    
    1. registerNatives()

    Normally, in order for the JVM to find your native functions, they have to be named a certain way.
    e.g., for java.lang.Object.registerNatives, the corresponding C function is named Java_java_lang_Object_registerNatives. By using registerNatives (or rather, the JNI function RegisterNatives), you can name your C functions whatever you want.

    Here's the associated C code (from OpenJDK 6):

    static JNINativeMethod methods[] = {
        {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
        {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
        {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
        {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
        {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
    };
    
    JNIEXPORT void JNICALL
    Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
    {
        (*env)->RegisterNatives(env, cls,
                                methods, sizeof(methods)/sizeof(methods[0]));
    }
    

    (Notice that Object.getClass is not in the list; it will still be called by the "standard" name of Java_java_lang_Object_getClass.) For the functions listed, the associated C functions are as listed in that table, which is handier than writing a bunch of forwarding functions.

    Registering native functions is also useful if you are embedding Java in your C program and want to link to functions within the application itself (as opposed to within a shared library), or the functions being used aren't otherwise "exported", since these would not normally be found by the standard method lookup mechanism. Registering native functions can also be used to "rebind" a native method to another C function (useful if your program supports dynamically loading and unloading modules, for example).


    2. getClass()

    The function of method getClass() seems to be very straightforward, but if you think more over it, you will find something worth pondering.
    A.class | a.getClass() | instanceof
    The difference between A.class and a.getClass():
    They are actually different with regards to where you can use them. A.class works at compile time while a.getClass() requires an instance of type A and works at runtime.

    The difference between a.getClass() and instanceof:
    When rewrite equals() method,
    Without using instanceof:

    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    

    Using instanceof:

    if (obj == null)
      return false;
    if (!(obj instanceof MyClass))
      return false;
    
    • instanceof tests whether the object reference on the left-hand side (LHS) is an instance of the type on the right-hand side (RHS) or some subtype.
    • getClass() == ... tests whether the types are identical.

    3. hashCode()

    How to override hashCode() method
    (1) Classic way

    public class User {
        private String name;
        private int age;
        private String passport;
    
        //getters and setters, constructor
    
        @Override
        public boolean equals(Object o) {
    
            if (o == this) return true;
            if (!(o instanceof User)) {
                return false;
            }
    
            User user = (User) o;
    
            return user.name.equals(name) &&
                    user.age == age &&
                    user.passport.equals(passport);
        }
    
        //Idea from effective Java : Item 9
        @Override
        public int hashCode() {
            int result = 17;
            result = 31 * result + name.hashCode();
            result = 31 * result + age;
            result = 31 * result + passport.hashCode();
            return result;
        }
    
    }
    

    The 17 and 31 hash code idea is from the classic Java book – effective Java : item 9

    The value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting. The advantage of using a prime is less clear, but it is traditional. A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31 * i == (i << 5) - i. Modern VMs do this sort of optimization automatically.
    To conclude, it's because the reasons below:

    1. Choose odd number to multiply because no information lost.
    2. Choose prime number because its a traditional behavior.
    3. Choose 31 because it can be optimized by VM.
      (2) JDK7
    import java.util.Objects;
    
    public class User {
        private String name;
        private int age;
        private String passport;
    
        //getters and setters, constructor
    
        @Override
        public boolean equals(Object o) {
    
            if (o == this) return true;
            if (!(o instanceof User)) {
                return false;
            }
            User user = (User) o;
            return age == user.age &&
                    Objects.equals(name, user.name) &&
                    Objects.equals(passport, user.passport);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, age, passport);
        }
    
    }
    

    (3) Apache Commons Lang
    Alternatively, you can use the Apache Commons Lang EqualsBuilder and HashCodeBuilder function.

    import org.apache.commons.lang3.builder;
    
    public class User {
        private String name;
        private int age;
        private String passport;
    
        //getters and setters, constructor
    
         @Override
        public boolean equals(Object o) {
    
            if (o == this) return true;
            if (!(o instanceof User)) {
                return false;
            }
    
            User user = (User) o;
    
            return new EqualsBuilder()
                    .append(age, user.age)
                    .append(name, user.name)
                    .append(passport, user.passport)
                    .isEquals();
        }
    
        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37)
                    .append(name)
                    .append(age)
                    .append(passport)
                    .toHashCode();
        }
    
    }
    

    4. equals()

    Here I will compare equals() versus "==", when the difference is clear, then the using scenario of equals() is undoubted.
    "==" compares object references, it checks to see if the two operands refer to the same object (not equivalent objects, the same object).
    While equals() will only compare what it is written to compare.

    • if a class does not override the equals method, then it defaults to the equals(Object o) method of the
      closest parent class that has overridden this method.
    • If no parent classes have provided an override, then it defaults to the method from the ultimate parent class, Object. According to Object API, it's the same as "==".
      Last but not least, every time you override equals(), you should also override hashcode()

    5. clone()

    Firstly I will clarify the difference between = and clone().

    Dog dogA = new Dog("old");
    Dog dogB = dogA;
    Dog dogC = (Dog)dogA.clone();
    dogA.setName("new");
    system.out.println(dogA.name);//new
    system.out.println(dogB.name);//new
    system.out.println(dogC.name);//old
    

    When an object implements clonable, then it can use clone(). In Java, objects are manipulated through reference variables, and there is no operator for copying an object—the assignment operator duplicates the reference, not the object. The clone() method provides this missing functionality.

    clone() acts like a copy constructor. Typically it calls the clone() method of its superclass to obtain the copy, etc. until it eventually reaches Object's clone() method. The special clone() method in the base class Object
    provides a standard mechanism for duplicating objects.The class Object's clone() method creates and returns a copy of the object, with the same class and with all the fields having the same values.
    .
    The default implementation of Object.clone() performs a shallow copy. When a class desires a deep copy or some other custom behavior, they must perform that in their own clone() method after they obtain the copy from the superclass.
    Some principles:
    (1) Every type that needs to be cloned must have a public clone() method in its own class or a publicly accessible clone() method in one of its parent classes.
    Example:
    To invoke clone() on varY1, which is of type Y, then Y or a parent of Y must declare a publicly accessible clone() method. Here, it is the parent class X that provides the public clone() method.

    public class X implements Cloneable {
            public X clone() throws CloneNotSupportedException {
                    return (X) super.clone();
            }
    }
    
    public class Y extends X { }
    
    public class Z extends Y { }
    
    public class test1 {
            public void function() throws CloneNotSupportedException {
                    Y varY1 = new Z();
                    Y varY2 = (Y) varY1.clone();
            }
    }
    

    (2) Every class that implements clone() should call super.clone() to obtain the cloned object reference. If the class has any object references that must be cloned as well (when deep copying, for example), then the clone() method should perform any required modifications on the object before returning it. (Since Object.clone() returns an exact copy of the original object, any mutable fields such as collections and arrays would be shared between the original and the copy - which in most cases would neither be expected nor desired.)
    Example:
    Since class Z contains an object reference, its clone() method also clones that object reference in order to return a deep copy of the original.

    public class X implements Cloneable {
            public X clone() throws CloneNotSupportedException {
                    return (X) super.clone();
            }
    }
    
    public class Y extends X { }
    
    public class ObjectABC implements Cloneable {
            public ObjectABC clone() throws CloneNotSupportedException {
                    return (ObjectABC) super.clone();
            }
    }
    
    public class Z extends Y {
            private ObjectABC someABC;
    
            public Z clone() throws CloneNotSupportedException {
                    Z newZ = (Z) super.clone();
                    newZ.someABC = someABC.clone();
    
                    return newZ;
            }
    }
    
    public class test1 {
            public void function() throws CloneNotSupportedException {
                    Y varY1 = new Z();
                    Y varY2 = (Y) varY1.clone();
            }
    }
    

    Generally, clone() is incompatible with final fields. Because clone() is essentially a default constructor (one that has no arguments) it is impossible to assign a final field within a clone() method; a compiler error is the result. Where the value of the field is an immutable object this is okay; just let the 'constructor' copy the reference and both the original and its clone will share the same object.


    6. toString()

    The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object.

    getClass().getName() + '@' + Integer.toHexString(hashCode())
    

    Effective Java suggests that the method toString should be override all the time to make it more practical.


    7. notify()

    I assume notify() and wait() methods are designed to implement a producer/consumer pattern.
    The wait() and notify() methods are designed to provide a mechanism to allow a thread to block until a specific condition is met. For this I assume you're wanting to write a blocking queue implementation, where you have some fixed size backing-store of elements.

    The first thing you have to do is to identify the conditions that you want the methods to wait for. In this case, you will want the put() method to block until there is free space in the store, and you will want the take() method to block until there is some element to return.

    public class BlockingQueue<T> {
    
        private Queue<T> queue = new LinkedList<T>();
        private int capacity;
    
        public BlockingQueue(int capacity) {
            this.capacity = capacity;
        }
    
        public synchronized void put(T element) throws InterruptedException {
            while(queue.size() == capacity) {
                wait();
            }
    
            queue.add(element);
            notify(); // notifyAll() for multiple producer/consumer threads
        }
    
        public synchronized T take() throws InterruptedException {
            while(queue.isEmpty()) {
                wait();
            }
    
            T item = queue.remove();
            notify(); // notifyAll() for multiple producer/consumer threads
            return item;
        }
    }
    

    There are a few things to note about the way in which you must use the wait and notify mechanisms.

    Firstly, you need to ensure that any calls to wait() or notify() are within a synchronized region of code (with the wait() and notify() calls being synchronized on the same object). The reason for this (other than the standard thread safety concerns) is due to something known as a missed signal.

    An example of this, is that a thread may call put() when the queue happens to be full, it then checks the condition, sees that the queue is full, however before it can block another thread is scheduled. This second thread then take()'s an element from the queue, and notifies the waiting threads that the queue is no longer full. Because the first thread has already checked the condition however, it will simply call wait() after being re-scheduled, even though it could make progress.

    By synchronizing on a shared object, you can ensure that this problem does not occur, as the second thread's take() call will not be able to make progress until the first thread has actually blocked.

    Secondly, you need to put the condition you are checking in a while loop, rather than an if statement, due to a problem known as spurious wake-ups. This is where a waiting thread can sometimes be re-activated without notify() being called. Putting this check in a while loop will ensure that if a spurious wake-up occurs, the condition will be re-checked, and the thread will call wait() again.


    8. notifyAll()

    Before choosing notify() or notifyAll(), think about this question: Do you want to tell one of the waiting threads that something happened, or do you want to tell all of them at the same time?
    In some cases, all waiting threads can take useful action once the wait finishes. An example would be a set of threads waiting for a certain task to finish; once the task has finished, all waiting threads can continue with their business. In such a case you would use notifyAll() to wake up all waiting threads at the same time.
    Another case, for example mutually exclusive locking, only one of the waiting threads can do something useful after being notified (in this case acquire the lock). In such a case, you would rather use notify(). Properly implemented, you could use notifyAll() in this situation as well, but you would unnecessarily wake threads that can't do anything anyway.


    9. wait(long timeout)
    10. wait(long timeout, int nano)
    11. wait()

    The above three methods don't have distinct differences except for the waiting time. Actually BlockingQueue is a better mechanism in my opinion.


    12. finalize()

    The main two arguments against overriding Object.finalize() is that:

    • You don't get to decide when it's called.
    • It may not get called at all.

    The finalize method is called when an object is about to get garbage collected. That can be at any time after it has become eligible for garbage collection.
    Note that it's entirely possible that an object never gets garbage collected (and thus finalize is never called). This can happen when the object never becomes eligible for gc (because it's reachable through the entire lifetime of the JVM) or when no garbage collection actually runs between the time the object become eligible and the time the JVM stops running (this often occurs with simple test programs).
    If you rely on finalize for the correct operation of your application, then you're doing something wrong. finalize should only be used for cleanup of (usually non-Java) resources. And that's exactly because the JVM doesn't guarantee that finalize is ever called on any object.

    According to some experience, there is one and only one reason for overriding Object.finalize(), but it is a very good reason:
    To place error logging code in finalize() which notifies you if you ever forget to invoke close().

    @Override
    protected void finalize() throws Throwable
    {
        if( Global.DEBUG && !closed )
        {
            Log.Error( "FORGOT TO CLOSE THIS!" );
        }
        //super.finalize(); see alip's comment on why this should not be invoked.
    }
    

    相关文章

      网友评论

          本文标题:Java Class — Object

          本文链接:https://www.haomeiwen.com/subject/jazulxtx.html