//hotspot的oop.hpp文件中class oopDesc
class oopDesc {
friend class VMStructs;
private:
volatile markOop _mark; //对象头部分
union _metadata { // klassOop 类元数据指针
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
public static void main(String[] args){
Object a = new Object(); // 16B 关闭压缩还是16B,需要是8B倍数;12B+填充的4B
int[] arr = new int[10]; // 24B 关闭压缩则是16B
}
public class ObjectNum {
//8B mark word
//4B Klass Pointer 如果关闭压缩则占用8B
//-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,
int id; //4B
String name; //4B 如果关闭压缩则占用8B
byte b; //1B 实际内存可能会填充到4B
Object o; //4B 如果关闭压缩则占用8B
}
```
2^11 * 4G
。不过jvm只是将指针左移三位,因此最大范围是2^3 * 4G = 32G
。如果大于32G,指针压缩会失效。如果GC堆大小在 4G以下,直接砍掉高32位,避免了编码解码过程-XX:+UseCompressedOops
(默认开启),禁止指针压缩:-XX:-UseCompressedOops
private static native void registerNatives()
将Object定义的本地方法和java程序链接起来public final native Class<?> getClass()
获取java的Class元数据public native int hashCode()
获取对象的哈希Codeprotected native Object clone() throws CloneNotSupportedException
获得对象的克隆对象,浅复制public final native void notify()
唤醒等待对象锁waitSet队列中的一个线程public final native void notifyAll()
类似notify(),唤醒等待对象锁waitSet队列中的全部线程public final native void wait(long timeout)
释放对象锁,进入对象锁的waitSet队列public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());}
public boolean equals(Object obj) { return (this == obj);}
public final void wait(long timeout, int nanos) throws InterruptedException;
//都是基于native void wait(long timeout)实现的
public final void wait() throws InterruptedException;
wait(long timeout, int nanos)、wait()
//jvm回收对象前,会特意调用此方法
protected void finalize() throws Throwable;
如不指定排序顺序,java里的默认排序顺序是升序的,从小到大
public boolean equals(Object obj) { return (this == obj);}
是使用 == 去比较的。equals方法的好处是我们可以重写该方法Collections.java
//Collections.sort(List<T> list),调用的是List的sort方法
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
List的sort 则调用了Arrays.sortList.java
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
如果Comparator c 为null,则是调用 Arrays.sort(Object[] a) ;最终调用LegacyMergeSort(归并排序)方法处理Arrays.java
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
LegacyMergeSort方法里的一段代码;最终底层是使用归并排序和compareTo来排序Arrays.java
......
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low &&
((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
int compare(T o1, T o2)
方法
Comparator提供了常用的几个静态方法thenComparing、reversed、reverseOrder(操作对象需要实现Comparator或者Comparable);可配合List.sort、Stream.sorted、Collections.sort使用。@Data
@AllArgsConstructor
static class Pair implements Comparator<Pair>, Comparable<Pair> {
Integer one;
Integer two;
@Override
public String toString() { return one + "-" + two; }
@Override
public int compareTo(Pair o) { return one.compareTo(o.one); }
@Override
public int compare(Pair o1, Pair o2) {return o1.compareTo(o2);}
}
public static void main(String[] args) {
List<Pair> col = Arrays.asList( new Pair(4, 6), new Pair(4, 2),new Pair(1, 3));
col.sort(Comparator.reverseOrder());
col.stream().sorted(Comparator.comparing(Pair::getOne).thenComparing(Pair::getTwo))
.forEach(item -> System.out.println(item.toString()) );
}
Collections.sort默认是升序排序的,可以看到reverseOrder将顺序反过来了;用了thenComparing的col则是先判断Pair::getOne的大小,如果相等则判断Pair::getTwo大小来排序result:
4-6
4-2
1-3
----------------
1-3
4-2
4-6
构造方法是每一个类独有的,并不能被子类继承,因为构造方法没有返回值,子类定义不了和父类的构造方法一样的方法。但是在同一个类中,构造方法可以重载
public class TestEquals {
int i;
public TestEquals() { i = 0; }
//构造方法重载
public TestEquals(int i) { this.i = i }
}
equals是用来比较两个对象是否相等的,可以重写该方法来实现自定义的比较方法;而hashCode则是用来获取对象的哈希值,也可以重写该方法。当对象存储在Map时,是首先利用Object.hashCode判断是否映射在同一位置,若在同一映射位,则再使用equals比较两个对象是否相同。
如果重写equals导致对象比较相同而hashCode不一样,是违反JDK规范的;而且当用HashMap存储时,可能会存在多个我们自定义认为相同的对象,这样会为我们代码逻辑埋下坑。
Object.wait是需要在synchronized修饰的代码内使用,会让出CPU,并放弃对对象锁的持有状态。而Thread.sleep则简单的挂起,让出CPU,没有释放任何锁资源
ObjectInputStream.readObject()
String one = new String("Hello");
两个对象和一个栈变量:一个栈变量one和一个new String()实例对象、一个"hello"字符串对象String s = "hello" ;
相当于执行了intern();先在常量池创建"hello",并且将引用A存入常量池,返回给s。此时String("hello").intern()会返回常量池的引用A返回 String one = "hello";
String two = new String("hello");
String three = one.intern();
System.out.println(two == one);
System.out.println(three == one);
result:
false // one虽然不等于two;但是它们具体的char[] value 还是指向同一块内存的
true // one 和 three 引用相同
A a = new A(); A b = a;
此时a和b指向同一块内存的对象@Getter
static class A implements Cloneable{
private B b;
private int index;
public A(){
b = new B(); index = 1000;
}
public A clone()throws CloneNotSupportedException{ return (A)super.clone(); }
}
static class B{
}
public static void main(String[] args) throws Exception{
A a = new A();
A copyA = a.clone();
System.out.println( a.getIndex() == copyA.getIndex() );
System.out.println( a.getB() == copyA.getB() );
}
//返回结果都是true,引用类型只是复制了引用值
true
true
public A clone() throws CloneNotSupportedException {
try {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(this);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream inputStream = new ObjectInputStream(byteIn);
return (A) inputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
throw new CloneNotSupportedException(e.getLocalizedMessage());
}
}