本文篇幅较长,建议合理利用右上角目录进行查看(若是没有目录请刷新)。html
目的:为彻底了解Java,须要理解Java的诞生缘由、成型动力以及他继承的思想。java
计算机语言的创新与发展的缘由:适应环境和用途的变化;实现编程艺术的完善和提升。程序员
Java大量特性从C和C++继承过来。web
C语言前,BASIC、COBOL、FORTRAN这几种编程语言没有遵循结构化原则设计,依赖GOTO做为程序控制手段;Pascal虽是结构化语言,但不是针对高效率设计的,没法设计系统级代码。正则表达式
C语言出现的2个条件:软件需求加快,学术界在努力建立一种新的设计语言;计算机硬件普及,计算机再也不被锁起来,程序员能够随意使用计算机进行尝试。算法
C语言是一种功能强大、高效率、结构化的语言;并且他是程序员设计的,为程序员服务的语言。数据库
出现的缘由:更好地管理程序的复杂性。编程
改进:C++是在C#的基础上,增长了对面向对象(OOP)的支持,使程序员能理解和管理更大的程序。小程序
20世纪80年代末90年代初,万维网(World Wide Web)和因特网发展到了临界规模。设计模式
Java于1991年,由Sun公司构想出。
最初开发Java的推进力:对平台独立的语言的需求。
当时须要为一些电子设备(微波炉、遥控器等)的各类CPU开发程序,若是使用C或者C++须要对每一种CPU开发对应的编译器,因此须要一种可移植对平台独立的语言。
因特网成就Java:恰好这个时候因特网的飞速发展,也须要可移植的程序,Java的特性也适合于因特网的需求,使Java的关注点从消费电子产品转移到Internet。
一、为了吸引C/C++的程序员,Java继承了不少C/C++的特性,但Java不是为了替代它们,而是为了解决特定领域问题而出现的。
二、Java是专门针对程序员的语言,由于他的设计、测试、改进都是由程序员完成,扎根与程序员的需求,也为程序员开放了足够的权限。
Java影响了C#语言的发展,二者共享相同语法,支持分布式编程,使用类似的对象模型。
Internet推进了Java,Java也影响了Internet。
Java简化了Web编程,建立了新的网络程序类型applet,解决了一些Internet棘手问题如移植性和安全性。
applet是一种能够在Internet上传送的程序,能够在兼容Java的Web浏览器中自动运行。
applet扩展了网络空间自由流动的对象的范畴。这是一种动态的,自动运行的代码,由服务器端初始化,而后在客户端自动运行。
虽然这种动态的联网程序符合人们愿望,可是同时带来了严重的安全性和可移植性。
当下载这个自动执行的程序的时候,里面可能包含各类病毒或者恶意代码。
而Java将applet限定在Java的执行环境内,不容许访问计算机的其它部分来实现安全性。
applet会被下载到不一样的环境,不一样的系统中,如何实如今这些不一样的环境下的运行,下面将讲解。
解决安全性和可移植性的关键:字节码。
Java编译器输出的不是可执行代码,而是高度优化的指令集合。
字节码在Java运行时系统中执行,Java运行时系统也称为Java虚拟机(Java Virtual Machine,JVM),原始也称为字节码解释器。
Java横跨服务器/客户端:servlet是在服务器中执行的Java程序,像applet扩展了Web浏览器的功能同样,servlet扩展了Web服务器的功能。
servlet用于动态建立发送到客户端的内容,如servlet能够读取服务器数据库,而后整理为客户端想要的内容,发送到客户端;同时,servlet还提供了一些额外的优势,例如性能的提高。
可移植性:由于servlet是Java程序,他们被编译成字节码,由JVM执行,因此servlet能够用于不一样服务器环境,只要服务器支持JVM和servlet容器。
面向对象编程(Object-Oriented Programming,OOP)在Java中处于核心地位。
全部计算机程序都包含2个元素:代码、数据
使用抽象管理复杂性:非面向对象的编程方式,每每将对象分解为不一样的部分进行处理;而面向对象的编程方式,则是把对象做为一个总体,去使用这个对象。
层次化分类:如一台车,下面又能够分为驾驶系统、制动系统等,每层又能够继续细分。当咱们去使用这个车的对象时,则只须要了解各系统如何操做,而不须要知道这个系统里面由什么组成
对变化的支持:面向对象的方式犹如人类理解事物同样;每每事物会不断变化,例如某一部分进行改变;那么面向对象的程序也能支持这些变化,能够优美地废除或者替换旧系统中的一些部分。
封装:将代码以及其操做的数据绑定在一齐的机制。能够想象为一个保护性的盒子,只容许外部经过盒子提供的通道进行访问和操做,而不容许随意访问盒子里面的代码和数据。
封装的基础是类:类,是一些对象共享的一种结构和行为(数据和代码)。使用类建立对象,相似使用模具生产零件,这些对象也称为类的实例。
变量和方法:类里面能够定义变量和方法,称为成员变量(或实例变量)和成员方法(或方法)。
公有/私有:类的变量或方法能够设置为公有或私有,公有的表示外部用户能够知道的内容,私有的表示只有类的成员才能访问。
继承:是一个对象得到另外一个对象的属性的过程,继承支持了层次化分类的概念。
例如定义了一个哺乳类动物,又定义了下一层的一个类叫犬类,咱们定义犬类继承了哺乳类,那么就表明犬类有哺乳类的全部属性和特征(变量和方法)。
多态(多种形态):容许将一个接口用于一类通用动做。
多态是为了下降复杂性。例如一个对象有同一个行为,可是根据数据不一样有不一样作法的时候,使用相同的接口来指定这个行为,而自动根据对应的参数,会执行对应的实际代码。
经过这3个原则,能够设计出健壮性强、方便维护、适应变化的系统级代码。
下面例子应在安装并配置好JDK 8下使用
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
运行后,会显示“测试”,表明程序运行成功
Java会找到程序多个类中的main()方法启动程序,注意大小写,没有找到会报错
int num;
if(num < 100)System.out.println("yes");
用{}表示逻辑单元
if(num<100){ System.out.println("yes1"); System.out.println("yes2"); }
在编译器完成编译前,会检查全部表达式和参数,确保类型是兼容的。
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不容许使用。
基本算数运算符+ - * /
注意整数类型使用除法,结果会截掉小数部分
求模运算符%
求余数,能够用于整数或小数
算数与赋值符合运算符+= -= *= /=
至关于运算后再赋值
自增与自减运算符++ --
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);
if(a=1){ b=1; } else if(a=2){ b=2; } else{ b=3; }
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(n>0){ System.out.println(n); n--; } i=100; j=200; while(++i<--j);//用;表示空语句
循环体至少执行一次
do{ System.out.println(n); n--; }while(n>0)
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风格在不一样的编程语言中都有实现,是一种很受程序员喜欢的风格
在Java中,是经过for语句实现的,能够对集合类变量进行循环
int nums[] = {1,2,3,4,5} int sum = 0; for(int x:nums){ sum+=x; }
用于终止当前所在的最近一个循环
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的循环 } }
能够使用标签,终止语句所在的全部嵌套循环中的其中一个
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后面的代码将不会执行
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的一次迭代 } }
能够使用标签,终止语句所在的全部嵌套迭代中的其中一个
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的一次迭代 } }
显式地从方法返回,把程序的执行控制返回到发放的调用者处
//类的基本形式 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会自动管理,大多数状况不须要人为编程。
为类添加这个方法,能够在类的对象被Java回收的时候执行方法内的代码。
protected void finalize() { //记录回收时间等自定义方法 }
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参数的方法 } }
能够将对象做为参数传递给方法
能够讲对象做为参数的返回值返回
方法能够调用本身实现递归算法
用于声明类自己的成员,而不是对象的成员
限制:
一、只能直接调用其它静态方法
二、只能直接访问静态数据
三、不能引用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 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(); } }
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");
限制:
一、一个方法最多只有一个可变长度参数
二、可变长度参数必须放到最后
class VarArgs{ static void vaTest(int ... v){ for(int x : v){ System.out.println(x); } } }
一个类能够继承另一个类,被继承的类叫超类,继承别人的类叫子类
继承:
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(); } }
用法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类型修饰符修饰的类
一、可以使用final关键字阻止重写
二、可以使用final关键字修饰类,防止类继承
Object类是全部其它类的超类
Object类型的引用变量能够应用其它全部类
Object类型能够引用数组,由于数组也是做为类来实现的
因此全部对象均可以使用Object的方法
若是全部类都放一块儿开发,方便易记的类名很快用完,也很容易出现协做时命名冲突的问题。
包是Java提供的一种命名机制,同时也是一种可见性控制机制。
Java使用文件系统目录存储包,包名必须和目录路径一致,包括大小写
//定义包名,写在Java源文件中的第一条语句 package pkg; //层次化 package java.awt.img;
Java运行时怎么找到这些包呢?
package MyPack;
3种方式:
而对【非嵌套类】只有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); }
class Client implements Callback{ public void callback(int p){ System.out.println(p); } }
class TestIface{ public static void main(String args[]){ //使用接口调用方法 Callback c = new Client(); //调用的方法是来自对象,而不是类型变量 c.callback(42); } }
abstract class Incomplete implements Callback{ void show(){ System.out.println("Good"); } }
建立一个包含变量的接口,实现这个接口的类至关于把这些这些变量看成常量导入到类的命名控件下。
interface SharedConstants{ int NO = 0; int YES = 1; int NULL = 2; }
这种用法有争议,仅做介绍
接口能够继承,实现一个子接口,必须实现这个接口的继承链上全部接口的全部方法。
【JDK8】才出现
默认方法也称扩展方法
能够为接口的方法提供默认实现
动机:
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();
注意:
一、实现接口的类或子接口不会继承接口中的静态方法。
处理程序运行时的非正常状态,即运行时错误。
Java会在出现异常时,抛出一个异常对象。
全部异常对象都是Throwable的子类
Exception:用于用户程序应当捕获的异常,或者自定义的异常
RuntimeException:程序自动定义
Error:通常指运行时环境出现的错误
若是出现异常且未捕获,程序会终止,并输出堆栈信息,能够根据堆栈信息帮助查找问题。
程序处理异常,会终止程序。
咱们本身处理异常,一能够修复错误,二能够避免终止程序。
try{ do(); }catch(Exception1 e){ System.out.println(e);//输出异常信息 catchDo(); }catch(Exception2 e){//能够多个catch语句 catchDo(); }
显式抛出异常
throw ThrowableInstance;
这个异常必须是Throwable或其子类类型的对象。
除了Error和RuntimeException及其子类类型的异常外,若是方法有其它类型的异常,则须要为方法标明这些异常。
目的是让方法的调用者知道此方法全部异常以作好准备措施。
public void do() throws MyException{ throw new MyException("test"); }
可选加载try{}catch{}后,不管是否抛出异常,都会在try{}catch{}后执行此代码
try{ do(); }catch(Exception1 e){ System.out.println(e);//输出异常信息 catchDo(); }finally{ finallyDo(); }
未经检查(编译器不检查这些异常是否使用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个构造函数的遗留异常类设置缘由
一、带资源的try语句
当try语句中使用资源时,再也不须要时资源能自动释放(如文件),后面解释
二、多重捕获
容许同一个catch子句同时捕获多个异常
catch(Exception1 | Exception2 e)
每一个多重捕获参数都被隐式声明为final,不能从新赋值
三、最后从新抛出/更精确地从新抛出(不是很理解,暂时不理)
程序会对从新抛出的异常类型进行限制,只能从新抛出知足如下条件的经检查的异常:由关联的try代码块抛出,没有被前面的catch子句处理过,而且是参数的子类型或超类型。
一样catch参数隐式声明为final,不能从新赋值
多任务:
Java线程模型:
线程的状态:
线程优先级:
一些整数,用于决定什么时候从一个运行的线程切换到下一个线程,称为上下文切换
意思应该是这样,根据CPU时钟周期,空余时间能够用来运行线程;当线程过多,而有线程阻塞时,何时切换到下一个进程呢:
同步:
消息传递:
Thread类和Runable接口:
Java的多线程系统基于Thread类、Thead类的方法以及伴随接口Runable而构建
主线程:
Java启动就会运行一个线程,称为主线程。
很重要:
调用主线程
2种方法:
实现Runable接口
扩展Thread类
一样的,扩展Thread类,重写run()方法,而后调用start()方法类开始新线程
为何有2种方式,哪一种好?
差异不大,一个是在于实现接口,一个是扩展重写类。
能够使用接口,这样能够使这个类能够扩展其它类。
建立多个线程
isAlive()和join()方法
好比主线程但愿等全部子线程执行完成再退出
isAlive()判断线程是否仍在运行
可是通常经过join方法来等待线程结束
再某个线程调用其它线程的join方法,会等待该线程终止。
也能够配置最长等待时间。
线程优先级
一、影响线程获得CPU时间的因素:优先级、系统多任务的方式等
在抢占式多任务环境下,高优先级的线程会替代掉低优先级的线程
在非抢占式多任务环境下,在运行中线程正常运行状况下(未休眠,未放弃控制权等),其它线程只有在运行中线程阻塞状态,如I/O等待等,致使线程挂起,才有机会运行
因此为了平滑多个线程的执行,最好常常释放控制权,使其它线程有机会运行。
调用setPriority方法设置线程优先级,范围1~10,默认值5
使用Java实现可预测,跨平台行为的最安全方法是使用资源放弃CPU控制权的线程。
同步
当多个线程须要访问共享资源时,他们须要用某种方法确保每次只有1个线程使用资源。
实现这个目的的过程称为同步。
同步使用监视器的概念实现,监视器做为互斥锁,一个时刻只有一个线程能够进入监视器,而其余试图进入监视器的线程会被挂起,知道上一个线程退出监视器。
2种方法
使用同步方法:
Java中,全部对象都有和自身关联的隐式监视器。要进入对象的监视器,只须要调用synchronized关键字修饰过的方法。
当调用对象的一个同步方法,线程就会进入对象的监视器;其它线程想要调用这个或其余同步方法,因为进入不了监视器,因此会被挂起等待;知道监视器种的线程退出,把对象的控制权交给下一个等待线程。
使用同步语句:
线程间通讯:
I/O:输入输出
流:
2种类型的流:
通常原则:在合适的状况下,应该更新代码,使用字符流替代字节流。
不过:在底层,全部I/O最终仍是面向字节的。
2个类层次:
InputStream和OutputStream最重要2个方法是read()和write(),子类须要实现这2个方法
2个类层次:
Reader和Writer最重要2个方法是read()和write(),子类须要实现这2个方法
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 } } }
主要是FileInputStream、FileOutputStream、AutoCloseable接口
一种Java程序,能够在Internet服务器上访问,传输,自动安装并做为Web文件的一部分运行的一类小程序。
transient修饰符:
volatile修饰符:
instanceof:
strictfp:
native:
assert:
import static:
this():
紧凑API配置文件:
目的:为了解决不一样类型的对象须要运行同一算法的需求
泛型:参数化类型,能够使用参数指定所操做数据的类型
之前:要实现这个需求,则使用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,表明不能建立泛型异常类
JDK8新增功能
增长了新的语法元素
使API库增长了新的功能,包括多核环境的并行处理功能(特别是for-each操做)变得容易,以及支持对数据执行管道操做的新的流API
催生了新的Java功能,包括默认方法以及方法引用
lambda表达式:
函数式接口:
()->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语句建立一个匿名实现。
方法引用:若是咱们在其余类中,已有方法恰好实现了这个接口,那么咱们能够直接引用这个方法,传入给这个函数式接口参数
原理:方法引用会建立函数式接口的一个实例。
// 静态方法引用 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,提供了预约义的函数式接口
String、StringBuffer、StringBuilder
StringBuffer、StringBuilder用于能够修改的字符串
StringBuilder,StringBuilder不是同步的,因此不是线程安全,优点在于性能更高
若是字符串被多个线程修改,没有使用其它同步措施的话,须要使用StringBuffer
暂略,大部分是接口和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); } }
集合框架以前:Java提供了特定的类以存储和管理对象组,如Dictionary、Vector、Stack和Properties。
问题:缺乏集中、统一的主体,不易扩展,不易改造。
集合框架的目标:
为了知足这些目标,Java提供了:
新的JDK为集合框架带来的改变:
除了集合接口外,集合还使用Comparator、RandomAccess、Iterator以及ListIterator接口,这些后面探讨。JDK8开始,还使用Spliterator接口。
Collection接口是集合框架的基础,全部定义集合的类都必须实现这个接口,是一个泛型接口。
interface Collection<E> //E是存储对象的类型
Collection扩展了Iterable接口,因此全部集合均可以使用for-each风格的for循环
Collection声明了全部集合将拥有的核心方法
异常:
核心方法总结:添加、删除、检查是否包含、获取迭代器、转换数组、获取流
扩展Collection,并声明了用来存储一连串元素的集合的行为。
能够使用从0开始的索引,经过元素位置插入或访问元素。
能够包含重复元素
interface List<E> //E是存储对象的类型
Set接口定义了组,扩展了Collection接口,声明了集合中不容许有重复元素的组行为
没有定义本身的其它方法,添加剧复元素的时候,add()方法返回false
interface Set<E> //E是存储对象的类型
SortedSet扩展了Set接口,并声明以升序进行排序的组行为。
interface SortedSet<E> //E是存储对象的类型
NavigableSet接口扩展了SortedSet接口,而且声明了支持基于最接近匹配原则检索元素的集合行为
interface NavigableSet<E> //E是存储对象的类型
Queue接口扩展了Collection接口,声明了队列的行为,队列一般是先进先出队列,但也有其余准则的队列类型。
interface Queue<E> //E是存储对象的类型
Deque接口扩展了Queue接口,而且声明了双端队列行为,既能够先进先出,也能够后进先出
interface Deque<E> //E是存储对象的类型
集合接口的标准实现
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类扩展了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类扩展了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扩展了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扩展了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扩展了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扩展了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扩展了AbstractSet并实现了Set接口,专门用于枚举类型的元素。
class EnumSet<E extends Enum<E>> //E是存储对象的类型
EnumSet类没有定义构造函数,而是使用工厂方法来建立对象
若是但愿遍历集合中的元素,方法之一是使用迭代器。
迭代器是实现了Iterator或ListIterator接口的对象。
Iterator接口容许遍历集合,获取或移除元素。
ListIterator接口扩展了Iterator接口,容许双向遍历列表,而且容许修改元素。
interface Iterator<E> //E是存储对象的类型 interface ListIterator<E> //E是存储对象的类型
获取迭代器:每一个集合类都提供了iterator()方法,方法返回一个指向集合开头的迭代器
具体步骤:
对于实现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 } }
JDK8新增一种叫splitertor的迭代器,由Spliterator接口定义。
Spliterator用于循环遍历元素序列。
它提供的方法远比Iterator或ListIterator多,最重要的一点是它支持并行迭代序列的一部分。
即便用不到并行编程,也能够使用Spliterator,其中一个缘由是它把hasNext和next操做合并到一个方法中,从而提供了效率
interface Spliterator<T> //T是被迭代元素的类型
暂略,须要lambda表达式知识
RandomAccess接口不包括成员。然而经过实现这个接口,能够代表集合支持高效地随机访问其中的元素。尽管集合可能支持随机访问,可是可能没有这么高效。
经过检查RandomAccess接口,客户端代码能够在运行时肯定集合是否适合特定类型的随机访问操做——特别是当将他们应用于大的集合时(能够使用instance of来判断类是否实现了这个接口)。
ArrayList和遗留的Vector类实现了RandomAccess接口。
映射是存储键和值之间关系(键值对)的对象。
键和值都是对象,键必须惟一,但值能够重复。
某些映射能够接收null键和null值,其它不能。
映射没有实现Iterable接口,因此不能使用for-each风格的for循环,也不能获取迭代器。
可是能够获取映射的集合视图,集合视图容许使用for循环和迭代器。
Map接口将惟一键映射到值。给定键和值就能够在Map对象中存储;存储后能够使用键来检索值。
interface Map<K,V>// K是键的类型,V是值的类型。
映射围绕2个基本方法:get()、put()
使用entrySet()方法,返回一个Set对象,包含映射中元素。
使用keySet()方法,返回一个Set对象,做为键的集合视图。
使用values()方法,返回一个Set对象,做为值的集合视图。
修改一个集合会影响其余集合,由于集合的数据是引用映射内的数据。
集合视图是将映射集成到集合框架中的手段。
SortedMap接口扩展了Map接口,确保条目以键的升序保存。
interface SortedMap<K,V>// K为键类型,V为值类型
有序映射支持很是高效的子映射操做,如headMap()、tailMap()或subMap()方法。
NavigableMap接口扩展了SortedMap接口,支持基于最接近匹配原则的条目检索行为,即支持检索与给定的一个或多个键最相匹配的条目。
interface NavigableMap<K,V>
Map.Entry接口提供了操做映射条目的功能。
Map接口声明的entrySet()方法返回一个包含映射条目的Set对象。
组的全部元素都是Map.Entry对象。
interface Map.Entry<K,V>
另外JDK8添加了2个静态方法:comparingByKey()和comparingByValue()。
前者返回根据键比较条目的Comparator对象,后者返回根据值比较条目的Comparator对象。
有几个类实现了映射接口
AbstractMap是全部具体映射实现的超类。
WeakHasMap实现了使用“弱键”的映射,键不在使用时能够被垃圾回收,这里不讨论。
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扩展了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扩展了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扩展了AbstractMap类并实现了Map接口。除了当比较元素时使用引用相等性外,其它方面和HashMap相似
class IdentityHasMap<k,V>
API文档明确指出IdentityHashMap不用于通用目的
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类定义的每一个方法
待补充
早期的java.util包没有包含集合框架,而是定义了几个类和一个接口,用来提供存储对象方法的专业方法。
注意现代集合类都不是同步的,可是全部遗留类都是同步的,固然能够使用Collection提供的算法很容易实现同步。
包括
流的概念:流是数据的渠道。
流表明一个对象序列。
流操做数据源,如数组或集合。
流自己不存储数据,只是移动数据,移动过程当中可能对数据执行过滤、排序或其余操做。
通常流操做不会修改数据源,而是建立一个新的流,包含过滤、排序或其余操做后的结果。
流接口
终端操做:会消费流,被消费后,流不能重用。
中间操做:会产生另外一个流。中间操做不是当即发生,是在新流上执行完终端操做后,中间操做才会发生,称为延迟行为,能让流API更加高效地执行。
另外一个关键点:
无状态:独立于其余元素处理每一个元素。如过滤,filter()
有状态:某个元素处理以来其余元素。如排序,sorted()
注意,并行处理流时,无状态和有状态区别尤为重要,由于有状态操做可能须要几回处理才能完成。
Stream操做是对象引用,因此增长了如下几个接口支持处理基本类型流,都扩展了BaseStream
DoubleStream
IntStream
LongStream
重点关注Stream,基本类型流处理上基本相同
获取流:
一、COllection接口被扩展,包含2个获取集合流的方法
补充代码
缩减操做
基于任意条件,从流中返回一个值。全部缩减操做都是终端操做。
这个是Java的组件架构,经过必定的规范保证组件能够重用和互操做;可是有Spring框架后,Spring框架中的Bean是基于POJO的,因此Java Bean的意义不大了。(我的观点)
软件行业一直在探索,以实现基于组件方式的可重用和互操做性。
Java Bean是一种组件架构,但愿开发软件时,能够利用这些软件组件来构建复杂的系统。
例如电子行业的电阻器、电容器、传感器等。
那么设计这能够选择组件,理解他们的功能,并把他们集成到应用程序中。
Java Bean:
Java语言书写,而且遵照JavaBean API规范
软件组件,被设计成能够在不一样环境下重用。
功能能够是获取库存值,又或者预测股票走势。
优点:
内省:
2种方式指示Bean应当暴露哪些属性、事件和方法:
属性的设计模式:
简单属性:
补充代码
索引属性:
补充代码
事件的设计模式
补充代码
方法与设计模式:
BeanInfo接口:
绑定属性与约束属性:
具备绑定属性的Bean:
具备约束属性的Bean:
持久性:
定制器:
Java Bean API:
Java Bean功能是由java.beans包的一组类和接口提供的。
applet动态扩展Web浏览器功能;而servlet是在Web链接的服务器端执行的小程序,动态扩展了Web服务器的功能。
背景:
Web浏览器如何与服务器之间进行协做并最终为用户提供内容呢?
请求静态Web页面:
请求动态内容:
servelet的生命周期:
有3个方法控制servlet的生命周期:init()、service()、destroy(),每一个servlet都须要实现它们,而且特定的时间由服务器调用它们。
一个典型用户场景:
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
源码编写:
JVM:java virtual machine,Java虚拟机,Java代码编译出来的类文件,在Java虚拟机上运行
JRE:java runtime environment,Java运行时环境,包含JVM,以及Java程序运行时须要的库
JDK:java development kit,Java开发工具包,包括JRE,以及Java开发时须要的工具、库等
URI:Uniform Resource Identifier,统一资源标志符,用来惟一的标识一个资源。
URL:Uniform Resource Locator,统一资源定位符。即URL能够用来标识一个资源,并且还指明了如何locate这个资源。
URN:Uniform Resource Name,统一资源命名。即经过名字来表示资源的。
URI指一个网络资源的标识符,有其格式;URL是URI的一种形式,包括协议、主机等信息,有其本身的格式要求;URN也是URI的一种形式,使用名称来表示该资源。
以前一直想下载JDK8的172版本,一直找不到下载地址
登陆甲骨文官网:https:/www.oracle.com/index.html,搜索jdk8 archive,点击进去便可下载JDK8全部版本的存档
下载地址: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:Java Development Kit,Java 语言软件开发工具包。
一个工具包,能支持人类输入编程语言,并将其转化为机器语言,其中包含了JRE和JVM。
JRE:Java Runtime Environment,Java运行环境。
人类使用JDK开发好程序后,JRE提供程序的运行环境,能把程序针对不一样环境编译成能够运行的机器语言。JRE包含了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菜单简介 |