Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use the method of Object class in Java

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

This article mainly introduces the relevant knowledge of how to use the Object class method in Java, the content is detailed and easy to understand, the operation is simple and fast, and it has a certain reference value, I believe you will have something to gain after reading this Java Object class method. Let's take a look at it.

Foreword:

The full path to Java's Object class is java.lang.Object, which is the parent class compilation of all classes. When we create a class, if we don't explicitly inherit a parent class, it automatically inherits Object and becomes a subclass of Object (implicit inheritance). There are nine common methods in the Object class, which are getClass (), finalize (), toString (), equals (), hashcode (), wait (), notify (), notifyAll (), and clone ().

1. GetClass ()

First of all, the getClass () method is used to get the runtime class (Class) of an object, and then obtain the relevant information of the Person through the returned Class object, such as the constructor of the class, the methods of the class, and the member variables of the class. Different VM have different optimizations for Class, so the implementation of getClass () is not the same:

/ / Java implements getClass () public final native Class getClass () with native method; / / Android special implementation method private transient Class shadow$_klass_;public final Class getClass () {return shadow$_klass_;}

This is because Java's default Hotspot virtual machine does not open up a separate Method Area space, but is implemented by GC Heap's older Metaspace. Android uses ART VM, which makes the difference. There are a lot of books to read about runtime data partitioning, ClassLoader, and Class classes for different VM implementations, and I won't discuss it too much in this article.

2. Finalize ()

Finalize () is the protected method of Object, which is triggered when GC occurs. The general process is that when an object becomes GC Roots unreachable, GC determines whether the object overrides the finalize () method, and if not, it is recycled directly. Otherwise, if the object has not executed the finalize () method, it is placed in the F-Queue queue, and a low-priority thread executes the finalize () method of the object in the queue. After executing the finalize () method, GC determines again whether the object is reachable, and if it is not reachable, it is recycled; otherwise, the object is "resurrected".

Subclasses can override methods to implement (1) prevent objects from being recycled and (2) prevent objects from being recycled. To prevent an object from being recycled, you only need to have an accessible chain between the object and the GC ROOTS. Let's focus on how FileInputStream, FileOutputStream, Connection and other classes prevent users from forgetting to release resources. Here are some of the source codes of FileInputStream:

Protected void finalize () throws IOException {/ / Android add CloseGuard to ensure more secure FlieInputStream recycling if (guard! = null) {guard.warnIfOpen ();} / Java uses FileDescriptor to ensure that FileInputStream is unreachable and can be safely recycled if ((fd! = null) & & (fd! = FileDescriptor.in)) {close ();}} III. ToString ()

The toString () method returns the String representation of the object, which is familiar to every junior programmer. If you read the source code of Java carefully, you will know that many kinds of toString () methods are carefully crafted, just like Integer's toString () method, which is adapted to Android:

Public String toString () {return toString (this.value);} / / returns the Stringpublic static String toString (int I) {if (I = = Integer.MIN_VALUE) return "- 2147483648" of the specified decimal integer; / / small is an Android-specific variable that uses 2D Array to cache the String boolean negative = I of smaller (two-digit) digits

< 0; boolean small = negative ? i >

-100: I

< 100; if (small) { final String[] smallValues = negative ? SMALL_NEG_VALUES : SMALL_NONNEG_VALUES; if (negative) { i = -i; if (smallValues[i] == null) { smallValues[i] = i < 10 ? new String(new char[]{'-', DigitOnes[i]}) : new String(new char[]{'-', DigitTens[i], DigitOnes[i]}); } } else { if (smallValues[i] == null) { smallValues[i] = i < 10 ? new String(new char[]{DigitOnes[i]}) : new String(new char[]{DigitTens[i], DigitOnes[i]}); } } return smallValues[i]; } int size = negative ? stringSize(-i) + 1 : stringSize(i); // getChars()方法略 char[] buf = new char[size]; getChars(i, size, buf); return new String(buf);} 在实际开发中,复杂对象的toString()方法用Gson生成JSON来实现。 四、equals()和hashcode() equals()方法和hashcode()方法,我要放在一起说。 // 其实Object方法默认的equals()也是比较引用是否相同public boolean equals(Object obj) { return (this == obj);} 一般来说==比较的是引用是否相同,而equals()则是需要重写来比较值是否相同。重写equals()要注意以下几点注意事项: (1)对任意x,x.equals(x)一定返回true (2)对任意x,y,如果x.equals(y)返回true,则y.equals(x)也一定返回true (3)对任意x,y,z,如果x.equals(y)返回true,y.equals(z)也返回true,则x.equals(z)也一定返回true (4)对任意x,y,如果对象中用于比较的信息没有改变,那么无论调用多少次x.equals(y),返回的结果应该保持一致,要么一直返回true,要么一直返回false (5)对任意不是null的x,x.equals(null)一定返回false,如果两个对象equals()方法相等则它们的hashCode返回值一定要相同。我们先看一下String是如何实现equals()的: //比较这个String和另一个对象,当且仅当那个对象不为null且与这个String有相同的字符排列顺序时返回truepublic boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = length(); if (n == anotherString.length()) { int i = 0; while (n-- != 0) { if (charAt(i) != anotherString.charAt(i)) return false; i++; } return true; } } return false;} 我们再看一下String是如何实现hashcode()的: // 缓存String的hashcode()private int hash; // 默认为0public int hashCode() { int h = hash; final int len = length(); if (h == 0 && len >

0) {for (int I = 0; I

< len; i++) { h = 31 * h + charAt(i); } hash = h; } return h;} 反之,如果两个对象的hashCode返回值相同,它们的equals()方法可以不返回true。这种情况叫做hash碰撞。HashMap处理hash碰撞的方法叫链地址法,除此以外hash碰撞还可以用ArrayMap采用的开放地址法解决,这些不在今天的话题讨论范围之内,不做赘述。 五、wait()、notify()和notifyAll() wait()、notify()和notifyAll()三个方法实现了Java的wait-notify机制。 先看wait()方法,wait()方法用来让持有此对象的监视器的线程处于阻塞状态,有参数不同的三个同名方法: // 无参方法的Java与Android实现方式没有区别// 如果不在synchronized修饰的方法或代码块里调用,如果没有获取锁,则会抛出IllegalMonitorStateException 异常// 如果当前线程在等待时被中断,则抛出InterruptedException异常public final void wait() throws InterruptedException { wait(0);}// timeout是线程等待时间,时间结束则自动唤醒,单位ms// Java默认的实现方式,native实现public final native void wait(long timeout) throws InterruptedException;// Android的特殊处理public final void wait(long timeout) throws InterruptedException { wait(timeout, 0);}// nanos是更精确的线程等待时间,单位ns(1 ms == 1,000,000 ns)// Java默认的实现方式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);} / / the special treatment of Android is changed to native to implement @ FastNativepublic final native void wait (long timeout, int nanos) throws InterruptedException

Ns means nanosecond, 1s = = 1000000000ns. The speed of light is the fastest in the world, and light travels only 0.3m in 1ns time. In general, PC's CPU calculates a simple instruction, such as the time of 2: 3: 5 is 2~4ns. We usually only use the wait () method with one parameter or the no-parameter method, and the second parameter is rarely used in real development.

After the parameterized wait () method call, the thread can enter the ready state after the wait time ends (hereinafter referred to as "Wake up"); after the non-parameterized wait () method call, it must wait for the thread holding the object monitor to actively call the notify () or notifyAll () method before it can be awakened. The difference is that the notify () method wakes up a single thread waiting on this object monitor, and if all threads are waiting on this object, it randomly wakes up one of them, while the notifyAll () method wakes up all threads waiting on this object monitor.

Public final native void notify (); public final native void notifyAll ()

Wait (), notify (), and notifyAll () are all final native methods, so we don't need to understand how they are implemented internally for the time being. We just need to know that this is Java's wait-and-notify (wait-notify) mechanism and learn their application scenarios.

For example:

(1) the time for the employer to decide to hire a programmer is uncertain. For example, many people may have to be interviewed, which need to be considered comprehensively and cannot be fed back in time.

(2) each programmer needs wait () after the interview.

(3) the programmer that the employer thinks is the most suitable after comprehensive consideration, let HR notify ()

(4) finally, the selected programmers go to work happily, and other programmers will wait.

In development, the most widely used wait-notify mechanism is to implement the producer / consumer model, which can solve most of the concurrency problems and improve the overall data processing speed of the program by balancing the working capacity of the production thread and the consumption thread.

Considerations for using the wait-notify mechanism:

(1) wait (), notify (), and notifyAll () must be used in synchronized-decorated methods or code blocks

(2) use wait () in the while loop rather than under the if statement to ensure that the condition triggered by wait () is checked before and after thread sleep (to prevent false wakeup)

(3) the wait () method must be called on an object shared by multiple threads.

Let's first define a producer of notes (1) and (2) and add elements to the queue:

/ / producer, with detailed comments public class Producer implements Runnable {private Queue queue; private int maxSize; public Producer (Queue queue, int maxSize) {this.queue = queue; this.maxSize = maxSize } @ Override public void run () {/ / there is an endless loop to facilitate the demonstration. Don't do while (true) {/ / (1) wait (), notify () and notifyAll () in real development. You must use synchronized (queue) {/ / (2) in the while loop instead of under the if statement to use wait () in the method or code block decorated by synchronized. Make sure that the condition triggered by wait () is checked before and after thread sleep (to prevent false wakeup) while (queue.size () = = maxSize) {try {System.out.println ("Queue is Full") / / the producer thread enters the waiting state, and all threads waiting on this object monitor (in fact, the only consumer thread) start competing for lock queue.wait ();} catch (InterruptedException ie) {ie.printStackTrace () }} Random random = new Random (); int I = random.nextInt (); System.out.println ("Produce" + I); queue.add (I) / / Wake up all threads in the waiting pool of this Queue object (actually only that consumer thread), and wait for the object monitor queue.notifyAll ();}

Define an identical consumer, except for removing elements from the queue, the other code is the same as above

/ / Consumer, note public class Consumer implements Runnable {private Queue queue; private int maxSize; public Consumer (Queue queue, int maxSize) {this.queue = queue; this.maxSize = maxSize } @ Override public void run () {while (true) {synchronized (queue) {while (queue.isEmpty ()) {System.out.println ("Queue isEmpty"); try {queue.wait () } catch (InterruptedException ie) {ie.printStackTrace ();}} int v = queue.remove (); System.out.println ("Consume" + v); queue.notifyAll ();}

Finally, write the test code that conforms to (3):

The public void test () {/ / (3) wait () method must be called on an object shared by multiple threads. / / this queue is the object Queue queue = new LinkedList (); int maxSize = 5; Producer p = new Producer (queue, maxSize); Consumer c = new Consumer (queue, maxSize); Thread pT = new Thread (p); Thread pC = new Thread (c). / / producer thread starts to acquire lock pT.start (); / / consumer thread starts pC.start ();}

View the running results:

Produce 1604006010

Produce 1312202442

Produce-1478853208

Produce 1460408111

Produce 1802825495

Queue is Full

Consume 1604006010

Consume 1312202442

Consume-1478853208

Consume 1460408111

Consume 1802825495

Queue is Empty

In addition to the above implementation of wait () / notity () using the synchronized keyword with Object, the producer-consumer model can also be implemented using the Lock interface with Condition's await () and signalAll (), and can also be implemented in BlockingQueue, but these are outside the scope of this article and will not be discussed in detail.

6. Clone ()

The Object class of the Java language implements the Cloneable interface, and an object can generate an object by calling the Clone () method. It should be noted that the clone () method is not in the Cloneable interface, but in the Object class. Cloneable is an identification interface, and the object identifying this class can be copied. If the clone () method is called without implementing the Cloneable interface, an error will be reported.

/ / protected native Object clone () throws CloneNotSupportedException;protected Object clone () throws CloneNotSupportedException {if (! (this instanceof Cloneable)) {throw new CloneNotSupportedException ("Class" + getClass (). GetName () + "doesn't implement Cloneable");} return internalClone ();} / / Native helper method for cloning.private native Object internalClone ()

In addition to new coming out and clone () coming out, objects can also be generated through reflection and deserialization, but these two ways are beyond the scope of our topic today.

The so-called prototype pattern is the design pattern that uses clone () to generate objects. You need to understand the concepts of deep copy and shallow copy in advance. The data type in Java is divided into basic type and reference type. If the variable in a method is a basic type, the variable is directly stored in the stack frame of this method, such as int, long, etc., while the reference type stores the pointer of this variable in the stack frame, pointing to the address of the entity in the heap, such as String, Array, etc. Deep and shallow copies are only for reference data types

For example, a method has a basic type parameter and a reference type parameter, and reassigning the parameter in the method body will affect the incoming reference type parameter, but not the basic type parameter, because the basic type parameter is value passing, and the reference type is reference passing. It's important to note that Java only passes values, because Java's reference passing passes the address of the reference type object in the heap memory space, and reference passing is just a habitual statement, which involves JVM and the operating system and doesn't talk too much about it.

First define a user class:

/ / this is a very simple user class public class User {private String name; private int age; public User (String name, int age) {this.name=name; this.age=age;} public String getName () {return name;} public void setName (String name) {this.name=name;} public int getAge () {return age } public void setAge (int age) {this.age = age;} @ Override public String toString () {return "User {name='" + name + ", age=" + age +'}';}}

Write test code:

Private int Xing10 * public void updateValue (int value) {value = 3 * value;} private User user= new User ("Tang Xijing", 18); public void updateUser (User student) {student.setName ("Guan Chenchen"); student.setAge (16);} public void test () {System.out.println ("value of x before calling:" + x); updateValue (x); System.out.println ("value of x after call:" + x) System.out.println ("value of user before calling:" + user.toString ()); updateUser (user); System.out.println ("value of user after call:" + user.toString ());}

The Log print results are as follows:

The value of x before calling: 10

The value of x after call: 10

The value of user before calling: User {name=' Tang Xijing, age=18}

The value of user after calling: User {name=' tube Chenchen, age=16}

The flowchart of the method (updateValue ()) for passing the basic type:

Flowchart of the method (updateUser ()) that passes the reference type:

But there are exceptions, such as the String type and

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 237

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report