java核心技术之基础篇(二)

 一、动态代理基于什么原理?谈谈java反射机制

典型回答: 反射机制是java 语言提供的一种基础功能,赋予程序在运行时自省的能力。通过反射我们可以直接操作类或对象,比如获取某个对象的类定义,获取类声明的属性和方法,

调用方法或者构造对象,甚至可以运行时修改类定义。

 动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似的机制做到的,比如用来包装RPC调用、面向切面编程(AOP)。

反射,是引用运行时的自省能力,赋予了java语言意外的活力,通多运行时操作元数据或对象,java可以灵活的操作运行时才能确定的信息,而动态代理则是一种在开发中应用广泛的技术,很多繁琐的重复编程都可以被动态代理优雅的解决。

知识扩展:(1)、关于反射,反射提供的AccessibleObject.setAccessible. 他的子类大多重写这个方法,这里所谓的accessible 可以理解成修饰成员的 public、protected、private,这意味着我们可以在运行时修改成员访问限制.

setAccessible 的应用场景很普遍,比如,在ORM 框架中,我们为一个java对象,运行时自动生成 getter,setter的逻辑,这是加载或者持久化数据非常必要的,框架通常会重复利用反射做这个事情,不需要开发者手动写类似重复的代码。

(2)、 动态代理解决了什么问题呢?首先她是一种代理机制,代理可以看作是对调用目标的一个包装,我们对目标代码的调用通过代理完成,通过代理可以让调用者与实现者之间解耦。

二、对比 Vecter、ArrayList、LinkebList 有何区别?

  日常开发中有效的管理和操作数据是非常有必要的,java提供了强大的集合框架,大大提高了开发者这效率;针对上面问题典型的回答是:

  三者都实现了集合框架中的List,也就是所谓的有序集合,因此功能比较相近,比如都提供按位置进行定位、添加、删除的操作,都提供便利器以遍历其内容等。但因为具体的设计区别,在行为、性能、线程上表现又有很大的不同。

  Vector 是java 早期提供的线程安全的动态数组,如不需要考虑线程安全不推荐使用,毕竟同步是有额外的开销的。Vector 内部使用对象数组保存数据,可以根据需要自动的增加容量,当数组已满时,会创建新的数组,并拷贝原有的数组数据。 

  ArrayList 是应用广泛的动态数组实现,本身不是线程安全的 ,性能好很多,与Vector 相似,Arraylist也可根据需要扩展容量,两者调整逻辑的区别是:Vector 扩容提高一倍,Arraylist 则提高50%,

 LinkedList 是java的双向链表 ,所以不需要像上面的那样扩容,他也不是线程安全的。

扩展部分:一般来说可以补充一些不同容器适合的场景:

(1)、Vector和ArrayList 作为动态数组,其内部元素以数组形式顺序存储的,所以非常适合随机访问的场合。除了尾部插入和删除元素,往往性能会相对较差,比如我们在中间位置插入一个元素,需移动后续所有元素。

(2)、而linkedList 进行节点插入、删除高效很多,但是随机访问性能要比动态数组慢。

三、对比 Hashtable、HashMap、TreeMap 有什么不同?谈谈你对HashMap的掌握。

典型回答:三者都是最常见的一些Map的实现,是以键值对的形式存储和操作数据的容器类型。

Hashtable 早期的java类库提供的哈希表的实现,本身是同步的,不支持null 键和值,由于同步的开销,很少推荐使用,

HashMap 应用广泛的哈希表的实现,行为上大致与Hashtable 一致,主要区别在于HashMap 不同步,支持null 键和值,通常情况下,Hashmap 进行 put(),get()方法,可以达到常数时间的性能,他是绝大部分利用键值对存取场景的首选。

TreeMap 则是基于红黑树的一种提供顺序访问的Map,和Hashmap 不同,他的get、put、remove操作都是O(log(n))的时间复杂度,具体顺序有Comparator 决定。

扩展部分:本来这里想聊一聊HashMap源码的分析,HashMap内部实现的基本点,以及容量 、负载系数、树化这些知识点,奈何笔者学浅,等我好好钻研一番再来总结

-------------这是HashMap 源码分析未总结的分割线--------------------------------------------------------------------------------------

四、如何保证集合是线程安全的?ConcurrentHashMap如何实现高效的线程安全?

  java 语言提供了并发包(java.util.concurrent),为高度并发需求提供了更加全面的工具支持。针对上面问题的典型回答:java提供了不同层面的线程安全支持,在传统集合框架内部,除了Hashtable等同步容器,还提供了所谓的同步包装器(Synchronized Wrapper),我们可以调用Collections 工具类提供的包装方法,来获取一个同步的包装容器,但是他们都是利用非常粗粒度的同步方法,在高并发的情况下性能比较低。

另外,更加普遍的选择是利用并发包提供的线程安全容器类,他提供了:

1、各种并发容器,比如 ConcurrentHashMap、CopyOnWriteArrayList.

2、各种线程安全队列(Queue/Deque),

3、各种有序容器的线程安全版本等。

具体保证线程安全的方式,包括有从简单的synchronize 方式,到基于更加精细化的,比如基于分离锁的实现的ConncurrentHashMap等并发实现,具体选择要看实际的开发场景需求,总体来说,并发包内提供的容器通用场景,远远优于早期的简单同步实现。

五、谈谈接口与抽象类的区别?

 典型回答:接口和抽象类是java 面向对象设计的两个基础机制。

接口是对行为的抽象,他是抽象方法的集合,利用接口可以达到API 定义和实现的分离的目的,接口不能实例化;不能包含任何非常量成员,任何field 都是隐含着 public static final的意义;同时,没有非静态方法,也就是说要么是抽象方法,要么是静态方法。java类库中定义额非常多的接口,如:java.util.List

抽象类是不能实例化的类,用abstract 关键字修饰class ,其目的主要是代码的重用。除了不能实例化,形式上和一般java类没有太大区别,可以有一个或多个抽象方法,也可以没有抽象方法。抽象类大多用于抽取相关java类的共有方法实现或者共同成员变量,然后通过继承的方式达到代码的复用,java 标准库中,collection 框架,很多通用的部分被抽取成为抽象类 ,例如:java.util.AbstractList。

另外,java类实现interface 使用 implements ,继承 abstract class 使用extends 关键字,

public class ArrayList extends AbstractList,RandemAccess,Cloneable,java.io.Serializable{............}

上面提到了面向对象的设计,现在就来夯实一下基础,都知道面向对象的基本要素:封装、继承、多态。

封装的目的是隐藏事物内部的实现细节,以便提高安全性和简化编程。封装提供了合理的边界,避免外部调用者触及到内部的实现细节,在日常开发中多线程环境暴露的内部状态,导致并发修改问题。从另一角度看,封装即隐藏,避免太多无意义的细节浪费精力。

继承是代码复用的基础机制,但要注意这是一种非常紧耦合的关系,滥用会有反效果;

多态,我会想到override 、overload、向上转型。简单说 ,重写是父子类中相同名字参数的方法,不同的实现;重载是相同名字的方法,但不同的参数,本质上这些方法的签名是不一样的;

再对面向对象编程的设计原则进行简单介绍:

也就是所谓的S.O.L.I.D

单一职责、开关原则、里氏替换原则、接口分离原则、依赖反转原则

猜你喜欢

转载自www.cnblogs.com/liu321kai/p/9264296.html