Java Object对象相关问题分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dreamcatcher1314/article/details/82386240
package java.lang;

public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    // 类加载器
   //返回Object 的运行时类
    public final native Class<?> getClass();

   
    public native int hashCode();

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

   
    protected native Object clone() throws CloneNotSupportedException;

  
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

  
    public final native void notify();

   
    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 >= 500000 || (nanos != 0 && timeout == 0)) {
            timeout++;
        }

        wait(timeout);
    }

  
    public final void wait() throws InterruptedException {
        wait(0);
    }

    protected void finalize() throws Throwable { }
}

为什么不用继承Object对象,就可以拥有Object的方法,虚拟机做了什么

JVM在编译源代码时,在遇到没有继承Object的对象的时候,编译器会默认指定一个默认的父类Object

Object 和接口的关系,接口是否继承Object

接口没有继承顶级父类,会隐式的声明一套和Object中的方法签名完全一样的方法,这也就符合万物皆对象的面向对象思想,任何对象直接或间接的跟Object对象有关

1. getClass()方法,返回的是运行时类Class,也就是当前运行类的字节码对象,可以获取到构造器、属性、方法

Java中获取Class对象的方式:

a.通过类名的方式 ClassName.class 编译期,不能执行到静态信息和动态信息

b.通过Class的方法中,使用类的全路径方式 Class.forName("类路径名"); 运行时期,可以执行到静态信息,不能获取到动态信息

c.通过运行实例类过去 Object.getClass(); 运行时期,可以到所有的信息

它们获取到的Class字节码对象的区别?

Classd对象和实例对象的关系?(https://blog.csdn.net/javazejian/article/details/70768369?utm_source=gold_browser_extension

过去到Class,跟反射相关。

2.重写equals()方法,为什么也需要重写hashcode()方法

对象判断相当obj==obj1;

equals(Object obj){

this==obj;

}

如果重写了equals方法,没有重写hashCode()方法;

会出现equals()相等为true; 而obj==obj1是对象判断,取出的是对象散列值,所以为false。所以显然没有达到想要的效果,需要得到这个对象也相等


 

        public final boolean equals(Object o) {
           if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public final int hashCode() {
            return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
        }

3. hashcode()算法 javaHashCode算法是通过存储地址值和对象信息算出来的

String,Long,Double,HashMap等对象都重写了hashCode()方法和equals()方法,为了比较的对象和数值有关

Integer 返回原来的value值

Hash冲突的解决方案:

1.链表的方式:

2.再哈希方法:当发现冲突的时候,再次计算hash值来得到

3.开放地址:线性探测再散列,二次探测再散列,伪随机探测再散列

4.建立公共溢出区

Long、Double重写HashCode算法

    public int hashCode() {
        return (int)(value ^ (value >>> 32));
    }

Long,Double重写hashCode() 做右移32位的原因?

为了避免高32位相同、低32位不同hashCode()生成的key一样,推荐的做法是将高32位和低32位做异或运算,

id >>> 32 无符号右移32位,高32位变成低32位,再与原有的id进行异或运算,再强转int取低32位

String重写hashCode算法

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

1.31是一个不大不小的奇素数,不至于乘以其他数时溢出,或太小以至于Hash表太小,分散不开

2.31会被JVM优化,31*i=(i<<5)-i;

String重写hashCode算法的说明—— https://cloud.tencent.com/developer/article/1113699

4.Java 克隆方法——原型设计模式,深克隆和浅克隆的区别

浅克隆是引用的克隆,对象引用指向同一个对象

深克隆是克隆创建对象,对象地址不同

实现深度克隆的方式,实现Cloneable接口,重写clone()方法

new创建对象时,首先查看new操作符后面的类型,知道了对象类型,才知道分配多大的内存空间。分配内存之后,再调用构造器函数,填充对象的个域,然后将他的引用(地址)发布到外部,通过引用操作对象

clone方法跟new方法相似

5.wait()方法,每个对象都有monitor(即锁)

如果调用对象wait()方法,当前线程必须拥有对象的monitor(即锁),调用wait()必须在同步代码块中或同步方法里面(synchorinized),否则会抛出java.lang.IllegalMonitorStateException异常

调用wait()方法时,相当于交出当前对象的monitor来释放锁,让线程处于等待状态,通过对象的notify()和notifyAll()方法来实现线程同步唤醒。这一点也是跟Thread.sleep()方法的区别,sleep()不释放锁

6. finalize() 方法

猜你喜欢

转载自blog.csdn.net/dreamcatcher1314/article/details/82386240
今日推荐