【已转移】【Java架构:基础技术】一篇文章搞掂:Java 8

本文篇幅较长,建议合理利用右上角目录进行查看(若是没有目录请刷新)。html

1、Java的历史与演变 

目的:为彻底了解Java,须要理解Java的诞生缘由、成型动力以及他继承的思想。java

计算机语言的创新与发展的缘由:适应环境和用途的变化;实现编程艺术的完善和提升。程序员

1.一、Java的家世

Java大量特性从C和C++继承过来。web

C语言的诞生

C语言前,BASIC、COBOL、FORTRAN这几种编程语言没有遵循结构化原则设计,依赖GOTO做为程序控制手段;Pascal虽是结构化语言,但不是针对高效率设计的,没法设计系统级代码。正则表达式

C语言出现的2个条件:软件需求加快,学术界在努力建立一种新的设计语言;计算机硬件普及,计算机再也不被锁起来,程序员能够随意使用计算机进行尝试。算法

C语言是一种功能强大、高效率、结构化的语言;并且他是程序员设计的,为程序员服务的语言。数据库

C++

出现的缘由:更好地管理程序的复杂性。编程

改进:C++是在C#的基础上,增长了对面向对象(OOP)的支持,使程序员能理解和管理更大的程序。小程序

Java出现的条件

20世纪80年代末90年代初,万维网(World Wide Web)和因特网发展到了临界规模。设计模式

1.二、Java诞生

Java于1991年,由Sun公司构想出。

最初开发Java的推进力:对平台独立的语言的需求。

推进力

当时须要为一些电子设备(微波炉、遥控器等)的各类CPU开发程序,若是使用C或者C++须要对每一种CPU开发对应的编译器,因此须要一种可移植对平台独立的语言。

因特网成就Java:恰好这个时候因特网的飞速发展,也须要可移植的程序,Java的特性也适合于因特网的需求,使Java的关注点从消费电子产品转移到Internet。

Java的特性

一、为了吸引C/C++的程序员,Java继承了不少C/C++的特性,但Java不是为了替代它们,而是为了解决特定领域问题而出现的。

二、Java是专门针对程序员的语言,由于他的设计、测试、改进都是由程序员完成,扎根与程序员的需求,也为程序员开放了足够的权限。

与C#的关系

Java影响了C#语言的发展,二者共享相同语法,支持分布式编程,使用类似的对象模型。

1.三、Java改变Internet的方式

Internet推进了Java,Java也影响了Internet。

Java简化了Web编程,建立了新的网络程序类型applet,解决了一些Internet棘手问题如移植性和安全性。

Java applet

applet是一种能够在Internet上传送的程序,能够在兼容Java的Web浏览器中自动运行。

applet扩展了网络空间自由流动的对象的范畴。这是一种动态的,自动运行的代码,由服务器端初始化,而后在客户端自动运行。

虽然这种动态的联网程序符合人们愿望,可是同时带来了严重的安全性和可移植性。

安全性

当下载这个自动执行的程序的时候,里面可能包含各类病毒或者恶意代码。

而Java将applet限定在Java的执行环境内,不容许访问计算机的其它部分来实现安全性。

可移植性

applet会被下载到不一样的环境,不一样的系统中,如何实如今这些不一样的环境下的运行,下面将讲解。

1.四、Java的魔力:字节码

解决安全性和可移植性的关键:字节码。

Java编译器输出的不是可执行代码,而是高度优化的指令集合。

字节码在Java运行时系统中执行,Java运行时系统也称为Java虚拟机(Java Virtual Machine,JVM),原始也称为字节码解释器。

字节码和JVM实现了移植性和安全性

  • 移植性:同一个程序,Java编译器输出的是相同的字节码;而这个字节码须要在不一样的环境中运行,只须要实现对应环境的JVM便可;这些不一样的JVM,运行的是相同的字节码,从而实现了移植性。
  • 安全性:由于Java程序依赖JVM来运行,因此在JVM以外的系统其它部分,Java代码是没法修改的,从而实现了必定的安全性。
  • 速度:通常来讲,这样通过一个中间层再执行代码,理论上会慢一点;可是Java对字节码进行了足够的高度的优化,因此这个速度是足够快的。
  • 执行代码:为了提升性能,Java也提供了HotSpot技术,为字节码提供了即时(Just In Time,JIT)编译器,可将字节码实时编译为系统可执行代码。

1.五、servlet:服务器端的Java

Java横跨服务器/客户端:servlet是在服务器中执行的Java程序,像applet扩展了Web浏览器的功能同样,servlet扩展了Web服务器的功能。

servlet用于动态建立发送到客户端的内容,如servlet能够读取服务器数据库,而后整理为客户端想要的内容,发送到客户端;同时,servlet还提供了一些额外的优势,例如性能的提高。

可移植性:由于servlet是Java程序,他们被编译成字节码,由JVM执行,因此servlet能够用于不一样服务器环境,只要服务器支持JVM和servlet容器。

1.六、Java关键特性

  • 简单性:继承C/C++语法和面向对象特性;原本的设计目标就是让程序员高效学习和使用。
  • 安全性:上面已讲述。
  • 可移植性:上面已讲述。
  • 面向对象:Java中的对象模型既简单又容易扩展,基本类型仍然是高性能的非对象类型。
  • 健壮性:编译时检查代码;可预见的方式运行;自动管理内存回收;面向对象的异常处理。
  • 多线程:Java提供了易用的多线程方法。
  • 体系结构中立:Java提供了Java虚拟机(JVM),解决了程序对不一样电脑,或者同一台电脑,不一样状态,可能致使程序不能运行的问题。
  • 解释执行和高性能:虽然Java使用了字节码和JVM,可是通过Java的优化,使用计时编译器,可以使这种模式依然保持了如本机代码同样的高性能。
  • 分布式:Java是针对Internet的分布式环境而设计的,因此对分布式有不少强大的支持。
  • 动态性:支持运行时类型信息,可在运行时验证和解决对象访问的问题。

2、Java综述 

2.一、面向对象编程

面向对象编程(Object-Oriented Programming,OOP)在Java中处于核心地位。

两种范式

全部计算机程序都包含2个元素:代码、数据

  • 面向过程模型:将程序描述为一系列步骤,并用代码描述每个步骤将如何做用于数据。
  • 面向对象编程:将数据设计为一系列对象,并为这些对象精心设计接口,使用这些接口来进行组织代码。

抽象

使用抽象管理复杂性:非面向对象的编程方式,每每将对象分解为不一样的部分进行处理;而面向对象的编程方式,则是把对象做为一个总体,去使用这个对象。

层次化分类:如一台车,下面又能够分为驾驶系统、制动系统等,每层又能够继续细分。当咱们去使用这个车的对象时,则只须要了解各系统如何操做,而不须要知道这个系统里面由什么组成

对变化的支持:面向对象的方式犹如人类理解事物同样;每每事物会不断变化,例如某一部分进行改变;那么面向对象的程序也能支持这些变化,能够优美地废除或者替换旧系统中的一些部分。

2.二、OOP三原则

封装

封装:将代码以及其操做的数据绑定在一齐的机制。能够想象为一个保护性的盒子,只容许外部经过盒子提供的通道进行访问和操做,而不容许随意访问盒子里面的代码和数据。

封装的基础是类:类,是一些对象共享的一种结构和行为(数据和代码)。使用类建立对象,相似使用模具生产零件,这些对象也称为类的实例。

变量和方法:类里面能够定义变量和方法,称为成员变量(或实例变量)和成员方法(或方法)。

公有/私有:类的变量或方法能够设置为公有或私有,公有的表示外部用户能够知道的内容,私有的表示只有类的成员才能访问。

继承

继承:是一个对象得到另外一个对象的属性的过程,继承支持了层次化分类的概念。

例如定义了一个哺乳类动物,又定义了下一层的一个类叫犬类,咱们定义犬类继承了哺乳类,那么就表明犬类有哺乳类的全部属性和特征(变量和方法)。

多态

多态(多种形态):容许将一个接口用于一类通用动做。

多态是为了下降复杂性。例如一个对象有同一个行为,可是根据数据不一样有不一样作法的时候,使用相同的接口来指定这个行为,而自动根据对应的参数,会执行对应的实际代码。

封装、继承与多态协同工做

经过这3个原则,能够设计出健壮性强、方便维护、适应变化的系统级代码。

下面例子应在安装并配置好JDK 8下使用

2.三、Java基本语法

源文件

Java中源文件的正确名称叫编译单元(compilation unit),是一个包含一个或多个类定义(及其它内容)的文本文件。

要求源文件使用.java做为扩展名;文件内主类的名称与源文件名必须相同且大小一致。

代码例子Test.java

class Test{
  public static void main(String args[]){
    System.out.println("测试");
  }
}

编译成字节码

在命令行中,执行命令,javac编译器会建立名为Test.class文件,这个就是字节码文件

c:\>javac Test.java

运行程序

c:\>java Test

运行后,会显示“测试”,表明程序运行成功

main()方法

Java会找到程序多个类中的main()方法启动程序,注意大小写,没有找到会报错

声明变量

int num;

控制语句

if(num < 100)System.out.println("yes");

代码块

用{}表示逻辑单元

if(num<100){
  System.out.println("yes1");
  System.out.println("yes2");
}

词汇问题

  • 空白符:能够用空格、制表符或换行符随意进行缩进。
  • 标识符:用于命名类、变量以及方法等。可由大小写字母、数字、下划线、美圆符号等字符组成的任意字符序列。不能以数字开头,不建议使用下划线。
  • 字面值:表示常量,如100,85.2,'X',"Long Text"
  • 注释:Java有3种注释
  • 分隔符:

  • 关键字:

3、数据类型、变量和数组

Java是强类型语言

在编译器完成编译前,会检查全部表达式和参数,确保类型是兼容的。

基本类型(也称简单类型)

Java定义了8中基本数据类型

整型:byte、short、int、long,表示有符号整数。

通常使用int,不够长度使用long

若是表达式中有byte、short类型,对表达式求值时他们会被提高为int类型

浮点型:float、double,表示带小数位数字。

float:32位单精度数值,某些处理器上单精度运算速度更快,占用空间是双精度的一半,可是数值很大或很小时会变得不许确;在须要小数部分,可是精度要求不高的时候,建议使用float类型。

double:64位双精度数值,在针对高速数学运算优化的现代处理器中,双精度数值速度更快;在须要屡次迭代运算中保持精度,或者操做很是大的数值时,建议使用double类型。

字符型:char,表示字符集中的符号,好比字母和数字。

Java使用Unicode表示字符,Unicode是一个彻底国际化的字符集,能够表示所有人类语言中的全部字符;Unicode是16位宽的,对好比ASCII字符集等更宽,效率有必定程度下降,这是Java为了全球化而作出的一点牺牲。

布尔型:boolean,表示true/false值的特殊类型。

深刻分析字面值

整型字面值

int x=06;//0开头表示8进制
int x=0x2f;//0x或0X开头表示十六进制
int x=0b1010;//0b或0B开头表示二进制
int x=123_456_789;
int x=123___456___789;//可在数值中嵌入一个或多个下划线,方便观看,编译时会去掉

浮点型字面值

float num = 2.44F;//默认浮点数为双精度,后面加F或f标明单精度
double num = 2.44D;//双精度能够这样表示,可是默认就是双精度,因此多余
double num = 3.13148;//标准计数法
double num = 2E-5;//科学计数法,能够用E或e后+正负号(正可省略)+十进制来表示
double num = 3_432_442.0_2_2;//同样能够用下划线分割

布尔型字面值

  Java中只能用true和false,不能用1或0

字符型字面值

char t = 'a';//用单引号表示字符
char t = '\141';//八进制表示子母a
char t = '\u0061';//十六进制表示Unicode字符a
char t = '\n';//转义字符表示换行符

字符串字面值

字符串中一样能够使用转义字符以及八进制/十六进制表示方法

Java中字符串开头和结尾必须同一行,没有分行输入的功能

其它语言中字符串是字符的一个数组,而Java中是把字符串做为一个对象(因此不能用a==b来判断2个字符串,由于2个对象是不一样的)

"Hello World"//使用双引号表示

变量

类型开始,能够连续定义多个变量,初始值可选

int a,b,c;
int a=1,b,c=1;//连续定义3个int类型变量,其中2个加入初始值
int a=1;//使用常量初始化
doucle c=Math.sqrt(a*a+b*b);//使用公式初始化

变量做用域:

花括号{}表示代码块,变量的做用域在其所在的代码块中,离开代码块,变量会丢失他的值

类型转换和强制类型转换:

自动类型转换:当把一个类型的数据赋值给另一个类型的变量时,若是知足条件,会发生自动类型转换。

条件:两种类型兼容;目标类型大于源类型。

知足上述条件,会发生扩宽转换。

例如把byte值赋值给int类型变量

强制类型转换

int a;  
byte b = (byte)a;//缩小转换
double c;
int d = (int)c;//浮点数转为整型,会把尾数直接截掉,而且若是整数部分太大,会转换为整数部分除以目标类型范围的余数,例如转换为byte类型,就是除以256

自动类型提高

原则:
一、表达式中的byte、short、char值都会提高为int
二、若是其中一个操做数为long,整个表达式会提高为long
三、若是其中一个操做数为float,整个表达式会提高为float
四、若是其中一个操做数为double,整个表达式会提高为double

byte b=50;
b=b*2;//错误,由于进行了自动提高,b在表达式中变成了int类型,因此b*2的结果是int类型,赋值给更小的类型byte会报错
b=(byte)b*2;//正确

数组

int array1[];//建立数组变量,只是变量,未分配内存
array1 = new int[12];//元素自动初始化为0(数值类型)、false、null(引用类型)
array1[3]=28;//使用[索引]进行访问
System.out.println(array1[3]);
int array1[] = new int[12];//结合起来的写法
int array1[] = {1,2,3,4,5};//初始化式声明

//多维数组
int twoD[][] = new int[4][5];//多维数组
//不一样长度的多维数组
int twoD[][] = new int[4][];
twoD[0] = new int[1];
twoD[1] = new int[2];
twoD[2] = new int[3];
twoD[3] = new int[4];
//初始化写法
double m[][] = {
    { 1, 2 }, 
    { 3, 4 }, 
};

//另一种写法
int a1[] = new int[3];
int[] a1 = new int[3];
char twod1[][] = new char[3][4];
char[][] towd1 = new char[3][4];
int[] a1,a2,a3;
int a1[],a2[],a3[];

关于字符串的说明

在Java中,字符串类型是String

可是String不是一个基本类型,而是一个对象,为他提供了一些面向对象的特性,因此放在后面探讨

关于指针

由于Java使用了JVM,限定了Java程序的执行边界,Java程序不容许使用指针。

由于指针能够访问内存中任何地址,破坏了JVM和宿主计算机之间的防火墙,和Java的设计理念不一样,因此Java不容许使用。

5、运算符

算数运算符

基本算数运算符+ - * /
注意整数类型使用除法,结果会截掉小数部分

求模运算符%
求余数,能够用于整数或小数

算数与赋值符合运算符+= -= *= /=
至关于运算后再赋值

自增与自减运算符++ --

y=x++;//先将x原值赋值给y,而后x加1
y=++x;//x先加1,而后将x加1后的值赋值给y

位运算符

位操做较少用,这里略过

关系运算符

布尔逻辑运算符

赋值运算符

a=1;//使用"="符号赋值
a=b=c=100;//将3个变量都赋值为100

“?”运算符

a=b==0?true:false;//用于简写的判断

优先级

使用圆括号

圆括号能够提高运算的优先级,而且能使阅读更加明确易懂,又不影响性能。

a=(b==0?true:false);

5、控制语句

选择语句

if语句
if(a=1){
  b=1;
}
else if(a=2){
  b=2;
}
else{
  b=3;
}
switch语句
switch(a){
  case 1:
    b=1;
    break;
  case 2:
    b=2;
    break;
  case 3:
  case 4:
    b=3.5;
    break;
  default:
    b=100;
    break;
} 

迭代语句

while
while(n>0){
  System.out.println(n);
  n--;
}
i=100;
j=200;
while(++i<--j);//用;表示空语句
do-while

循环体至少执行一次

do{
  System.out.println(n);
  n--;
}while(n>0)
for
int n;
for(n=10;n>0;n--){
  System.out.println(n);
}
for(int n=10;n>0;n--){
  System.out.println(n);
}
for(a=1,b=4;a<b;a++,b--){
  System.out.println(a);
  System.out.println(b);
}
for-each

for-each风格在不一样的编程语言中都有实现,是一种很受程序员喜欢的风格
在Java中,是经过for语句实现的,能够对集合类变量进行循环

int nums[] = {1,2,3,4,5}
int sum = 0;
for(int x:nums){
  sum+=x;
}

跳转语句

break

用于终止当前所在的最近一个循环

for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m==5)break;//跳出m的循环
  }
}
break label

能够使用标签,终止语句所在的全部嵌套循环中的其中一个

outer:for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m==5)break outer;//跳出n的循环
  }
}
continue

提早终止循环的一次迭代
在本次迭代中,在continue后面的代码将不会执行

for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m>5)continue;//跳出m的一次迭代
  }
}
continue label

能够使用标签,终止语句所在的全部嵌套迭代中的其中一个

outer:for(int n=10;n>0;n--){
  for(int m=10;m>0;m--){
    System.out.println(n);
    System.out.println(m);
    if(m>5)continue outer;//跳出n的一次迭代
  }
}
return

显式地从方法返回,把程序的执行控制返回到发放的调用者处

6、类

类的形式

//类的基本形式
class Box{
  double width;//实例变量
  double height;//实例变量
  double depth;//实例变量

  //无参构造函数,new Box()实际是调用了类的构造函数
  Box(){
    width = 10;height= 10;depth= 10;
  }
  //带参构造函数
  Box(double width,double height,double depth){
    this.width = width;//使用this引用实例对象
    this.height= height;
    this.depth= depth;
  }

  double volume()//方法,返回值、参数都是可选的
  {
    return width * height * depth;
  }
}

//建立类的实例
Box mybox1;//声明一个Box类型变量
mybox1 = new Box();//建立一个实际对象,并将引用到上面的变量中
Box mybox1 = new Box();//简写方式
mybox.width = 100;//为实例变量赋值

//变量引用的概念
Box b1 = new Box();
Box b2 = b1;
b1 = null;
//此时b2不是null,而是引用第一行建立的对象
//由于第二行代码是把b1引用的对象也给b2引用
//第三行代码,只是将b1的引用去除,并不影响b2和对象的引用

垃圾回收

当对象用完后,应该把对象在内存中清掉,释放内存。
这方面Java会自动管理,大多数状况不须要人为编程。

finalize()方法

为类添加这个方法,能够在类的对象被Java回收的时候执行方法内的代码。

protected void finalize()
{
  //记录回收时间等自定义方法
}

7、方法和类深刻分析

重载方法

Java中支持多态性的方式之一
支持多个不一样参数的方法共享方法名称,经过传入的参数来判断调用哪一个具体方法

class OverloadDemo{
  void test(){
  System.out.println("test1");
  }
  void test(int a){
  System.out.println("test2");
  }
  void test(int a,int b){
  System.out.println("test3");
  }
}
class Overload{
  public static void main(String args[]){
    OverLoadDemo ob = new OverloadDemo();
    ob.test();//调用无参的方法
    ob.test(10);//调用1个int参数的方法
    ob.test(10,20);//调用2个int参数的方法
  }  
}

对象能够做为参数

能够将对象做为参数传递给方法

参数的传递

  • 传递的形式分为:值传递,引用传递
  • 基本类型的参数,使用的是值传递
  • 其它类型的参数,使用的是引用传递
  • 参数使用值传递,至关于建立该值的一个副本,修改该参数,不会影响原值
  • 参数使用引用传递,至关于把参数指向和原值所指向的同一个对象,因此修改参数值的时候,其实是在修改其所指向的对象,因此原值也会一齐变化。

对象能够做为返回值

能够讲对象做为参数的返回值返回

递归算法

方法能够调用本身实现递归算法

访问控制

  • 为了使类能够更好地封装,咱们系统能够把类看成一个黑盒子,只对外暴露能够访问的成员
  • Java提供了访问修饰符来实现这种封装
  • public:成员被public修饰,能够被任何代码访问,无修饰符时默认为public
  • private:成员被private修饰,该成员只能被所属类的其它成员访问
  • protected:涉及继承才会使用下章介绍

static

用于声明类自己的成员,而不是对象的成员
限制:
一、只能直接调用其它静态方法
二、只能直接访问静态数据
三、不能引用this或super关键字

class UseStatic (
  static int a * 3;//静态变量
  static int b;//静态变量

  static void meth(int x) {//静态方法
    System.out.println("x:" + x);
    System.out.println("a:" + a);
    System.out.println("b:" + b);

  static (//静态代码块,会在加载此类时运行,整个程序生命周期仅运行一次
    System.out.println("Static block initialized");
    b = a * 4;
  }

  public static void main (String args[]) {
    meth(42);//调用静态方法
  }
 }

静态方法、静态变量也能够看做是Java中的全局方法和全局变量

final

能够用于声明变量或者方法

//声明变量,能够将变量定义成常量
//表明整个程序生命周期,他的值不能改变
//约定写法为全大写
final int FILE_NEW = 1;

final声明方法与声明变量的用法有本质区别,下章讨论final声明方法的用法

从新审视数组

数组的length成员
只反映最初设计时数组所能包含的元素数量

int a1[] = new int[10];
System.out.println("length is " + a1.length);

嵌套类和内部类

嵌套类:在一个类的内部再定义一个类,这个再定义的类称为嵌套类;外部的类称为包含类

限制:

  • 一、嵌套类不能独立于包含类存在
  • 二、嵌套类能够访问包含类的成员(含私有成员)
  • 三、包含类不能访问嵌套类的成员
  • 四、嵌套类能够做为包含类的成员声明;也能够在代码块中声明

嵌套类按是否静态能够分为2种:静态的、非静态的

由于静态嵌套类只能访问包含类的静态成员,只能经过对象访问包含类的非静态成员,因此不多这样使用

非静态的嵌套类称为【内部类】

class outer
  int outer_x = 100;
  void test(){
    Inner inner = new Inner();
    inner.display();
  }

  //内部类
  class Inner{
    void display{
      System.out.println("display: outer_x ="+ outer_x);
    }
  }

  //代码块中定义内部类
  void test2(){
    for(int i=0;i<10;i++){
      class Inner2{
        void display(){
          System.out.println("display:outer_x = " + outer_x);
        }
      }
      Inner inner = new Inner();
      inner.display();
    }
  }
}
class InnerClassDemo{
  public static void main(String args[])(
    Outer outer new Outer();
    outer test();
  }
}

String类介绍

Java中每一个字符串,包括变量和常量,都是一个String对象

//多种方式构造字符串
String myString = "this is a test";

//引用
System.out.println(mySting);

//Java为String对象定义了“+”运算符
String myString1 = "I" + " Love You";

//经常使用方法
//equals方法判断相等
if(str1.equals(str2))
  System.out.println("equals");
//length方法获取长度
if(str1.length()==0)
  System.out.println("空字符串");
//charAt方法获取字符
System.out.println("equals".charAt(0));

//常见错误,2个相同字符串是不相等的,由于是2个对象
if("yes"=="yes")
  System.out.println("Yes");

varargs:可变长度参数

限制:
一、一个方法最多只有一个可变长度参数
二、可变长度参数必须放到最后

class VarArgs{
  static void vaTest(int ... v){
    for(int x : v){
      System.out.println(x);
    }
  }
}

8、继承

一个类能够继承另一个类,被继承的类叫超类,继承别人的类叫子类

extends

继承:

  • 一、子类包含了超类的全部非私有成员
  • 二、一个类只能有一个超类
class A{
  int i = 1;
  void showi(){
    System.out.println("i = "+i);
  }
}
class B extends A{
  int j = 2;
  void showj(){
    System.out.println("j = "+i);
  }
}

超类变量引用子类对象

变量的成员决定于变量类型,而不是对象类型

class test(){
  void test(){
      A a = new B();
  }
}

super关键字

用法1:子类构造函数中调用超类构造函数

class B extends A{
    B(){
        super();//调用超类A的构造函数
    }
}

用法2:引用超类被子类隐藏的成员

class A{
  public string name = "a";
  void showA(){
    System.out.println(name);
  }
}
class B extends A{
  public string name = "b";//同名成员,隐藏了超类的name成员
  void showB(){
    System.out.println(name);//b
    System.out.println(super.name);//a
  }
}

多级继承层次

类能够无限级继承

构造函数的执行顺序

从最上层超类的构造函数到最下层子类的构造函数执行

重写(隐藏)

当子类的成员与超类成员名称相同且参数类型相同,会把超类成员重写(隐藏),可是能够经过super调用超类的成员

动态方法调度

Java经过对象的类型选择调用的成员,而不是变量的类型

class A{
  void call(){
    System.out.println("a");
  }
}
class B{
  void call(){
    System.out.println("b");
  }
}
class C{
  void call(){
    System.out.println("c");
  }
}
class Test{
  public static void main(String args[]){
    A a = new A();
    A b = new B();
    A c = new C();
    a.call();//输出a
    b.call();//输出b
    c.call();//输出c
  }
}

抽象类

使用abstract类型修饰符修饰的类

  • 一、抽象类不存在对象,不能用new实例化。
  • 二、不能声明抽象的构造函数。
  • 三、不能声明抽象的静态方法。
  • 四、子类要么实现全部抽象方法,要么本身声明为抽象的。
  • 五、应用动态方法调用,抽象类能够做为变量引用,引用其子类所建立的对象,调用其抽象方法时,实际是调用对应对象所实现的方法。

继承中使用final关键字

一、可以使用final关键字阻止重写
二、可以使用final关键字修饰类,防止类继承

Object类

Object类是全部其它类的超类
Object类型的引用变量能够应用其它全部类
Object类型能够引用数组,由于数组也是做为类来实现的
因此全部对象均可以使用Object的方法

9、包和接口

若是全部类都放一块儿开发,方便易记的类名很快用完,也很容易出现协做时命名冲突的问题。
包是Java提供的一种命名机制,同时也是一种可见性控制机制。

包定义

Java使用文件系统目录存储包,包名必须和目录路径一致,包括大小写

//定义包名,写在Java源文件中的第一条语句
package pkg;

//层次化
package java.awt.img;
包查找与CLASSPATH

Java运行时怎么找到这些包呢?

package MyPack;

3种方式:

  • 一、Java程序运行目录下有MyPack目录
  • 二、CLASSPATH环境变量下有Mypack目录
  • 三、运行程序时经过-classpath选项指明包路径运行

类成员的访问保护

而对【非嵌套类】只有2种访问级别

  • 默认级别:只能被同包中的其它类访问。
  • 公有级别:任何其它代码均可访问;要求该类是文件中惟一一个公有类,切文件名要和类名彻底一致。

导入包

import java.util.Data;
import java.io.*;//导入整个包

Java隐式地为全部代码都导入了java.lang包,至关于每一个源文件开头都添加了

import java.lang.*;

import语句是可选的,也能够选择使用彻底限定名来使用类

class MyDate extends java.util.Date{
}

接口

使用interfere建立接口,可用于指定类必须实现哪些功能

定义接口

interface Callback{
  void callback(int param);
}
  • 一、若是接口没有修饰符,采用默认访问级别,只有声明接口的包中的其它成员才能访问接口。
  • 二、若是接口声明为public,那么全部代码均可以使用接口,且接口是当前文件中的惟一公有接口,文件名必须和接口同名。
  • 三、JDK 8及之后的版本中,能够为接口建立默认实现。
  • 四、接口中能够声明变量,隐式标识为final和static,全部实现接口的类都不能修改他们,还必须初始化他们。
  • 五、全部方法和变量都隐式声明为public。

实现接口

class Client implements Callback{
  public void callback(int p){
    System.out.println(p);
  }
}
  • 一、实现接口方法时,必须声明为public
  • 二、使用接口调用方法,是在运行时动态查询到方法并执行,和常规方法调用相比占用更多资源,对性能要求苛刻的代码中谨慎使用。
class TestIface{
  public static void main(String args[]){
    //使用接口调用方法
    Callback c = new Client();
    //调用的方法是来自对象,而不是类型变量
    c.callback(42);
  }
}
  • 部分实现:
  • 若是类实现一个接口,可是没有实现全部接口方法,那么必须将这个类声明为abstract
abstract class Incomplete implements Callback{
  void show(){
    System.out.println("Good");
  }
}

接口中的变量

建立一个包含变量的接口,实现这个接口的类至关于把这些这些变量看成常量导入到类的命名控件下。

interface SharedConstants{
  int NO = 0;
  int YES = 1;
  int NULL = 2;
}

这种用法有争议,仅做介绍

接口的继承

接口能够继承,实现一个子接口,必须实现这个接口的继承链上全部接口的全部方法。

默认接口方法default

【JDK8】才出现

默认方法也称扩展方法

能够为接口的方法提供默认实现

动机:

  • 一、当接口须要增长一个方法,那么实现接口的类必须实现这个方法,致使增长方法会破坏原有代码;
  • 二、提供可选方法。例若有一个接口有一个方法remove,有2个类都实现了这个接口,其中一个类但愿他是不可删除的,原来方法就须要写一个remove的空实现。如今有了默认方法,能够在接口默认空实现,或抛出异常,这样类就不用去作空实现了。
public interface MyIF{
  //使用default关键字
  default String getString(){
    return "Default";
  }
}

优势:

  • 一、优雅地随时间演进接口
  • 二、提供可选功能,且类没必要在不须要该功能时提供占位符实现。

不一样接口的同名方法

一个类实现了2个接口,2个接口都有默认方法reset,那么使用方法的顺序以下:

  • 一、类有实现,优先类的实现
  • 二、类没有重写实现,则报错

若是是一个接口继承另一个接口,且有相同默认方法,则继承接口的版本更高优先级

//显式调用被继承接口中的默认实现
SuperInterface.super.reset();

在接口中使用静态方法

【JDK 8】才出现

能够在接口中直接定义静态方法,而后直接调用

public interface MyIF{
  static int getDefaultNumber(){
    return 0;
  }
}

//调用
int a = MyIF.getDefaultNumber();

注意:
一、实现接口的类或子接口不会继承接口中的静态方法。

10、异常处理

异常处理

处理程序运行时的非正常状态,即运行时错误。
Java会在出现异常时,抛出一个异常对象。

异常类型

全部异常对象都是Throwable的子类

Exception:用于用户程序应当捕获的异常,或者自定义的异常

RuntimeException:程序自动定义

Error:通常指运行时环境出现的错误

未捕获的异常

若是出现异常且未捕获,程序会终止,并输出堆栈信息,能够根据堆栈信息帮助查找问题。

使用try和catch

程序处理异常,会终止程序。

咱们本身处理异常,一能够修复错误,二能够避免终止程序。

try{
  do();
}catch(Exception1 e){
  System.out.println(e);//输出异常信息
  catchDo();
}catch(Exception2 e){//能够多个catch语句
  catchDo();
}
  • 一、在try{}的代码中,若是出现异常,则在代码块中异常代码后面的代码会跳过,直接转到catch里面
  • 二、能够写多个catch语句
  • 三、若是嵌套了try,若是内层try没有处理异常,异常会抛出到外层的try里面去。

throw

显式抛出异常

throw ThrowableInstance;

这个异常必须是Throwable或其子类类型的对象。

throws

除了Error和RuntimeException及其子类类型的异常外,若是方法有其它类型的异常,则须要为方法标明这些异常。

目的是让方法的调用者知道此方法全部异常以作好准备措施。

public void do() throws MyException{
  throw new MyException("test");
}

finally

可选加载try{}catch{}后,不管是否抛出异常,都会在try{}catch{}后执行此代码

try{
  do();
}catch(Exception1 e){
  System.out.println(e);//输出异常信息
  catchDo();
}finally{
  finallyDo();
}

Java内置异常

未经检查(编译器不检查这些异常是否使用throws标明)的RumtimeException子类

须要检查的Java定义的异常类

建立本身的异常子类

一、定义Exception的子类便可

二、Exception没有为本身定义任何方法,可是继承了Throwable提供的方法

三、Exception有4个公有构造函数,其中2个支持链式异常(下面介绍),另外2个以下

Exception()
Exception(String msg)

链式异常

当一个异常的抛出,是由于另一个异常致使的,但愿能把这个异常链显式出来,因此提出了链式异常。
Throwable中有2个构造函数和2个方法

//2个构造函数
Throwable(Throwable causeExc)
Throwable(String msg,Throwable causeExc)
//2个方法
Throwable getCuase()//返回引起当前异常的异常
Throwable initCause(Throwable causeExc)//建立异常后将背后异常和建立的异常联系在一块儿,只能调用一次

一般initCause是用于不支持前面2个构造函数的遗留异常类设置缘由

JDK7开始添加的3个异常特性

一、带资源的try语句

当try语句中使用资源时,再也不须要时资源能自动释放(如文件),后面解释

二、多重捕获

容许同一个catch子句同时捕获多个异常

catch(Exception1 | Exception2 e)

每一个多重捕获参数都被隐式声明为final,不能从新赋值

三、最后从新抛出/更精确地从新抛出(不是很理解,暂时不理)

程序会对从新抛出的异常类型进行限制,只能从新抛出知足如下条件的经检查的异常:由关联的try代码块抛出,没有被前面的catch子句处理过,而且是参数的子类型或超类型。

一样catch参数隐式声明为final,不能从新赋值

11、多线程编程

多任务:

  • 基于进程:运行多个程序
  • 基于线程:单个程序同时运行多个任务

Java线程模型:

  • 单线程模型:轮询时间循环:轮询一个事件队列,当执行一个事件并返回以前,不能执行其余工做
  • 多线程模型:并发执行的线程共享CPU,每一个线程获得一篇CPU时钟周期。

线程的状态:

  • 运行:只要得到CPU时间就准备运行
  • 挂起:临时中止线程活动
  • 恢复:让挂起的线程变成运行状态
  • 阻塞:等待资源时,线程处于阻塞状态
  • 终止:一旦终止不能恢复

线程优先级:

一些整数,用于决定什么时候从一个运行的线程切换到下一个线程,称为上下文切换

意思应该是这样,根据CPU时钟周期,空余时间能够用来运行线程;当线程过多,而有线程阻塞时,何时切换到下一个进程呢:

  • 一、运行的线程资源放弃控制:显式放弃控制权、休眠或I/O以前阻塞,则检查全部线程,优先级最高的线程会得到CPU资源
  • 二、高优先级线程取代低优先级线程:只要高优先级线程但愿运行,就会取代低优先级线程,称为抢占式多任务处理
  • 三、相同优先级的2个线程竞争CPU,Windows系统下会循环获取CPU资源,而其余系统除非正在运行的线程放弃控制权,不然其余线程不能运行(因为不一样系统不一样,可能引发移植性问题)

同步:

  • 某个线程位于一个同步方法中,则其余线程不能调用对象的其它同步方法

消息传递:

  • Java的消息传递系统容许某个线程进入对象的同步方法,而后进行等待,而后其它线程显式通知这个线程退出为止

Thread类和Runable接口:

Java的多线程系统基于Thread类、Thead类的方法以及伴随接口Runable而构建

主线程:

Java启动就会运行一个线程,称为主线程。

很重要:

  • 一、其它子线程都是由主线程产生
  • 二、一般主线程必须是最后才结束执行的线程,由于他要执行各类关闭动做。

调用主线程

  • Thread t = Thread.currentThread();//获取主线程
  • t.setName("");//修改进程名字

建立线程

2种方法:

  • 一、实现Runable接口
  • 二、扩展Thread类自己

 

实现Runable接口

  • Runnable接口抽象了一个可执行代码单元,能够依托任何实现了Runnable接口的对象来建立线程。
  • 要实现Runnable接口,只须要实现run()方法,而后run()方法能够调用其它方法,使用其它类,声明变量,像main线程那样,惟一的区别就是入口点不一样,run()方法为并发线程执行创建了入口点,run()方法返回时,这个线程也将结束。
  • 而后建立实现了Runnable接口的类后,能够实例化一个Thread类型的对象,而后调用线程start()方法才真正线程。

扩展Thread类

一样的,扩展Thread类,重写run()方法,而后调用start()方法类开始新线程

 

为何有2种方式,哪一种好?

差异不大,一个是在于实现接口,一个是扩展重写类。

能够使用接口,这样能够使这个类能够扩展其它类。

 

建立多个线程

 

isAlive()和join()方法

好比主线程但愿等全部子线程执行完成再退出

isAlive()判断线程是否仍在运行

可是通常经过join方法来等待线程结束

再某个线程调用其它线程的join方法,会等待该线程终止。

也能够配置最长等待时间。

 

线程优先级

一、影响线程获得CPU时间的因素:优先级、系统多任务的方式等

在抢占式多任务环境下,高优先级的线程会替代掉低优先级的线程

在非抢占式多任务环境下,在运行中线程正常运行状况下(未休眠,未放弃控制权等),其它线程只有在运行中线程阻塞状态,如I/O等待等,致使线程挂起,才有机会运行

因此为了平滑多个线程的执行,最好常常释放控制权,使其它线程有机会运行。

调用setPriority方法设置线程优先级,范围1~10,默认值5

使用Java实现可预测,跨平台行为的最安全方法是使用资源放弃CPU控制权的线程。

 

同步

当多个线程须要访问共享资源时,他们须要用某种方法确保每次只有1个线程使用资源。

实现这个目的的过程称为同步。

 同步使用监视器的概念实现,监视器做为互斥锁,一个时刻只有一个线程能够进入监视器,而其余试图进入监视器的线程会被挂起,知道上一个线程退出监视器。

 

2种方法

 

使用同步方法:

Java中,全部对象都有和自身关联的隐式监视器。要进入对象的监视器,只须要调用synchronized关键字修饰过的方法。

当调用对象的一个同步方法,线程就会进入对象的监视器;其它线程想要调用这个或其余同步方法,因为进入不了监视器,因此会被挂起等待;知道监视器种的线程退出,把对象的控制权交给下一个等待线程。

 

使用同步语句:

 

 

 

线程间通讯:

 

十3、I/O、applet以及其余主题

13.一、I/O

I/O:输入输出

流:

  • Java程序经过流执行I/O。
  • 流是一种抽象,要么产生信息,要么使用信息。
  • 流经过Java的I/O系统链接到物理设备。
  • 全部流的行为方式都是相同的,即便他们连接的物理设备不一样。
  • 所以,能够将不一样类型的输入(磁盘文件、键盘或网络socket),抽象为输入流;输出流也能够引用控制台、磁盘文件或网络连接。

2种类型的流:

  • 字节流:负责处理字节的输入和输出。
  • 字符流:使用Unicode编码,为处理字符的输入和输出提供更方便的方法,某些状况下比字节流高效。

通常原则:在合适的状况下,应该更新代码,使用字符流替代字节流。

不过:在底层,全部I/O最终仍是面向字节的。

字节流类

2个类层次:

  • 顶层:2个抽象类InputStream和OutputStream
  • 子类:用于处理不一样设备的具体子类

InputStream和OutputStream最重要2个方法是read()和write(),子类须要实现这2个方法

字符流类

2个类层次:

  • 顶层:Reader、Writer,这2个抽象类处理Unicode字符流。
  • 子类:用于处理不一样设备的具体子类

Reader和Writer最重要2个方法是read()和write(),子类须要实现这2个方法

预约义流:

  • Java预约义了3个流变量,在java.lang包的System类中,分别为in、out、err,而且声明为pubilc、static、final,因此程序任何地方均可以使用他们。
  • System.out引用标准输出流,默认控制台。
  • SYstem.in引用标准的输入流,默认键盘
  • System.err引用标准的错误留,看默认控制台。
  • 可是能够重定向到任何兼容I/O设备
  • System.in是InputStream类型对象;out和err是PrintStream类型对象;都是字节流。
import java.io.*;

public class test {
    public static void main(String[] args) throws IOException {
        // 使用InputStreamReader将字节输入流InputStream转换成字符输入流Reader
        // 使用BufferedReader读取缓冲的输入流

        // 读取字符
        {
            char c;
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入字符,q退出");
            do {
                c = (char) br.read();// 读取字符
                System.out.println(c);
            } while (c != 'q');
        }

        // 读取字符串
        {
            String str;
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("输入字符串,stop退出");
            do {
                str = br.readLine();// 读取字符串
                System.out.println(str);
            } while (!str.equals("stop"));
        }

        // 输出
        {
            // System.out类型是PrintStream类,派生自OutputStream,提供了print和println方法,同时也实现了write
            System.out.print("A");
            System.out.print("\n");
            System.out.println("B");
            System.out.write('C');
            System.out.write('\n');
        }

        // 推荐使用字符流的输出方法,更容易国际化
        // 使用PrintWriter
        {
            PrintWriter pw = new PrintWriter(System.out, true);
            pw.println("long text");
            int i = 1;
            pw.println(i);
            double d = 4.5e-7;
            pw.println(d);// 4.5E-7
            double d2 = 0.000000045;
            pw.println(d2);// 4.5E-8
        }
    }
}

 文件I/O(暂略)

主要是FileInputStream、FileOutputStream、AutoCloseable接口

13.二、applet(暂略)

一种Java程序,能够在Internet服务器上访问,传输,自动安装并做为Web文件的一部分运行的一类小程序。

13.三、几个主题

transient修饰符:

  • 用来修饰类的变量,那么该类的对象写入永久存储区域时,不会保存该属性的内容

volatile修饰符:

  • 用来修饰类的变量,标明实例变量能够被程序的其它部分随意修改。
  • 例如在多线程下,正常一个变量在一个线程中是有一个副本,而后经过同步方法来工做,可是这种有效效率并不高。
  • 能够用这个修饰类变量,使其主副本和其它私有版本保持一致,各个线程访问主变量的顺序与全部私有副本相同。

instanceof:

  • 判断对象是否该类型或是否能够转换为该类型。

strictfp:

  • Java2对浮点计算模型放宽了,不须要截断特定的中间值,能够防止溢出。
  • 而使用strictfp修饰类、方法、接口,能够使用旧版本Java的浮点计算方式。

native:

  • 本地方法,能够从Java内部调用非Java语言编写的子例程。

assert:

  • 断言,经过则不执行,不经过则抛出异常。2种形式。运行时默认禁用断言,能够运行时给予参数启用或禁用断言。

import static:

  • 静态导入,导入静态成员,节省代码。

this():

  • 调用重载的构造函数,避免在重载的构造函数中代码重复。使用this(),能够减小重复代码,减小了对象代码,提升了对象的加载时间;可是this()的调用和返回又会下降代码执行速度。
  • 若是类只建立少许对象,或调用this()构造函数不多调用,那么没有问题;可是若是须要建立数千个对象或常常调用this函数,这个必须衡量加载时间和执行速度。
  • 2个限制应该牢记:调用this()时不能使用当前类任何实例变量;同一个构造函数不能同时使用super()和this(),由于她们必须是构造函数中的第一条语句

紧凑API配置文件:

  • conpact一、compact二、compact3;2包含1,3包含2;可配置每一个配置文件中包含的库,减小库的大小,减少加载时间。

十4、泛型

目的:为了解决不一样类型的对象须要运行同一算法的需求

泛型:参数化类型,能够使用参数指定所操做数据的类型

之前:要实现这个需求,则使用Object来引用,由于Object是其它全部类的超类,可是不能以类型安全的方式进行工做。

如今:泛型提供了类型安全性,也避免了显式强制类型转换,更安全、容易地重用代码。

泛型类:

import org.junit.Test;

public class test {
    class Gen<T> {
        T ob;
        Gen(T o) {
            ob = o;
        }
        T getob() {
            return ob;
        }
        void showType() {
            System.out.println("Type of T is" + ob.getClass().getName());
        }
    }

    @Test
    public void test() {
        Gen<Integer> iOb;
        iOb = new Gen<Integer>(88);
        iOb.showType();
        int v = iOb.getob();
        System.out.println("value:" + v);

        System.out.println();

        Gen<String> strOb;
        strOb = new Gen<String>("Test");
        strOb.showType();
        String str = strOb.getob();
        System.out.println("value:" + str);
    }
}

泛型只能使用引用类型,不能使用基本类型

多个参数的泛型类,差很少,Gen<T,V>

有界类型:

限制参数类型的范围,使用extends和&链接符,能够使用类和接口限定

class Gen<T extends MyClass & MyInterface>{
}

通配符参数:

当其余类须要引用泛型类,能够不写参数,或者使用通配符参数;通配符参数还能够使用有界通配符(包括extends上界和super下界)

public class test {
    class Gen<T> {
        T ob;
        Gen(T o) {ob = o;}
        T getob() {return ob;}
        void showType() {
            System.out.println("Type of T is" + ob.getClass().getName());
        }
    }
    class Gen1 {
        public void m1(Gen g){// 直接引用类名
            g.showType();
        }
    }
    class Gen2 {
        public void m1(Gen<? extends Integer> g){// 要求泛型的类型是Integer或Integer的子类
            g.showType();
        }
    }
    class Gen3 {
        public void m1(Gen<? super Integer> g){// 要求泛型的类型是Integer或Integer的超类
            g.showType();
        }
    }
    @Test
    public void test() {
        Gen<Integer> iOb;
        iOb = new Gen<Integer>(88);
        iOb.showType();
        int v = iOb.getob();

        new Gen1().m1(iOb);
        new Gen2().m1(iOb);
        new Gen3().m1(iOb);
    }
}

泛型方法:

public class test {
    // 泛型方法
    static <T extends Comparable<T>, V extends T> boolean isIn(T x, V[] y) {
        for (int i = 0; i < y.length; i++)
            if (x.equals(y[i])) return true;

        return false;
    }

    // 泛型构造函数
    public class Gen {
        <T extends Number> Gen(T num) {
            System.out.println(num);
        }
    }

    @Test
    public void test() {
        Integer nums[] = {1, 2, 3, 4, 5};
        if (isIn(2, nums))// 调用泛型方法,不须要指定类型,Java能自动推断
            System.out.println("2 is in nums");

        new Gen(88);
        new Gen(12.6);
    }
}

 

泛型接口:

public class test {
    interface MinMax<T extends Comparable<T>> {// 泛型接口
        T min();
        T max();
    }

    class MyClass2 implements MinMax<Interger>{}// 非泛型实现方式

    class MyClass<T extends Comparable<T>> implements MinMax<T> {// 泛型实现方式
        T[] vals;
        MyClass(T[] o) {
            vals = o;
        }
        public T min() {
            T v = vals[0];
            for (int i = 1; i < vals.length; i++)
                if (vals[i].compareTo(v) < 0) v = vals[i];
            return v;
        }
        public T max() {
            T v = vals[0];
            for (int i = 1; i < vals.length; i++)
                if (vals[i].compareTo(v) > 0) v = vals[i];
            return v;
        }
    }

    @Test
    public void test() {
        Integer inums[] = {3, 6, 2, 8, 5};
        Character chs[] = {'b', 'r', 'a', 'z'};
        MyClass<Integer> iob = new MyClass<Integer>(inums);
        MyClass<Character> cob = new MyClass<Character>(chs);

        System.out.println(iob.min());// 2
        System.out.println(iob.max());// 8
        System.out.println(cob.min());// a
        System.out.println(cob.max());// z
    }
}

原始类型与遗留代码:

// 能够使用不带参数类型的原始类型,其实是建立了Gen<Object>,只为了兼容旧代码,新代码不能这样作
Get raw = new Gen(new Double(98.6));

泛型类层次化:

public class test {
    class Gen<T> {
        T ob;
        Gen(T o) {
            ob = o;
        }
        T getob() {
            return ob;
        }
    }

    class Gen2<T> extends Gen<T> {// 扩展了泛型类Gen,并吧T传递给Gen
        Gen2(T o) {
            super(o);
        }
    }

    class Gen3<T, V> extends Gen<T> {// 添加本身另外的参数化类型
        V ob2;
        Gen3(T o, V o2) {
            super(o);
            ob2 = o2;
        }
        V getob2() {
            return ob2;
        }
    }

    class Gen4<T> extends Object {// 超类能够不是泛型类
    }
}

泛型的类型推断:

MyClass<Integer, String> mcOb = new MyClass<Integer, String>(98,"String");
MyClass<Integer, String> mcOb = new MyClass<>(98,"String");// 建立实例时推断

if(mcOb.isSame(new MyClass<>(1,"String"))) System.out.println("same");// 传递参数时推断

擦除:

Java经过擦除这个技术来实现泛型。

擦除工做原理:编译Java代码时,全部泛型信息被擦除;使用它们的界定类型替换类型参数,若是没有界定类型则使用Object,而后使用适当的类型转换。因此泛型只存在于源代码,运行时没有泛型。

详细深刻的内容,这里不讨论。

模糊性错误:

class MyClass<T,V>{// 当T和V同类型时,就会引起模糊性错误,2个set重载编程一样类型
    T ob1;
    V ob2;

    void set(T o){ob1 = o;}
    void set(V o){ob2 = o;}
}

泛型的使用限制:

class Gen<T>{
    T ob;
    T vals[];

    Gen(){
        ob = new T();// 不能实例化类型参数
        vals= new T[10];// 不能实例化类型为参数类型的数组
    }

    static T ob;// 错误,不能使用参数类型建立静态成员
    static T getob(){..}// 错误,不能使用参数类型建立静态成员
}

Gen<Integer> gens[] = new Gen<Integer>[10];// 错误,不能建立特定类型的泛型引用数组
Gen<?> gens[] = new Gen<?>[10];// 正确

// 另外泛型类不能扩展Throwable,表明不能建立泛型异常类

十5、lambda表达式

JDK8新增功能

增长了新的语法元素

使API库增长了新的功能,包括多核环境的并行处理功能(特别是for-each操做)变得容易,以及支持对数据执行管道操做的新的流API

催生了新的Java功能,包括默认方法以及方法引用

2个关键结构:

lambda表达式:

  • 本质上是一个匿名方法。这个方法不是用来独立执行的,而是用于实现函数式接口定义的另外一个方法。
  • 实现函数式接口,一种方法是日常同样,建立一个类,而后实现方法;而lambda是另外一种方法,使用匿名方法的方式实现。
  • lambda表达式会致使产生一个匿名类。
  • lambda表达式也常常成为闭包。

函数式接口:

  • 仅包含一个抽象方法的接口,一般表示单个动做。
  • 函数式接口定义了lambda表达式的目标类型。
  • 特别注意:lambda表达式只能用于其目标类型已被指定的上下文中。
  • 另外,函数式接口有时候被称为SAM类型,意思是单抽象方法(Single Abstract Method)

 应用实例:

()->123.45
至关于
double myMeth(){return 123.45;}

()->Math.randow()*100
()->(n%2)==0

// 函数式接口,只有一个抽象方法的接口
// JDK8以前,全部接口方法隐式都是抽象方法
// 可是JDK8以后,能够接口声明默认方法
// 全部JDK8及之后,没有默认实现的接口方法,才是隐式地是抽象方法
interface MyNumber{
    double getValue();
}

MyNumber myNum;// 定义一个函数式接口
myNum = ()->123.45;// 赋值lambda表达式,至关于建立了一个匿名类,实现了MyNumber接口,该方法的内容等于等号后面部分。
System.out.println(myNum.getValue())// 有具体实现的接口,能够调用方法

// 带参数的lambda表达式
(n)->(n%2)==0// 参数类型能够根据接口来推线,能够不指定参数类型
(int n)->(n%2)==0// 显式指定参数类型

// 多个参数
NumericTest2 isFactor  = (n,d)->(n%d)==0;

// 使用代码块的lambda表达式
NumericFunc factorial = (n) -> {
    int result = 1;
    
    for(int i=1; i <= n; i++)
        result = i * result;
        
    return result;
};

// 泛型函数式接口
// lambda表达式不能指定类型参数,可是函数式接口能够是泛型
interface SomeFunc<T>{
    T func(T t);
}
SomeFunc<String> func1 = (str) -> {... return str;};
func1.func("func1");
SomeFunc<Integer> func2 = (val) -> {... return val;};
func2.func(1);

// 做为参数传递lambda表达式
interface StringFunc{
    String func(String n);
}
public String stringOp(StringFunc,String s)
{
    return StringFunc.func(s);
}

StringFunc func = (n)->{return n+"!";};
String result = stringOp(func,"no");

// 若是lambda表达式抛出异常,接口的throws子句应该匹配该异常
interface StringFunc{
    String func(String n) throws NullException;
}
StringFunc func = (n)->{
    if(n.equals(""))
        throw new NullException();
    return n+"!";
};

lambda表达式和变量捕获:

lambda表达式中,能够访问:

  • 能够获取或者是外层类的实例或静态变量的值
  • 能够隐式或显式地访问this变量,引用lambda表达式外层类的调用实例
  • 变量捕获:
    • lambda表达式只能使用实质上是final(第一次赋值后,值就不变化)的局部变量;
    • lambda表达式不能修改外层做用域内的局部变量,由于修改会移除其实质final状态

方法引用:

在上面,要传入一个函数式接口的实例,必须使用lambda语句建立一个匿名实现。

方法引用:若是咱们在其余类中,已有方法恰好实现了这个接口,那么咱们能够直接引用这个方法,传入给这个函数式接口参数

原理:方法引用会建立函数式接口的一个实例。

// 静态方法引用
interface StringFunc{
    String func(String n);
}
class MyStringOps{
    static String strReverse(String str){
        ....
        return ...;
    }
}
static String stringOp(StringFunc sf,String s){
    return sf.func(s);
}
String outStr = stringOp(MyStringOps::strReverse, "str1");

// 实例方法引用
class MyStringOps{
    String strReverse(String str){
        ....
        return ...;
    }
}
static String stringOp(StringFunc sf,String s){
    return sf.func(s);
}
MyStringOps ops = new MyStringOps();
String outStr = stringOp(ops::strReverse, "str1");

// 类的实例方法的引用
// 上面引用的是类的静态方法,实例的方法;如今还能够引用类的实例方法
// 此时,函数式接口匹配的方法是,第一个参数匹配调用对象,后面的参数再匹配实例方法的参数
interface MyFunc<T>{
    boolean func(T v1,T v2);
}
class HighTemp{
    boolean sameTemp(HighTemp ht2){
        ...
    }    
}

static <T> void do(MyFunc<T> f,T t1,T t2){
    f.func(t1,t2);// 执行的是t1.sameTemp(t2)
}
// HighTemp的sameTemp方法只有一个参数,可是调用类的实例方法,第一个参数须要匹配调用对象
do(HighTemp::sameTemp,new HighTemp(1),new HighTemp(2));

// super::name 能够引用发放的超类版本

// 泛型中的方法引用
// 泛型方法MyArrayOps::<Integer>countMatching
// 泛型类MyArrayOps<Integer>::countMatching
// 类型也能够不写,经过类型推断
interface MyFunc<T>{
    int func(T[] vals, T v);
}
class MyArrayOps{
    static <T> int countMatching(T[] valus,T v){
        int count = 0;
        for(int i=0;i<vals.length;i++)
            if(vals[i]==v)count++;
        return count;
    }
}
class Demo{
    static <T> int myOp(MyFunc<T> f,T[] vals,T v){
        return f.func(vals,v);
    }
    public static void main(String args[]){
        Integer[] vals = {1,2,3,4,2,2,3,4};
        String[] strs = {"One","Two","Three","Two"};
        int count;
        
        count = myOp(MyArrayOps::<Integer>countMatching,vals,4);
        count = myOp(MyArrayOps::<String>countMatching,strs,"Two");
    }
}

// Collection,如Compare接口,不必定须要实现接口,并建立对应实例
// 能够考虑建立一个静态方法,与Comparator的compare方法兼容,而后使用方法引用
class MyClass{
    private int val;
    MyClass(int v){val = v;}
    int getVal(){return val;}
}
class UseMethodRef{
    static int compareMC(Myclass a,MyClass b){
        reutrn a.getVal() - b.getVal();
    }
    public static void main(String args[])
    {
        ArrayList<MyClass> a1 = new ArrayList<MyClass>();
        a1.add....
        MyClass maxValObj = Collections.max(a1,UseMethodRef::compareMC);
    }
}

构造函数引用:

暂略,不想看了。

预约义的函数式接口:

为了不常常本身定义函数式接口,JDK8提供了java.util.function,提供了预约义的函数式接口

十6、字符串处理

String、StringBuffer、StringBuilder

StringBuffer、StringBuilder用于能够修改的字符串

StringBuilder,StringBuilder不是同步的,因此不是线程安全,优点在于性能更高

若是字符串被多个线程修改,没有使用其它同步措施的话,须要使用StringBuffer

十7、java.lang

暂略,大部分是接口和API

public interface Iterable<T> {
    // 返回迭代器
    Iterator<T> iterator();

    // 迭代每一个元素执行action代码
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    // 返回被迭代序列的Spliterator
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

十8、java.util集合框架

一、集合框架概述

集合框架以前:Java提供了特定的类以存储和管理对象组,如Dictionary、Vector、Stack和Properties。

问题:缺乏集中、统一的主体,不易扩展,不易改造。

集合框架的目标:

  • 一、高性能。基本集合(动态数组、链表、树和哈希表)的实现是高效率的。
  • 二、统1、高互操做性。框架必须容许不一样类型的集合以相似的方式进行工做,而且具备高度的互操做性。
  • 三、易扩展、易改造。
  • 四、必须将标准数组集成到集合框架中的机制。

为了知足这些目标,Java提供了:

  • 一套标准接口和实现:整个集合框架基于一套标准接口进行构造,提供了这些接口的一些能够直接使用的标准实现(如LinkedList、HashSet、TreeSet),也能够实现本身的集合。
  • 集合算法:算法是集合机制中的另外一个重要部分。算法操做集合,而且被定义为Collections类中的静态方法。因此全部集合均可以使用它们,每一个集合都不须要实现本身的版本,算法为操做集合提供了标准方法。
  • Iterator接口,迭代器:为访问集合中的元素提供了通用的、标准的方式,每次访问一个元素。每一个集合都提供了迭代器。
  • spliterato:JDK8提供了一种新的迭代器,叫spliterator,用于支持并行迭代。支持spliterator的接口有Spliterator和支持基本类型的几个嵌套接口。JDK8还添加了用于基本类型的迭代器接口,例如PrimitiveIterator和PrimitiveIterator.OfDouble。
  • 处理映射:除了集合外,框架还定义了一些映射接口和类。映射存储键值对。虽然映射是集合框架的组成部分,可是严格意义上说,他们不是结婚。不过,能够得到映射的集合视图(collection-view)。这种视图包含来自映射的元素,并存储在集合中。所以,也能够做为一种选择,能够想处理集合同样处理映射内容。

新的JDK为集合框架带来的改变:

  • 一、泛型:泛型从根本上改变了集合框架,新增的泛型使整个集合框架对泛型进行了从新设计。因此集合如今都是泛型,许多操做集合的方法如今都是使用泛型参数。
  • 二、自动装箱:自动装箱使得使用基本类型更加容易。集合只能存储引用,不能存储基本类型值,之前须要手动装箱,如今就再也不须要了。
  • 三、for-each风格的for循环:合框架中全部集合类进行了从新设计以实现Iterable接口,因此能够使用for-each风格的for循环遍历集合。之前须要使用迭代器,如今能够使用for循环替代。

二、集合接口

除了集合接口外,集合还使用Comparator、RandomAccess、Iterator以及ListIterator接口,这些后面探讨。JDK8开始,还使用Spliterator接口。

Collection接口

Collection接口是集合框架的基础,全部定义集合的类都必须实现这个接口,是一个泛型接口。

interface Collection<E> //E是存储对象的类型

Collection扩展了Iterable接口,因此全部集合均可以使用for-each风格的for循环

Collection声明了全部集合将拥有的核心方法

异常:

  • UnsupportedOperationExceiption:不能被修改集合执行修改集合的方式时抛出
  • ClassCastException:一个对象和另外一个对象不兼容时抛出,如试图将一个不兼容的对象添加到集合中
  • NullPointerException:视图在不容许存储null对象的集合中存储null对象
  • IllegalArgumentException:使用参数无效
  • IllegalStateException:未长度固定且已满的集合添加元素

核心方法总结:添加、删除、检查是否包含、获取迭代器、转换数组、获取流

List接口

扩展Collection,并声明了用来存储一连串元素的集合的行为。

能够使用从0开始的索引,经过元素位置插入或访问元素。

能够包含重复元素

interface List<E> //E是存储对象的类型

 

Set接口

Set接口定义了组,扩展了Collection接口,声明了集合中不容许有重复元素的组行为

没有定义本身的其它方法,添加剧复元素的时候,add()方法返回false

interface Set<E> //E是存储对象的类型

SortedSet接口

SortedSet扩展了Set接口,并声明以升序进行排序的组行为。

interface SortedSet<E> //E是存储对象的类型

NavigableSet接口

NavigableSet接口扩展了SortedSet接口,而且声明了支持基于最接近匹配原则检索元素的集合行为

interface NavigableSet<E> //E是存储对象的类型

Queue接口

Queue接口扩展了Collection接口,声明了队列的行为,队列一般是先进先出队列,但也有其余准则的队列类型。

interface Queue<E> //E是存储对象的类型

Deque接口

Deque接口扩展了Queue接口,而且声明了双端队列行为,既能够先进先出,也能够后进先出

interface Deque<E> //E是存储对象的类型

三、集合类

集合接口的标准实现

ArrayList

ArrayList扩展了AbstractList类并实现了List接口

class ArrayList<E> //E是存储对象的类型

用于按需增加的动态数组,Java里面的数组长度是固定的,定义后不能增加或缩小。

// 构造函数
ArrayList()
ArrayList(Collection<? extends E> c) // 使用一个集合进行初始化
ArrayList(int capacity) // 初始容量

使用示例

public class test {
    @Test
    public void test() {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("a");
        arrayList.add("d");
        arrayList.add("c");
        arrayList.add("d");
        arrayList.add(1, "b");
        System.out.println(arrayList);// [a, b, d, c, d]
        System.out.println(arrayList.size());// 5

        arrayList.remove("d");// 从前日后查找,找到第一个删除
        System.out.println(arrayList);// [a, b, c, d]
        System.out.println(arrayList.size());// 4

        arrayList.remove("d");
        System.out.println(arrayList);// [a, b, c]
        System.out.println(arrayList.size());// 3

        arrayList.ensureCapacity(12);// 一次性增长内存,提高性能;避免每次增长一个元素就分配一次内存
        System.out.println(arrayList.size());// 仍为3

        arrayList.trimToSize();// 减小内存到恰好容纳如今的元素
        System.out.println(arrayList.size());// 仍为3

        // 转换为数组
        Object[] array1 = arrayList.toArray();// 方法1,转换为Object数组
        // 经常使用方法2,转换为特定类型数组
        String[] array2 = new String[arrayList.size()];
        arrayList.toArray(array2);
        for (Object item : array1) System.out.print(item + ",");// a,b,c,
        System.out.println();
        for (Object item : array2) System.out.print(item + ",");// a,b,c,
    }
}

LinkedList类

LinkedList类扩展了AbstractSequentialList类,实现了List、Deque以及Queue接口,而且提供了一种链表数据结构

class LinkedList<E> //E是存储对象的类型
// 构造函数
LinkedList()
LinkedList(Collection<? extends E> c)
public class test {
    @Test
    public void test() {
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("F");
        linkedList.add("B");
        linkedList.add("D");
        linkedList.add("E");
        linkedList.add("C");
        linkedList.add("Z");
        linkedList.add("A");
        linkedList.add(1, "A2");
        System.out.println(linkedList);// [F, A2, B, D, E, C, Z, A]

        linkedList.remove("F");
        linkedList.remove(2);
        System.out.println(linkedList);// [A2, B, E, C, Z, A]

        linkedList.removeFirst();
        linkedList.removeLast();
        System.out.println(linkedList);// [B, E, C, Z]

        String val = linkedList.get(2);
        linkedList.set(2, val + "Changed");
        System.out.println(linkedList);// [B, E, CChanged, Z]
    }
}

HashSet类

HashSet类扩展了AbstractSet类并实现了Set接口,用于建立使用哈希表存储元素的集合。

散列机制优点是及时集合较大,add()、contains()、remove()、size()的方法执行时间保持不变

class HashSet<E> //E是存储对象的类型
// 构造函数
HashSet()
HashSet(Collection<? extends E> c)// 使用集合初始化
HashSet(int capacity)// 使用容量初始化,默认16
HashSet(int capacity, float fillRatio)// 容量和填充率初始化,填充率是0.0到1.0之间,集合中数量达到填充率,就会扩展和哈希组,默认0.75

HashSet没有本身的方法,只有超类和接口的方法

public class test {
    @Test
    public void test() {
        HashSet<String> hs = new HashSet<String>();
        hs.add("b");
        hs.add("c");
        hs.add("d");
        hs.add("e");
        hs.add("a");
        hs.add("a");
        System.out.println(hs);// [a, b, c, d, e] 不可重复且没有顺序
    }
}

LinkedHashSet类

LinkedHashSet扩展了HashSet类,没有添加本身的方法

class LinkedHashSet<E> //E是存储对象的类型

LinkedHashSet维护条目中的一个链表,链表中条目顺序就是插入顺序,能够按照插入顺序迭代。

同时toString()方法也是按照插入顺序输出

public class test {
    @Test
    public void test() {
        LinkedHashSet<String> hs = new LinkedHashSet<String>();
        hs.add("b");
        hs.add("c");
        hs.add("d");
        hs.add("a");
        hs.add("e");
        hs.add("a");
        System.out.println(hs);// [b, c, d, a, e] 按照插入顺序输出,重复的则不插入
    }
}

TreeSet

TreeSet扩展了AbstractSet类并实现了NavigableSet接口,用于建立使用树存储的组。

对象以升序存储,访问和检索速度至关快,使得对存储大量的、必须可以快速查找的有序信息来讲,TreeSet是极佳选择。

class TreeSet<E> //E是存储对象的类型
// 构造函数
TreeSet()// 建立空树,按照元素的天然顺序以升序进行存储
TreeSet(Collection<? extends E> c)// 构建一个包含集合c中元素的树
TreeSet(Comparator<? super E> comp)// 构建一个空树,按照comp指定的比较器进行存储
TreeSet(SortedSet<E> ss)// 构建一个包含ss中元素的树
public class test {
    @Test
    public void test() {
        TreeSet<String> ts = new TreeSet<String>();

        ts.add("C");
        ts.add("A");
        ts.add("B");
        ts.add("E");
        ts.add("F");
        ts.add("D");

        System.out.println(ts);// [A, B, C, D, E, F] 自动排序
        System.out.println(ts.subSet("C","F"));// [C, D, E],使用NavagalbeSet接口的方法检索TreeSet元素
    }
}

PriorityQueue类

PriorityQueue扩展了AbstractQueue类并实现了Queue接口,用于建立根据队列的比较器来判断优先次序的队列。

PriorityQueue是动态的、按需增加的。

class PriorityQueue<E> //E是存储对象的类型
// 构造函数
PriorityQueue()// 起始容量为11
PriorityQueue(int capacity)// 指定初始容量
PriorityQueue(Comparator<? super E> comp)// 指定比较器
PriorityQueue(int capacity,COmparator<? super E> comp)// 指定容量和比较器
PriorityQueue(Collection<? extends E> c)// 使用集合C来初始化
PriorityQueue(PriorityQueue<? extends E> c)// 使用集合C来初始化
PriorityQueue(SortedSet<? extends E> c)// 使用集合C来初始化

若是没有指定比较器,将使用队列中存储的数据类型的默认比较器。

默认比较器以升序对队列进行排序。

使用comparator()方法获取比较器,若是队列使用的是天然顺序,则返回null

虽然能够使用迭代器遍历PriorityQueue,可是迭代顺序是不肯定的。

使用PriorityQueue,应该使用offer()和poll()这类由Queue接口定义的方法 

ArrayDeque类

ArrayDeque扩展了AbstractCollection类并实现了Deque接口,没有添加本身的方法。

ArrayDeque是动态数组,没有容量限制(Deque接口支持限制容量的实现,但不是必须的)

class ArrayDeque<E> //E是存储对象的类型
// 构造函数
ArrayDeque()// 空的双端队列,初始容量是16
ArrayDeque(int size)// 指定容量
ArrayDeque(COllection<? extends E> c)// 使用集合来初始化
public class test {
    @Test
    public void test() {
        ArrayDeque<String> adq  = new ArrayDeque<String>();
        adq.push("A");
        adq.push("B");
        adq.push("D");
        adq.push("E");
        adq.push("F");
        System.out.println(adq);// [F, E, D, B, A]
        while (adq.peek()!=null)
            System.out.print(adq.poll()+",");// F,E,D,B,A,
    }
}

EnumSet类

EnumSet扩展了AbstractSet并实现了Set接口,专门用于枚举类型的元素。

class EnumSet<E extends Enum<E>> //E是存储对象的类型

EnumSet类没有定义构造函数,而是使用工厂方法来建立对象

四、经过迭代器访问集合

若是但愿遍历集合中的元素,方法之一是使用迭代器。

迭代器是实现了Iterator或ListIterator接口的对象。

Iterator接口容许遍历集合,获取或移除元素。

ListIterator接口扩展了Iterator接口,容许双向遍历列表,而且容许修改元素。

interface Iterator<E> //E是存储对象的类型
interface ListIterator<E> //E是存储对象的类型

使用迭代器

iterator:

获取迭代器:每一个集合类都提供了iterator()方法,方法返回一个指向集合开头的迭代器

具体步骤:

  • 一、调用集合的iterator()方法,获取指向集合开头的迭代器
  • 二、创建一个hasNext()方法调用循环,只要hasNext()返回true,就继续迭代
  • 三、循环中,调用next()方法获取每一个元素

对于实现List接口的集合,还能够调用listIterator()方法来获取迭代器,这种方式提供了向前和向后2个方向的访问集合的能力,并容许修改元素。除此以外,2个用法相似。

public class test {
    @Test
    public void test() {
        ArrayList<String> a1 = new ArrayList<String>();
        a1.add("C");
        a1.add("A");
        a1.add("E");
        a1.add("B");
        a1.add("D");
        a1.add("F");
        System.out.println(a1);// [C, A, E, B, D, F]

        Iterator<String> itr = a1.iterator();
        while (itr.hasNext()) {
            String element = itr.next();
            System.out.print(element + ",");// C,A,E,B,D,F,
        }
        System.out.println();

        ListIterator<String> litr = a1.listIterator();
        while (litr.hasNext()) {
            String element = litr.next();
            litr.set(element + "+");
        }
        System.out.println(a1);// [C+, A+, E+, B+, D+, F+]

        itr = a1.iterator();
        while (itr.hasNext()) {
            String element = itr.next();
            System.out.print(element + ",");// C+,A+,E+,B+,D+,F+,
        }
        System.out.println();

        while (litr.hasPrevious()) {
            String element = litr.previous();
            System.out.print(element + ",");// F+,D+,B+,E+,A+,C+,
        }
        System.out.println();
    }
}

for-each循环代替迭代器:

若是不修改集合的内容,也不用反向获取元素,那么使用for-each风格的for循环遍历集合一般更加方便。

for循环能够遍历全部实现Iterable接口的集合对象,而全部集合类都实现了这个接口,因此均可以用for循环操做。

public class test {
    @Test
    public void test() {
        ArrayList<Integer> vals = new ArrayList<Integer>();
        vals.add(1);
        vals.add(2);
        vals.add(3);
        vals.add(4);
        vals.add(5);
        System.out.println(vals);// [1, 2, 3, 4, 5]

        for(int v :vals)
            System.out.print(v+",");// 1,2,3,4,5,
        System.out.println();

        int sum = 0;
        for(int v:vals)
            sum+=v;
        System.out.println(sum);// 15
    }
}

Spliterator:

JDK8新增一种叫splitertor的迭代器,由Spliterator接口定义。

Spliterator用于循环遍历元素序列。

它提供的方法远比Iterator或ListIterator多,最重要的一点是它支持并行迭代序列的一部分。

即便用不到并行编程,也能够使用Spliterator,其中一个缘由是它把hasNext和next操做合并到一个方法中,从而提供了效率

interface Spliterator<T> //T是被迭代元素的类型

暂略,须要lambda表达式知识

RandomAccess接口:

RandomAccess接口不包括成员。然而经过实现这个接口,能够代表集合支持高效地随机访问其中的元素。尽管集合可能支持随机访问,可是可能没有这么高效。

经过检查RandomAccess接口,客户端代码能够在运行时肯定集合是否适合特定类型的随机访问操做——特别是当将他们应用于大的集合时(能够使用instance of来判断类是否实现了这个接口)。

ArrayList和遗留的Vector类实现了RandomAccess接口。

五、使用映射

映射是存储键和值之间关系(键值对)的对象。

键和值都是对象,键必须惟一,但值能够重复。

某些映射能够接收null键和null值,其它不能。

映射没有实现Iterable接口,因此不能使用for-each风格的for循环,也不能获取迭代器。

可是能够获取映射的集合视图,集合视图容许使用for循环和迭代器。

映射接口:

Map接口:

Map接口将惟一键映射到值。给定键和值就能够在Map对象中存储;存储后能够使用键来检索值。

interface Map<K,V>// K是键的类型,V是值的类型。

映射围绕2个基本方法:get()、put()

使用entrySet()方法,返回一个Set对象,包含映射中元素。

使用keySet()方法,返回一个Set对象,做为键的集合视图。

使用values()方法,返回一个Set对象,做为值的集合视图。

修改一个集合会影响其余集合,由于集合的数据是引用映射内的数据。

集合视图是将映射集成到集合框架中的手段。

SortedMap接口

SortedMap接口扩展了Map接口,确保条目以键的升序保存。

interface SortedMap<K,V>// K为键类型,V为值类型

有序映射支持很是高效的子映射操做,如headMap()、tailMap()或subMap()方法。

NavigableMap接口

NavigableMap接口扩展了SortedMap接口,支持基于最接近匹配原则的条目检索行为,即支持检索与给定的一个或多个键最相匹配的条目。

interface NavigableMap<K,V>

Map.Entry接口

Map.Entry接口提供了操做映射条目的功能。

Map接口声明的entrySet()方法返回一个包含映射条目的Set对象。

组的全部元素都是Map.Entry对象。

interface Map.Entry<K,V>

另外JDK8添加了2个静态方法:comparingByKey()和comparingByValue()。

前者返回根据键比较条目的Comparator对象,后者返回根据值比较条目的Comparator对象。

映射类

有几个类实现了映射接口

AbstractMap是全部具体映射实现的超类。

WeakHasMap实现了使用“弱键”的映射,键不在使用时能够被垃圾回收,这里不讨论。

一、HashMap类

HashMap扩展了AbstractMap类并实现了Map接口,没有添加本身的方法。

他使用哈希表存储映射,使得即便比较大的集合,get()和put()方法执行时间保持不变

class HashMap<K,V>
// 构造函数
HashMap()
HashMap(Map<? extends K, ? extends V> m)// 使用m中元素初始化
HashMap(int capacity)// 使用容量初始化
HashMap(int capacity, float fillRatio)// 使用容量和填充率初始化,默认是16,0.75
public class test {
    @Test
    public void test() {
        HashMap<String,Double> hm = new HashMap<String,Double>();

        hm.put("a",new Double(11.24));
        hm.put("d",new Double(22.24));
        hm.put("e",new Double(33.24));
        hm.put("b",new Double(44.24));
        hm.put("c",new Double(55.24));

        Set<Map.Entry<String,Double>> set = hm.entrySet();

        for(Map.Entry<String,Double>me:set){
            System.out.print(me.getKey()+":"+me.getValue()+",");// a:11.24,b:44.24,c:55.24,d:22.24,e:33.24,
        }
        System.out.println();

        double balance = hm.get("a");
        hm.put("a",balance+100);

        System.out.println(hm.get("a"));// 111.24
    }
}

TreeMap类

TreeMap扩展了AbstractMap类并实现了NavigableMap接口,该类用于建立存储在树结构中的映射。

TreeMap提供了有序存储键值对的搞笑手段,并支持快速检索。

与哈希映射不一样,树映射确保元素以键的升序存储。

class TreeMap<K,V>
// 构造函数
TreeMap()// 按键的天然顺序存储
TreeMap(Comparator<? super K> comp)// 使用比较器comp进行排序
TreeMap(Map<? extends K, ? extends V> m)// 使用m中条目初始化树映射,使用键的天然顺序进行排序
TreeMap(SortedMap<K, ? extends V> sm)// 使用sm中条目初始化树映射,使用sm相同顺序进行排序

TreeMap类的映射方法没有超出NavagableMap接口和AbstractMap类定义的那些方法。

public class test {
    @Test
    public void test() {
        TreeMap<String,Double> tm = new TreeMap<String,Double>();
        tm.put("a",new Double(11.24));
        tm.put("d",new Double(22.24));
        tm.put("e",new Double(33.24));
        tm.put("b",new Double(44.24));
        tm.put("c",new Double(55.24));
        Set<Map.Entry<String,Double>> set = tm.entrySet();

        for(Map.Entry<String,Double>me:set){
            System.out.print(me.getKey()+":"+me.getValue()+",");// a:11.24,b:44.24,c:55.24,d:22.24,e:33.24, 按照键升序排列
        }
        System.out.println();

        double balance = tm.get("a");
        tm.put("a",balance+100);

        System.out.println(tm.get("a"));// 111.24
    }
}

LinkedHashMap类

LinkedHashMap扩展了HashMap类,在映射中以插入条目的顺序维护一个条目链表,从而能够按照插入顺序迭代整个映射。

也就是说,当遍历LinkedHashMap的集合视图时,将以元素的插入顺序返回元素。也能够建立按照最后访问的顺序返回元素的LinkedHashMap。

class LinkedHasMap<K,V>
// 构造函数
LinkedHashMap()
LinkedHashMap(Map<? extends K, ? extends V> m)// 使用m中元素初始化LinkedHashMap
LinkedHashMap(int capacity)// 指定容量
LinkedHashMap(int capacity, float fillRatio)// 指定容量和填充率,默认16,0.75
LinkedHashMap(int capacity, float fillRatio, boolean Order)// Order为true,使用访问顺序;Order为false,使用插入顺序,默认的是插入顺序

LinkedHashMap除了继承自HashMap定义的方法外,只添加了一个方法,removeEldestEntry()

protected bollean removeEldestEntry(Map.Entry<k,V> e)

这个方法由put()和putAll()调用。最旧的条目由e传入。

默认状况下这个方法返回false,而且不执行任何操做;重写这个方法,能够使LinkedHashMap移除映射中最旧的条目。

IdentityHashMap类

IdentityHashMap扩展了AbstractMap类并实现了Map接口。除了当比较元素时使用引用相等性外,其它方面和HashMap相似

class IdentityHasMap<k,V>

API文档明确指出IdentityHashMap不用于通用目的

EnumMap类

EnumMap扩展了AbstractMap类并实现Map接口,是专门为使用枚举类型的值设计的。

class EnumMap<K extends Enum<K>,V>
// 构造函数
EnumMap(Class<K> kType)// 建立类型为kType的空EnumMap
EnumMap(Map<K, ? extends V> m)// 建立一个包含m中相同条目的EnumMap
EnumMpa(EnumMap<K, ? extends V> em)// 建立一个使用em中的值进行初始化的EnumMap

EnumMap类没有定义本身的方法。

六、比较器

TreeSet和TreeMap使用有序顺序存储元素。

比较器精肯定义了有序顺序的含义。

默认状况,Java使用天然循序为这些元素排序(如ABCD,1234等),而比较器可让咱们自定义顺序

interface Comparator<T>

JDK8前,Comparator接口定义了2个方法

int compare(T obj1, T obj2)// obj1大于obj2则返回正数
boolean equals(object obj)// 若是obj和调用对象都是比较器,且使用相同的排序规则,则返回true,不然返回false;通常不须要重写equals方法

JDK8经过默认接口方法和静态接口方法,增长了不少新功能

default Comparator<T> reversed()// 得到一个反转的比较器
static <T extends Comparable<? super T>> Comparator<T> reverseOrder()// 返回一个颠倒元素的天然顺序比较器
static <T extends Comparable<? super T>> Comparator<T> naturalOrder()// 返回一个天然顺序比较器
static <T> Comparator<T> nullsFirst<Comparator<? super T> comp)// 支持处理null值,并认为null比其余值小
static <T> Comparator<T> nullsLast<Comparator<? super T> comp)// 支持处理null值,并认为null比其余值大
// thenComparing:当第一次比较结果相等时,则使用这个比较器执行第二次比较
// 三种形式
default Comparator<T> thenComparing(Comparator<? super T> thenByComp)// 指定第二次使用的比较器
default <U extends Comparable<? super U> Comparator<T> thenComparing(Function<? super T, ? extends U> getKey)// getKey引用的函数用于获取下一个比较键
default <U> Comparator<T> thenComparing(Function<? super T, ? extends U> getKey,Comparator<? super U> keyComp)// keyComp指定了用于比较键的比较器
// Comparator还为基本类型添加了以下所示的专用版本方法
// 这些方法中,getKey引用的函数用于获取下一个比较键
static <T> Comparator<T> ComparingDouble(ToDoubleFunction<? super T> getKey)
static <T> Comparator<T> ComparingInt((ToIntFunction<? super T> getKey)
static <T> Comparator<T> ComparingLong((ToLongFunction<? super T> getKey)

使用比较器代码(待补充)

七、集合算法

集合框架定义了一些能够用于集合和映射的算法,被定义在Collections类的静态方法中

不少方法,待补充

八、Arrays类

Arrays类提供了对数组操做有用的方法,有助于链接集合和数组。

如下将解释Arrays类定义的每一个方法

待补充

九、遗留的类和接口

早期的java.util包没有包含集合框架,而是定义了几个类和一个接口,用来提供存储对象方法的专业方法。

注意现代集合类都不是同步的,可是全部遗留类都是同步的,固然能够使用Collection提供的算法很容易实现同步。

包括

  • Enumeration接口
  • Vector类
  • Dictionary类
  • Hashtable类
  • Properties类、store()和load()方法

十9、java.util其它工具类(略)

二10、java.io(略)

二11、探究NIO(略)

二12、联网(略)

二十3、Applet(略)

二十4、事件处理(略)

二十5、AWT介绍:使用窗口、图形和文本(略)

二十6、使用AWT控件、布局管理器和菜单(略)

二十7、图像(略)

二十8、并发使用工具(略)

二十9、流API

流的概念:流是数据的渠道。

流表明一个对象序列。

流操做数据源,如数组或集合。

流自己不存储数据,只是移动数据,移动过程当中可能对数据执行过滤、排序或其余操做。

通常流操做不会修改数据源,而是建立一个新的流,包含过滤、排序或其余操做后的结果。

流接口

 

 

终端操做:会消费流,被消费后,流不能重用。

中间操做:会产生另外一个流。中间操做不是当即发生,是在新流上执行完终端操做后,中间操做才会发生,称为延迟行为,能让流API更加高效地执行。

另外一个关键点:

无状态:独立于其余元素处理每一个元素。如过滤,filter()

有状态:某个元素处理以来其余元素。如排序,sorted()

注意,并行处理流时,无状态和有状态区别尤为重要,由于有状态操做可能须要几回处理才能完成。

 

Stream操做是对象引用,因此增长了如下几个接口支持处理基本类型流,都扩展了BaseStream

DoubleStream

IntStream

LongStream

重点关注Stream,基本类型流处理上基本相同

 

 获取流:

一、COllection接口被扩展,包含2个获取集合流的方法

 

 补充代码

 

 缩减操做

基于任意条件,从流中返回一个值。全部缩减操做都是终端操做。

 

 

 

 

三10、正则表达式和其它包(略)

三11、Swing简介(略)

三12、探究Swing(略)

三十3、Swing菜单简介(略)

三十4、JavaFX GUI编程简介诶(略)

三十5、探究JavaFX控件(略)

三十6、JavaFX菜单简介(略)

三十7、Java Bean

这个是Java的组件架构,经过必定的规范保证组件能够重用和互操做;可是有Spring框架后,Spring框架中的Bean是基于POJO的,因此Java Bean的意义不大了。(我的观点)

软件行业一直在探索,以实现基于组件方式的可重用和互操做性。

Java Bean是一种组件架构,但愿开发软件时,能够利用这些软件组件来构建复杂的系统。

例如电子行业的电阻器、电容器、传感器等。

那么设计这能够选择组件,理解他们的功能,并把他们集成到应用程序中。

Java Bean:

Java语言书写,而且遵照JavaBean API规范

软件组件,被设计成能够在不一样环境下重用。

功能能够是获取库存值,又或者预测股票走势。

优点:

内省:

  • JavaBean的核心是内省,内省是分析Bean的过程,用于肯定Bean的功能。
  • 这是Java Bean API的本质特征,容许其余应用程序获取关于组建的信息。
  • 有了内省机制,Java Bean技术才能起做用。

2种方式指示Bean应当暴露哪些属性、事件和方法:

  • 简单的命名约定,这些约定使内省机制可以推断出与Bean相关信息
  • 提供一个扩展了BeanInfo的接口的附加类,显式提供这些信息

属性的设计模式:

  • 属性是Bean状态的子集。
  • 赋给属性的值决定了组件的行为和外观。
  • 属性经过setter方法设置,经过getter方法获取
  • 2种属性:简单属性、索引属性

简单属性:

补充代码

索引属性:

补充代码

事件的设计模式

补充代码

方法与设计模式:

  • 设计模式不能用于命名非属性方法。
  • 内省机制可以发现Bean的全部公有方法,可是不能显示保护方法和私有方法。

BeanInfo接口:

  • 显式控制哪些信息可得
  • 补充代码

绑定属性与约束属性:

具备绑定属性的Bean:

  • 属性发生变化时会产生事件。
  • 时间的类型是PropertyChangeEvent,而且事件将被发送到以前注册的对接收这种通知感兴趣的对象。
  • 处理这种事件的类必须实现PropertyChangeListener接口。

具备约束属性的Bean:

  • 当尝试修改约束属性的值会产生事件。
  • 事件的类型也是PropertyChangeEvent,而且也将被发送到以前的对接收这种通知感兴趣的对象。
  • 可是,其它对象能够抛出PropertyVetoException异常来否决建议的修改。
  • 这种能力使得Bean能够根据运行时环境来进行不一样的操做。
  • 处理这种事件的类必须实现VetoableChangeListener接口。

持久性:

  • 持久性是保存Bean当前状态到非易失性存储器的能力,以及以后检索他们的能力,包括Bean的属性值和实例变量的值。
  • Java类库提供的对象串行化能力,能够用于为Bean提供持久化。
  • 串行化Bean:让Bean实现java.io.Serializable接口,只是一个简单的标记接口。
  • 实现后无需其它操做,使得Bean能够自动完成串行化。
  • 自动串行化还能进行继承。
  • 使用transient关键字能够阻止某个实例变量参与串行化。
  • 若是没有实现该接口,能够经过实现java.io.Externalizable等方式来自行提供串行化,不然容器態保存组件的配置信息。

定制器:

  • Bean开发者能够提供定制器,用于帮助其余开发者配置Bean。
  • 定制器能够提供一步步的指导,以完成再特定上下文中使用组件必须遵循的步骤。
  • 还能够提供在线文档。
  • 对于开发定制器,Bean开发者拥有很大的灵活性,能够根据市场对产品进行微调。

Java Bean API:

Java Bean功能是由java.beans包的一组类和接口提供的。

三十8、servlet

applet动态扩展Web浏览器功能;而servlet是在Web链接的服务器端执行的小程序,动态扩展了Web服务器的功能。

背景:

Web浏览器如何与服务器之间进行协做并最终为用户提供内容呢?

请求静态Web页面:

  • 用户在浏览器输入URL地址
  • 浏览器产生HTTP请求,发送到Web服务器
  • Web服务器将HTTP请求映射到特定文件
  • Web服务器在HTTP响应中,把文件返回到浏览器,响应中HTTP头指明了内容的类型
  • MIME(多用途Internet邮件扩展,Multipurpose Internet Mail Extension)用于指明内容类型。如,普通ASCII文本的MIME类型是text/plain,Web页面的HTML源码的MIME类型是text/html

请求动态内容:

  • Web早起,经过CGI(公共网关接口,Common Gateway Interface)与Web 服务器通讯,CGI容许单独的进程从HTTP请求读取数据,而后将数据写入HTTP响应,能够用各类语言实现CGI程序。
  • 可是CGI存在严重性能问题,每一个客户端请求都须要建立独立的进程和数据库链接;并且CGI不是平台独立的。
  • 出现了其它技术,servlet是其中之一。
    • servlet在Web服务器地址空间内执行,不须要建立单独进程来处理每一个客户端请求;
    • servlet是平台独立的,由Java编写;
    • 服务器上的Java安全管理器强制执行一套限制,以保护服务器上的资源;
    • servlet能够使用Java类库的所有功能

servelet的生命周期:

有3个方法控制servlet的生命周期:init()、service()、destroy(),每一个servlet都须要实现它们,而且特定的时间由服务器调用它们。

一个典型用户场景:

  • 用户在Web浏览器输入URL地址
  • 浏览器生成HTTP请求发送到对应的服务器
  • Web服务器接收到HTTP请求
  • Web服务器将请求映射到特定的servlet
  • servlet被动态检索并加载到服务器地址空间中
  • Web服务器调用servlet的init()方法,只有servlet第一次被加载到内存中才会调用该方法,向servlet传递初始化参数,以配置自身
  • Web服务器调用servlet的service()方法,以处理HTTP请求
  • servlet执行service方法时,会读取HTTP请求中的数据,而且根据需求计算出HTTP响应
  • servlet会保留在Web服务器的地址空间中,能处理从不一样客户端接收到的其它HTTP请求,为每一个请求调用service()方法
  • 最后服务器能够决定从内存写在servlet,调用destroy()方法,释放资源

servlet开发选项

为了建立servlet,须要访问servlet容器/服务器,经常使用的有Glassfish和Tomcat

使用Tomcat开发和建立servlet:

一、安装Tomcat

二、启动Tomcat

三、使用Tomcat下的servlet-api.jar包,编译写好的servlet代码java文件,生成class文件

四、把class文件放到Tomcat下并配置Tomcat的web.xml文件,让Tomcat能找到这个servlet

建立并运行一个servlet:

建立并编译servlet源码

将servlet类文件复制到正确的目录下,并添加servlet的名称和映射到正确的web.xml中

启动Tomcat

启动Web浏览器,请求这个servlet

源码编写:

 

 

 

常见问题

JDK、JRE、JVM

JVM:java virtual machine,Java虚拟机,Java代码编译出来的类文件,在Java虚拟机上运行

JRE:java runtime environment,Java运行时环境,包含JVM,以及Java程序运行时须要的库

JDK:java development kit,Java开发工具包,包括JRE,以及Java开发时须要的工具、库等

URI、URL、URN

URI:Uniform Resource Identifier,统一资源标志符,用来惟一的标识一个资源。

URL:Uniform Resource Locator,统一资源定位符。即URL能够用来标识一个资源,并且还指明了如何locate这个资源。

URN:Uniform Resource Name,统一资源命名。即经过名字来表示资源的。

URI指一个网络资源的标识符,有其格式;URL是URI的一种形式,包括协议、主机等信息,有其本身的格式要求;URN也是URI的一种形式,使用名称来表示该资源。

 

 

 

实际应用

下载历史JDK版本的方法

以前一直想下载JDK8的172版本,一直找不到下载地址

登陆甲骨文官网:https:/www.oracle.com/index.html,搜索jdk8 archive,点击进去便可下载JDK8全部版本的存档

 

JDK安装

下载

下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html

选择下载Java 8的JDK

根据系统选择对应安装包

下载后,安装直接下一步就可

安装完成可得2个文件夹

设置环境变量

目的有2个:一、为了在命令行中直接能够使用Java命令,而不须要跳转到Java文件夹里面才能使用;二、其它程序引用Java安装地址时,使用这个变量便可,不须要写绝对地址;而Java地址更改时,只要变量不变,这些程序也不须要更改地址。

一、计算机→属性→高级系统设置→高级→环境变量→系统变量→新建 JAVA_HOME 变量,变量值填写jdk的安装目录

二、系统变量→找到已存在的Path 变量→编辑→在变量值最后输入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

此步骤至关于为命令行增长了2个搜索java.exe程序的路径,因此当在命令行中执行java命令时,系统就能找对java.exe程序

三、 系统变量→新建 CLASSPATH 变量→变量值填写 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一点)

 

验证是否安装成功

开始→运行→输入cmd,回车→输入java -version

若是出现一下对应信息,表明安装成功

JDK、JRE、JVM的区别

JDK

JDK:Java Development Kit,Java 语言软件开发工具包。

一个工具包,能支持人类输入编程语言,并将其转化为机器语言,其中包含了JRE和JVM。

JRE

JRE:Java Runtime Environment,Java运行环境。

人类使用JDK开发好程序后,JRE提供程序的运行环境,能把程序针对不一样环境编译成能够运行的机器语言。JRE包含了JVM的标准实现。

JVM

JVM:Java Virtual Machine,Java虚拟机。

全部Java程序,都由JRE编译成JVM能认识的一种特定语言,在JVM上运行,JVM再经过与不一样操做系统,不一样环境的交互,进而在不一样的系统下。

2五、AWT介绍:使用窗口、图形和文本
2六、使用AWT控件、布局管理器和菜单
2七、图像
2八、并发使用工具
2九、流API
30、正则表达式和其它包
3一、Swing简介
3二、探究Swing
3三、Swing菜单简介
3四、JavaFX GUI编程简介诶
3五、探究JavaFX控件
3六、JavaFX菜单简介
相关文章
相关标签/搜索