java基础之Object类
Posted 简单就是幸福
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基础之Object类相关的知识,希望对你有一定的参考价值。
1、简单概述
Object类是是所有类的父类,对于java中的任意一个类来说,都是Object类的子类。
Object类中的源码:
public class Object {
// 本地注册一些必要信息
private static native void registerNatives();
static {
registerNatives();
}
// 获取得到字节码文件对象。对于每一个类来说,是唯一的
public final native Class<?> getClass();
// 默认返回的是对象在内存中的地址值
public native int hashCode();
// equals方法默认比较的就是两个对象的hashCode值
// 所以equals方法和hashCode方法通常都会来进行重写
public boolean equals(Object obj) {
return (this == obj);
}
// 看到这个权限修饰符就知道是要留给子类来去重写的。
// 之后这里会提到这个克隆方法。
protected native Object clone() throws CloneNotSupportedException;
// toString方法,可以看到打印出来的是类名+@+该对象十六进制的整数。
// 这个方法一般来说,都会去进行重写
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// 这些方法出现在Object类中,首先想到的是Object是所有对象的父类。
// 那么下面的肯定是和对象有关的方法。
// 通过方法注释反复看到一个关键字:monitor对象监视器
// 用对象来作为一个监视器,所有的线程都将会去抢夺这个监视器。如果抢到了,那么来进行执行,如果没有抢到,那么就进入到阻塞阶
// 段。notify、notifyAll和wait方法通常都是放到一个synchronized修饰的代码块来或者是方法中来进行使用的。
// 需要注意的是:对象监视器必须是同一个而且必须要使用这个对象监视器来调用方法来唤醒其他线程等等。
// notify是随机唤醒对象监视器上的一个线程
// 还需要注意一点的是:调用了整个方法,并不会立马释放掉对象监视器,而是需要等待下面的逻辑执行完成之后才会去进行调用。
public final native void notify();
// notifyAll是唤醒对象监视器上的所有线程。这个时候就会有争夺对象监视器的现象
public final native void notifyAll();
// 这个方法指的是在对象监视器上等待获取得到对象监视器的使用权。超过时间之后,将会自动再次去进行抢夺
// 在此期间,会释放掉占用的锁对象已经进入到超时等待状态中去。
public final native void wait(long timeout) throws InterruptedException;
// 从这里可以看到调用的都是上面的方法
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);
}
public final void wait() throws InterruptedException {
wait(0);
}
// 子类重写的方法。这里是在垃圾回收机制之前做的是结尾工作。
protected void finalize() throws Throwable { }
所以我更喜欢将这个对象监视器理解成是一个数据结构来盛放线程的,对于一个线程执行完成或者是执行过程中释放了对象监视器,那么对象监视器会随机挑选一个线程来进行执行syncronized代码块中的逻辑。
对于每一个线程来说,都会有寄存器来记录上线程的线程状态,然后将线程的执行现场来进行恢复。
同时注意一点,native关键字修饰的方法是本地方式,底层是通过c和c++来进行实现的。
所以没有方法体的方法不一定就是抽象方法;抽象方法一定是没有方法体的;
2、代码演示
演示一下通过Object类中的wait方法和notify方法来进行线程间的通信:
2.1、Demo1
public class Foodie extends Thread {
private BaoZi baoZi;
public Foodie(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
synchronized (baoZi) {
for (; ; ) {
synchronized (baoZi) {
// 如果有包子,那么就开始进入到等待状态;如果说没有包子,那么就开始制作包子
if (baoZi.getFlag() == false) {
System.out.println("没有包子,通知厨师来包包子");
try {
// 线程就会在对象监视器上进行等待
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 程序执行到了这个地方,说明了是没有包子的。那么开始做包子
baoZi.setFlag(false);
baoZi.notify();
}
}
}
}
}
public class Cook extends Thread {
private BaoZi baoZi;
public Cook(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
synchronized (baoZi) {
for (; ; ) {
// 如果有包子,那么就消费;如果没有,那么就进行等待
if (baoZi.getFlag() == true) {
try {
System.out.println("有包子,开始等消费者来进行消费.......");
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 程序走到了这里,那么就说明这里有了包子
// System.out.println("开始做包子,然后将包子修改成没有包子");
baoZi.setFlag(true);
baoZi.notify();
}
}
}
}
public class BaoZi {
// FLAG为true的时候,表示的是有包子;为false的时候,表示的是没有包子
private boolean flag;
public Boolean getFlag() {
return flag;
}
public void setFlag(Boolean flag) {
this.flag = flag;
}
}
public class DemoTwo {
public static void main(String[] args) {
BaoZi baoZi = new BaoZi();
Cook cook = new Cook(baoZi);
Foodie foodie = new Foodie(baoZi);
cook.start();
foodie.start();
}
}
通过上面的例子可以看到控制台中的输出信息:
没有包子,通知厨师来包包子
有包子,开始等消费者来进行消费.......
没有包子,通知厨师来包包子
有包子,开始等消费者来进行消费.......
2.2、Demo2
/**
* 使用三条线程交替打印出来ABC
*/
public class DemoOne {
private static int num = 1;
public static void main(String[] args) {
new Thread(() -> {
while (true){
synchronized (DemoOne.class) {
while (num != 1) {
try {
DemoOne.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num=2;
DemoOne.class.notifyAll();
System.out.println("A");
}
}
}).start();
new Thread(() -> {
while (true){
synchronized (DemoOne.class) {
while (num != 2) {
try {
DemoOne.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num=3;
DemoOne.class.notifyAll();
System.out.println("B");
}
}
}).start();
new Thread(() -> {
while (true){
synchronized (DemoOne.class) {
while (num != 3) {
try {
DemoOne.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num=1;
DemoOne.class.notifyAll();
System.out.println("C");
}
}
}).start();
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3、克隆方法
上面提到过的克隆方法。其实克隆就相当于是一份拷贝方法。为了更加方便容易的来书写我们的代码而写。
包括一些强软弱虚等对象的引用,其实本质上是由于程序员没有手动释放占用的内存,而是由GC算法来决定的。使用GC来进行回收的时候,需要在什么时间段来进行回收。
千里之行,始于足下。不积跬步,无以至千里
以上是关于java基础之Object类的主要内容,如果未能解决你的问题,请参考以下文章