欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java笔记,

来源: javaer 分享于  点击 23832 次 点评:17

Java笔记,


前言

大二上的时候选了Java的课,一边学着,一边磕磕绊绊地做着项目。
最近,越来越感觉到自己对Java的掌握还不够深刻,并且,一些有关Java的笔试面试题也经常让我困惑。
因此,打算在近期对Java部分的知识进行一次系统的复习,主要关注Java类库源码,JVM,对Java一些特性的深入理解。

持续更新。

  • 2016/4/8 Java集合框架
  • 2016/4/10 封装、继承、多态;抽象类和接口。
  • 2016/4/11 泛型

Java集合框架

Java提供了一些能够有效组织和操作数据的数据结构,这些数据结构通常称为Java集合框架

Java集合框架支持两种容器:

  • collection:存储元素集合
  • map:存储键值对

1 collection

  • Set:用于存储一组不重复的元素
    • 具体实现:TreeSet,HashSet,LinkedHashSet
  • List:用于存储一个有序的元素集合
    • 具体实现:Vector,Stack,ArrayList,LinkedList
  • Queue:用于存储先进先出方式处理的对象
    • 具体实现:PriorityQueue

TreeSet

基于TreeMap实现,实质上是将TreeSet的元素作为键,一个空的Object作为值,存入TreeMap中。具体细节在TreeMap部分讨论。

HashSet

基于HashMap实现。

LinkedHashSet

基于LinkedHashMap实现

Vector

实现方式与ArrayList类似。
区别:
1. Vector包含了一些不属于集合框架的传统方法
2. Vector是同步的

Stack

基于Vector实现的栈,先进后出。

ArrayList

1.实现方式
ArrayList基于数组实现。
2.各操作复杂度
get/set方法直接访问对应下标即可,复杂度是O(1)的。
add/delete方法的复杂度是O(n)的,
其中,add过程如下:
插入元素E到index处:将(index,end)间的内容复制到(index+1,end+1),并将index处的内容置为E。其中数组复制的部分是由c/c++实现的,效率很高。
3.扩容
当数组容量不够时,newCapacity=1.5*oldCapacity
创建大小为newCapacity的数组,然后将旧数组复制进去。
扩容时,至少扩充至10。

LinkedList

1.实现方式
基于双向链表实现。
2.各操作复杂度
基于下标的访问复杂度是O(n)的。
在已知节点前后进行插入/删除复杂度是O(1)的。

PriorityQueue

优先队列,JDK1.5引入。
1.实现方式
最小堆
2.各操作复杂度
插入删除均为O(n)

2 map

存储键值对。

具体实现:HashMap,LinkedHashMap,TreeMap

HashMap

1.实现方式
基于key的hash表。
2.要点

  • 无参构造方法初始容量为16。指定容量的构造方法,容量为最小的2^n,使得容量大于指定容量。
  • 当元素个数达到容量*负载因子时,容量翻倍。因此,容量总为2^n。
  • 散列函数以key的hashcode为基础,经过运算得到一个数字,取其低n位(哈希表容量为2^n)作为在数组中的位置。
  • hash冲突:链接法(拉链法)
  • 扩容:新建一个table,将旧table的元素添加到新table中,复杂度O(n)
  • 性能:存取操作的平均复杂度是O(1)的,但最坏情况下是O(n)的。

LinkedHashMap

1.实现方式
在HashMap的基础上,将所有节点加入到一个双向链表中。
2.要点

  • 默认按照插入顺序存储,可指定按照访问顺序存储

TreeMap

1.实现方式
红黑树
2.各操作复杂度
查找、插入、删除操作复杂度都是O(lg n)

3 关于集合类的同步

JDK1.1遗留的Vector,Stack,Hashtable是线程安全的。
后来引入的集合类本身是不支持并发的。
但Vector,Stack,Hashtable的线程安全是有一定缺陷的。
假设下面的情况:

Vector v;
int len=v.size();
v.get(len-1);

获取v的size,根据size获取最后一个元素。
在v.size()与v.get()之间,如果另一个线程删除了v中的一个元素,那么v.get()就越界了。
因此,为达到目的,我们往往需要再加一层synchronized。
另外,Vector,Stack,Hashtable为了实现同步,效率较低。
因此不推荐使用。

面向对象的基本特征

封装

将实现细节隐藏,只提供一些接口供外部使用,称为封装
一个相关的概念是抽象,提取一些类的特征与行为而不关注细节,称为抽象。

继承

从已有的类派生出新类,称为继承
继承是一种提高代码可重用性的手段。另一种常用的手段是组合,将在下面提到。

构造方法链

  • Tips
    • 只能用super调用父类的构造方法,这个调用必须是构造方法的第一条语句
    • 父类的构造方法不被继承

构造方法可以调用重载的构造方法或它的父类的构造方法。如果它们都没有被显式地调用,编译器会自动地将super()作为构造方法的第一条语句(此时,如果父类不存在无参构造方法,编译不通过)。
子类递归地调用父类的构造方法,直到继承体系架构的最后一个构造方法被调用为止。这就是构造方法链

覆盖

子类修改父类中定义的方法的实现,称为方法覆盖

  • Tips
    • 仅当实例方法是可访问时,它才能被覆盖。父类中的私有方法与子类无关。
    • 静态方法能被继承但不能被覆盖。

继承与组合的比较

一个对象可以包含另一个对象,这样的关系称为组合
继承和组合都是提高代码可重用性的手段,很多时候可以相互替代。
通常更推荐组合而不是继承。

  • 继承
    • 优点
      • 子类能自动继承父类的接口
    • 缺点
      • 破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
      • 扩展功能时往往以增加系统结构的复杂度为代价
      • 脆弱的基类
  • 组合
    • 优点
      • 不破坏封装,整体类与局部类之间松耦合,彼此相对独立
      • 具有较好的可扩展性
      • 支持动态组合。在运行时,整体对象可以选择不同类型的局部对象
    • 缺点
      • 整体类不能自动获得和局部类同样的接口
      • 创建整体类的对象时,需要创建所有局部类的对象

多态

父类型的变量引用子类型的对象,称为多态

动态绑定

  • 声明类型:一个变量被声明时定义的类型
  • 实际类型:变量引用的对象的实际类
  • 变量调用的非静态方法是由实际类型决定的,称为动态绑定

抽象类和接口

抽象类

抽象类用来表示抽象概念,由abstract关键字修饰。
* 抽象类不能被实例化
* 抽象方法必须包含在抽象类中。因此,抽象类的非抽象子类必须实现所有抽象方法。
* 包含抽象对象的类必须是抽象的

接口

接口是一种与类相似的结构,只包含常量与抽象方法。

  • 实现接口的非抽象类必须要实现该接口的所有方法。抽象类可以不用实现。
  • 接口的所有方法都是public abstract的

区别

  • 语法上
    • 抽象类可以拥有任意范围的成员数据,同时也可以拥有自己的非抽象方法
    • 接口只能包含常量与抽象方法
  • 概念上
    • 接口指明了多个对象的共同行为,关注于局部特征
    • 抽象类更关注本质特征,子类与父类间是“is-a”的关系

泛型

泛型是指参数化类型的能力。可以定义带泛型类型的类或方法,随后编译器会用具体的类型替换它。

泛型的优点

  • 编译时进行类型安全检查,使程序更加可靠。
  • 代码更加灵活

定义泛型类

public class Example<E>{
    public void method(){
    }
}

定义泛型方法

public class Example{
    public <E> void method(){
    }
}

通配泛型

  • ?
    • 非受限通配符,等价于? extends Object
  • ? extends T
    • 受限通配,表示T或T的一个子类型
  • ? super T
    • 下限通配,表示T或T的一个父类型

实现

Java的泛型是通过类型擦除的方法实现的。
编译器使用泛型类型信息来编译代码,但随后会消除它。因此,泛型信息在运行时是不可用的。
泛型存在于编译时,一旦编译器确认泛型类型是安全可用的,就会将它转换为原始类型。

Tips

  • 不能使用new E()
  • 不能使用new E[]
  • 在静态环境下,不允许使用泛型
  • 异常类不能是泛型的

总结

其实就是提供了写起来比较好看的语法,然后由编译器在编译阶段进行了强制类型转换。在运行时跟1.5以前用Object来实现泛型并无区别。
即,泛型这一概念,在运行时是不存在的。
这样的实现被称为伪泛型。
而有些语言,如C#,在运行层面实现了泛型容器,被称为真泛型。
比较起来,Java的伪泛型存在一些劣势。

Java泛型的劣势

语法上:

  • 不支持new E()
  • 不支持new E[]
  • List<String> listList<Integer> list被认为是相同的类型

性能上:
C#的真泛型性能比Java的伪泛型高很多,差距大致在10倍以上。

Java泛型的优势

  • 保证了向前兼容。新版本编译后的代码可以直接在旧版本JVM上运行。
  • 通配泛型在可变性上更优越

可以看到,比起真泛型,Java的泛型主要还是处在劣势的。原因其实就是Java语言在早期没有支持泛型,也没有考虑到以后添加这种特性。因此,后来再想要实现真泛型难度太大,于是退而求其次实现了伪泛型。

多线程

待补充

sleep和wait的区别

网络

待补充

JVM

待补充

相关文章

    暂无相关文章
相关栏目:

用户点评