美文网首页Java的那些事儿
Java基础宝典(一)

Java基础宝典(一)

作者: 简单就好_1897 | 来源:发表于2019-04-17 17:30 被阅读0次

1.Java中的Object类的共有方法

toString(),HashCode(),wait(),notify(),equals(),getClass(),clone(),finalize();

2.Hash 碰撞冲突

  产生:对象Hash的前提是实现了equals()和hashCode()两个方法,而HashCode()的作用是保证了对象返回唯一的hash值,但是当两个对象计算值一样时,这样就会发生碰撞冲突。 因此发生hash冲突的前提是hashCode返回相等

  解决:

    1).开放地址法

    2).再哈希法

    3).拉链法 (HashMap就是使用此方法,如果hash冲突,那么就通过hashCode()返回的值,找到对应的bucket(哈希桶),然后将对象追加到桶的最后面,即在遍历链表,在最后一个节点追加这个冲突的对象)

    4).建立一个公共溢出区

3.HashMap和HashTable的区别

  两者几乎完全相像,但主要的区别有:线程安全性,同步(synchronization),以及速度。

  HashMap不安全

  HashTable安全  因为查询有增删操作中加了锁

4.HashCode 作用,如何重载hashCode方法

1)hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;

2)如果两个对象相同,就是适用于equals(Java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;

3)如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用一致,否则就会违反上面提到的第2点;

4)两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。

再归纳一下就是hashCode是用于查找使用的,而equals是用于比较两个对象的是否相等的。

5.Java代理模式

    代理模式:是一种设计模式,目的是希望能做到代码重用。具体的讲:代理设计模式是不是直接访问被代理对象的方式,而是通过代理对象去访问的。

如:商户 --->明星经纪人 ------->明星

    房子---->中介------------>房东

    分为动态代理和静态代理

    我们根据加载被代理类(目标对象)的时机不同,将代理分为静态代理和动态代理。

1)如果在代码编译时能确定被代理的类是哪一个,那么就可以直接使用静态代理。

2)如果在代码编译时不能确定被代理类是哪一个,那么可以使用动态代理。 流行框架有:RPC、Spring下的AOP机制。

    动态代理主要用到的一个类和一个接口,分别为Proxy类与InvocationHandler接口

    每一个动态代理类都必须要实现InvocationHandler这个接口(代码中的中介) ,内部是通过反射实现的。

    InvocationHandler接口中的方法

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable

    //proxy:  指代我们所代理的那个真实对象

    //method:  指代的是我们所要调用真实对象的某个方法的Method对象

    //args:  指代的是调用真实对象某个方法时接受的参数

    Proxy类的方法

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

//loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

//interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

//h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

使用方式  Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner

            .getClass().getInterfaces(), handler);

6.Java 泛型

泛型:是JDK5中引入的一个新特性,提供了编译时类型安全检查机制,改机制运行程序员在编译时检测到非法的类型。

public <T> void Sort(T[] t) {

Arrays.sort(t);

}

它只会对编译时期检测,运行时,无法检测,亲测List<>中可以反射注入一些其他类型的数据,并且size增加了,也可以list.get()到它

7.Synchronized

常见的三种使用方法

  1)普通的同步方法,锁是当前实例对象

  2)静态的同步方法,锁是当前类的Class对象,字节码数据存在永久态中,是该类的一个全局锁。

  3)对于同步代码块,锁是synchronized括号中配置的对象。

  通过反汇编代码可以观察到:

    同步代码块是使用MonitorEnter和MoniterExit指令实现的,在编译时,MonitorEnter指令被插入到同步代码块的开始位置,MoniterExit指令被插入到同步代码块的结束位置和异常位置。

          任何对象都有一个Monitor与之关联,当Monitor被持有后将处于锁定状态。MonitorEnter指令会尝试获取Monitor的持有权,即尝试获取锁。

    同步方法依赖flags标志ACC_SYNCHRONIZED实现,字节码中没有具体的逻辑,可能需要查看JVM的底层实现(同步方法也可以通过Monitor指令实现)。

ACC_SYNCHRONIZED标志表示方法为同步方法,如果为非静态方法(没有ACC_STATIC标志),使用调用该方法的对象作为锁对象;

如果为静态方法(有ACC_STATIC标志),使用该方法所属的Class类在JVM的内部对象表示Klass作为锁对象。

8.ReentrantLock

    这种比较常见大家也都在用,主要是防止资源使用冲突,保证同一时间内只有一个操作可以使用该资源。

但与synchronized的明显区别是性能优势(伴随jvm的优化这个差距在减小)。同时Lock有更灵活的锁定方式,公平锁与不公平锁,而synchronized永远是公平的。

  ReentrantLock lock=new ReentrantLock();//默认为false,非公平锁

  ReentrantLock lock=new ReentrantLock(true);//公平锁

  不公平锁与公平锁的区别:

  公平情况下,操作会排一个队按顺序执行,来保证执行顺序。(会消耗更多的时间来排队)

  不公平情况下,是无序状态允许插队,jvm会自动计算如何处理更快速来调度插队。(如果不关心顺序,这个速度会更快)

9.乐观锁与悲观锁

1) 悲观锁

    总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,

用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

2)乐观锁

    总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。

乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。

在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

两种锁的使用场景

从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,

加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

10.Volatile

JVM底层volatile是采用“内存屏障”来实现的。观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令,

lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

    I. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内

      存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

    II. 它会强制将对缓存的修改操作立即写入主存;

    III. 如果是写操作,它会导致其他CPU中对应的缓存行无效。

相关文章

网友评论

    本文标题:Java基础宝典(一)

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