java 基础篇
集合类: collection:集合类的父接口,集合长度不固定,数组长度固定 add()-添加元素 addAll()-添加集合元素 clear()-清空处理 contains()-是否包含 equals()-重写obj的方法,判断对象是否相等 hashcode()-重写obj的方法,判断对象的哈希码是否相等 isEmpty()-判空 iterator()-返回迭代器Iterator,hasNext() 以及next()进行迭代 remove()-移除某元素 size()-返回集合元素大小 toArray()-转为数组 list: add(index,xxx)-指定位置添加元素 addAll(index,xxx)-指定位置添加集合元素 get(index)-返回指定位置元素 indexOf(obj)-某元素在集合中的下标 lastIndexOf(obj)-某元素在集合中最后出现的下标 remove(index)-移除指定位置元素 set(index,obj)-替换指定位置元素 subList(from,to)-返回当前下标区间元素 sort(Comparator)-根据排序参数排序 toArray()-转为数组 arraylist: 以数组实现。节约空间,但数组有容量限制。超出限制时会增加50%容量,用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值。默认第一次插入元素时创建大小为10的数组。按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优势。 直接在数组末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e),remove(i),remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。当增加数据的时候,如果ArrayList的大小已经不满足需求时,那么就将数组变为原长度的1.5倍,之后的操作就是把老的数组拷到新的数组里面。 LinkedList是一个简单的数据结构,与ArrayList不同的是,他是基于链表实现的。 ? hashmap: 在HashMap中有两个很重要的参数,容量(Capacity)和负载因子(Load factor) Capacity就是bucket的大小,Load factor就是bucket填满程度的最大比例。如果对迭代性能要求很高的话,不要把 put函数大致的思路为:
get函数
HashMap不保证数据有序,LinkedHashMap保证数据可以保持插入顺序,而如果我们希望Map可以保持key的大小顺序的时候,我们就需要利用TreeMap了。 使用红黑树的好处是能够使得树具有不错的平衡性,这样操作的速度就可以达到log(n)的水平了。 ? LinkedHashMap是Hash表和链表的实现,并且依靠着双向链表保证了迭代顺序是插入的顺序。 ? 泛型: 通配符:<?> ?上限通配符 <? extends shape> 继承shape的子类或者本身 下限通配符 <? super shape> ?shape的父类或者本身 ? 代理模式: 给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。 静态代理:代理类是在编译时就实现好的。也就是说 Java 编译完成后代理类是一个实际的 class 文件。 目标对象(RealSubject )以及代理对象(Proxy)都实现了主题接口(Subject)。在代理对象(Proxy)中,通过构造函数传入目标对象(RealSubject ),然后重写主题接口(Subject)的request()方法,在该方法中调用目标对象(RealSubject )的request()方法,并可以添加一些额外的处理工作在目标对象(RealSubject )的request()方法的前后。 class Proxy implements InterfaceClass { private?InterfaceClass obj public Proxy(InterfaceClass obj) { this.obj = obj } public void xxxMethod() { prehandle() obj.xxxMethod() lasthandle() } } 动态代理是指在运行时动态生成代理类。即,代理类的字节码将在运行时生成并载入当前代理的 ClassLoader。 class Proxy implements InvocationHandle { private?InterfaceClass obj public Proxy(InterfaceClass obj) { this.obj = obj } public Object invoke(Object proxy,Method method,Object[] args) { prehandle() Object result = method.invoke(obj,args) lasthandle() return result } } ? 抽象类和接口类
? 浅拷贝和深拷贝 浅拷贝是拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。 深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。 ? 序列化: 遵守Serializabel 1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。 2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。 3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。 ? 异常捕获 try中的return语句已经执行了再去执行finally语句,不过并没有直接返回,而是等finally语句执行完了再返回结果。 finally块中的return语句会覆盖try块或者catch块中的return返回。 catch中的return语句先执行,确定了返回值后再去执行finally块,执行完了catch再返回。 finally块中如果没有return语句,在finally中修改变量,假如改变量本身,则不会影响返回值,假如修改变量内部的某个属性和某个元素,则会影响返回值。 ? 多线程: 采用实现Runnable、Callable接口的方式创见多线程时,优势是: 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。 在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。 劣势是: 编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。 使用继承Thread类的方式创建多线程时优势是: 编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。 劣势是: 线程类已经继承了Thread类,所以不能再继承其他父类。 ? 锁: synchronized: 对象锁,也可以用作类的锁 ReentrantLock:?显示的获取锁和释放锁 Lock: 显示的获取锁和释放锁 当一个线程得到一个对象后,再次请求该对象锁时是可以再次得到该对象的锁的。 具体概念就是:自己可以再次获取自己的内部锁。 Java里面内置锁(synchronized)和Lock(ReentrantLock)都是可重入的。 ReentrantLock便是一种公平锁,通过在构造方法中传入true就是公平锁,传入false,就是非公平锁。公平锁可以保证线程按照时间的先后顺序执行,避免饥饿现象的产生。 synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁; 通过Lock可以通过tryLock/isLocked知道有没有成功获取锁,而synchronized却无法办到。 ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。 可以通过readLock()获取读锁,通过writeLock()获取写锁。 Object类中相关的方法有notify方法和wait方法。因为wait和notify方法定义在Object类中,因此会被所有的类所继承。这些方法都是final的,即它们都是不能被重写的,不能通过子类覆写去改变它们的行为。 当前的线程必须拥有当前对象的monitor,也即lock,就是锁,才能调用wait()方法,否则将抛出异常java.lang.IllegalMonitorStateException。 线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。 要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。 被唤醒的线程是不能被执行的,需要等到当前线程放弃这个对象的锁,当前线程会在方法执行完毕后释放锁。 wait()/singal() 类似于 conditon的wait()/singal() ? 一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。因为处理器在进行重排序时是会考虑指令之间的数据依赖性,如果一个指令语句 2必须用到语句 1的结果,那么处理器会保证语句 1会在语句 2之前执行。 ? 在多线程中共享变量的时候,如果想要变量立即生效,那么使用volatile修饰符 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |