javaSE个人总结

总结

一.

1.       什么是编程?

编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程。

为了是计算机能够理解人的意图,人类就必须将需解决的问题的思路、方法、和手段通过计算机能够理解的形式告诉计算机,使得计算机能够根据人的指令一步一步地区工作,完成某种特定的任务。这种人和计算机之间交流的过程就是编程。

2.Java语言概述,历史、特点

是SUN(Stanford University Network,斯坦福大学网络公司)1995年推出的一门高级语言。是一种面向Internet的编程语言。

随着java技术在web方面的不断成熟,已经成为web应用程序的首选开发语言。是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。

Java5.0之后的三大技术框架

J2EE(java 2 platform enterprise edition)企业版

在jdk5.0版本之后称为javaee,是为开发企业环境下的应用程序提供的一套解决方案。该技术体系中包含的技术如servlet jsp等,主要是针对于web应用程序开发。石川智播客就业班和黑马训练营的只要学习内容之一。

J2se(java 2 platform standard edition)标准版

在jdk5.0版本之后称为javase,这是在基础阶段主要学习的内容,也是java的基础,以后不管充android开发或者是物联网+云计算的开发,都是建立在jse基础上的,一次该技术是java的最核心技术,是传智播客基础班的主要上课内容。

J2ME(Java 2 Plaformt Micro Edition)小型版

在jdk5.0版本之后称为JAVAME,该技术多应用于一些电子产品的嵌入式开发,以前在手机开发上应用的也比较多,但是随着智能手机的发展,现在手机应用程序(比如Android程序)的开发已经不再使用该技术。

3.什么是跨平台性?原理是什么?jvm

   所谓跨平台性,是指jav语言编写的程序,一次编译后,可以在多个系统平台上运行。

实现原理:java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序。(注意:不是能在所有的平台上运行,关键是该平台是否能够安装相应的虚拟机)。

我的总结:

4.jre和jdk的区别

Jre:(java runtime environment),java运行环境。包括java虚拟机(jvm  java virtual machine )和java程序所需的核心类库等。如果想要运行一个开发好的java程序,计算机值要安装jre即可。

Jdk:(java development kit java )开发工具包,jdk是提供SEIjava开发人员的,其中包含了java的开发工具,也包括了jre,所以安装了jdk,就不用安装jre了;

其中的开发工具:编译工具:javac.exe

                打包工具:jar.exe

简单而言:使用jdk开发完成的java程序,交给fre去运行

5.java虚拟机

Java virtual macthine ,简称jvm

它是运行所有的java程序的抽象的计算机,是java语言的运行环境,它是java最具吸引力的特性之一,jvm读取并处理编译通过的与平台无关的字节码(class)文件。

Java编译器针对jvm产生class文件,因此是独立于平台的;

Java解释器负责将jvm的代码在特定的平台上运行;

Java虚拟机是不跨平台的;

6.java程序运行机制

编译:javac文件名.文件名后缀名

运行:java 类名

7.java注意的地方

 Java语言拼写上严格区分大小写

一个java源文件可以定义多个java类,但其中最多只能有一个类被定义成public类;

若源文件中包含了public类,源文件必须和该public类同名;

一个源文件中包含了很多个java类时,编译后不会产生很多份字节码文件,即每个类都会生成一份单独的class文件,而且,字节码文件名和其对应的类名相同;

总结:一个java源文件中只定义一个类,不同的类使用不同的源文件定义;

将每个源文件中单独定义的类都定义成public的

保持java源文件的主文件名与源文件的类名一致;

8.java语法格式

任何一种语言都有自己的语法规则。Java也一样,既然是规则,那么知道其是如何使用就可以了。

代码都定义在类中,类有class来定义,区分public class和class

Java中的标识符和关键字:

注释:

Main方法的作用:

程序的入口,保证程序的独立运行,被jvm调用

9.代码注释:单行//   多行/* */    文档注释/***/

单行注释//后到本行结束的所有字符会被编译器忽略

多行注释/*  */之间的所有字符会被编译器忽略

文档注释/***/之间的所有字符会被编译器忽略,java特有的,用于生成文档

10.java中的标识符

可简单理解为:在java程序中为了增强阅读性而自定义的名称,如:类名、方法名、变量名等

命名规则:(1)有字母(可以是中文,外文)、下划线、$组成,不能以数字开头

(2)大小写敏感

(3)不能使用java中的关键字和保留字

(4)不能用api中的类名作为自己的类名

11.java中的变量和常量

变量的概念:占据着内存的某一个区域,该区域有自己的名称(变量名)和类型(数据类型)

            该区域的数据可以在同一类型范围内不断变化

为什么要定义变量:用来不断地存放同一类型的常量,并可以重复使用;

使用变量注意:变量的作用范围和初始化值;

定义变量的格式:

   数据类型   变量名   =初始化值;

注意:格式是固定的;

作用范围:从定义开始到定义它的代码块结束;同一个范围内,不允许多个局部变量命名冲突

12:java中局部变量和成员变量:

局部变量:是声明在类的方法体中的变量,局部变量使用前必须初始化值;局部变量没有默认初始化值;局部变量的作用域是从定义开始到定义它的代码块结束;

成员变量:在方法体外,类体内声明的变量,又称字段(field)或全局变量;(其实java中没有全局变量,由于java是面向对象语言,所有变量都是类成员)

成员变量的作用域是在整个类中;

13.基本数据类型

在数据类型中,最常用的也是最基础的数据类型,被称为基本数据类型。可以使用这些类型的值来代表一些简单的状态;

Java语言的基本数据类型总共有4类,8种;

整数型:byte字节型、short短整型、int整形、long长整型

小数型:float单精度浮点型、double双精度浮点型

字符型:char字符型

布尔型:boolean布尔型

定点类型:整数型是一类代表整数值的类型。当需要代表一个整数的值时,可以根据需要从四种类型中挑选合适的,若没有特殊要求,一般选用int型,4中整数类型的主要区别主要在每个数据内存中 占用的空间大小和代表的数值的范围;

浮点类型:小数型是一类代表小数值的类型。当需要代表一个小数的值时,可以根据需要从两种类型中挑选合适的,若没有特殊要求,一般选择double型;

有于小数的存储方式和整数不同,所以小数都有一定的精度,所以在计算机中运算时不够精确。根据精度和存储区间的不同,设计了两种小数类型;

单精度浮点型:float,占用4个字节空间

双精度浮点型:double,占用8个字节空间

字符型:字符型代表特定的某个字符,计算机中都是以字符集的形式来保存字符的,所以字符型的值实际只是字符集中的编号,而不是实际代表的字符,有计算机完成从编号转成对应的字符的工作,java语言为了更加方便国际化,使用Unicode字符集作为默认的字符集,该字符集包含各种语言中常见的字符。在程序代码中,字符使用一对单引号加上需要表达大字符来标识,也可以用字符编码即一个非负整数进行表示,char类型占用2个字节的空间。

布尔型:代表逻辑中的成立和不成立,java语言中使用关键字true代表成立,false代表不成立,布尔型是存储逻辑值的类型,其实很多程序中都有逻辑值的概念,java把逻辑的值用布尔型来表达;布尔型占用1个字节的空间。

14.基本数据类型向上转换和向下转换

向上转换:整数,字符型,浮点型的数据在混合运算中相互转换,转换时遵循以下原则:容量小的类型可以自动转换成容量大的数据类型(也叫隐式转换);

Byte,short,char----int---long---float----double

Byte,short,char之间不会相互转换,他们在计算时首先会转换成int类型。

Boolean类型不可以转换成其他基本数据类型。

向下转换:整数,字符型,浮点型的数据在混合运算中相互转换,转换时遵循以下原则:

容量大的类型转换成容量大的类型必须进行强转(也叫显式类型转换)

15.java的运算符

运算符时一种特殊的符号,用以表示数据的运算、赋值和比较等。

分为:算术运算符:+ - * / %

      赋值关系符:=  +=  -=  *=  /=  %=

关系运算符:<  >  <=  >=   !=

条件运算符:&  &&  |  ||  !  ^

位运算符:&  |  ^  ~  <<  >>  <<<  >>>

总结:& 和&& :但与时,两边都参与运算,双与时,若左边为真,右边参与运算;若左边为假,右边不参与运算;

      | 和||  :单或时,两边都参与运算;

              双或时,若左边为真,右边不参与运算;

      ^:当左右都相同时,为false;当左右不同时,为真;

16.表达式和三目运算符

   是由数字、运算符、数字分组符号(括号)等以能求得数值的有意义排列的序列;

  表达式的类型和值:对表达式中的操作数进行运算得到的结果是表达式的值;

      表达式的数据类型即为表达式的类型;

  表达式的运算顺序:应按照运算符的优先级从高到低的顺序进行;

  优先级相同的运算符按照事先约定的结合方向进行。

  三目运算符的语法格式:

      X?y:z;

     其中,x为boolean类型表达式,先计算x的值,若为true,则整个三目运算符的结果是表达式y的值,否则就是z的值。

17.流程控制语句

  顺序结构  分支结构    循环结构    控制循环结构

顺序结构:如果代码里没有流程控制,程序是至上而下逐行执行的,一行语句执行完后继续执行下一行语句,直到程序结束。

If语句:

   基本语法:if(表达式){方法体}else if(表达式){方法体}else{方法体}

   三种格式:

(1)       if(条件表达式){执行语句;}

(2)       if(条件表达式){执行语句;}else{执行语句;}

(3)       if(条件表达式){执行语句;}else if(条件表达式){执行语句;}……else{执行语句;}

switch控制语句:

  格式:

   Switch(表达式)

{

       case表达式可能的结果1:

        执行语句;

    break;

   case表达式可能的结果2:

     执行语句;

   break;

   ……

   default:

      执行语句;

      break;

}  

注意:case与default之间没有顺序。

     结束switch语句的两种方法:遇到break,switch语句执行结束。   如果匹配的case或者default没有对应的default,那么程序会从第一次匹配的case语句开始继续向下执行,运行可以运行的语句,直到遇到break或switch结束为止。——switch语句的穿透性

Switch语句只能使用byte、char、short、int、四种基本类型以及它们的包装类和枚举18.三大循环结构

用于处理需要重复执行的操作;

根据判断条件的成立与否,决定程段落的执行次数,这个程序段落被称为循环体;

While   事先不知道循环执行多少次

do while  实现不知道执行多少次,至少执行一次(限制性一次,在进行判断)

for    需要知道循环次数

while格式

while(条件表达式值为true)

{

       执行语句;

}

do while语句

格式:

do

{

       执行语句;

}

while(条件表达式为true);

循环里的条件表达式不能直接写false或直接写结果为false的表达式,不过可以使用变量来传递false值。

for循环结构

格式:

for(初始化表达式(1);循环条件表达式(2);循环后的操作表达式(3))

{

       执行语句;(4)

}

执行顺序:(1)-(2)--(4)-(3)--(2)--(4)---(3)

备注:(1)。for循环里的3个表达式的顺序,初始化表达式只读一次,判断循环条件,为真就执行循环体,然后再执行循环后的操作表达式,接着继续判断循环条件,重复找个过程,直到条件不满足为止。

(2)while与for可以互换,区别在于for为了循环而定义的变量在for循环结束后就在内存中释放了,而while循环使用的变量在循环结束后还可以继续使用。

(3)最简单无限循环格式:while(true),for ( ; ; ),无限循环存在的原因是并不知道循环多少次,而是根据某些条件来控制循环。

19.嵌套循环与流程控制

嵌套循环:循环里套循环;

假设外循环的循环次数是m次,内循环的此数是n次,那么内循环的循环次数需要m*n次

流程控制

break语句、continue 语句

break  终止该层循环

continue 跳过该层循环

注意:(1)若这两个语句离开应用范围,存在是没有意义的;

(2)这两个语句后面都不能有语句,因为执行不到;

(3)continue语句是跳出本次循环,继续下次循环;

(4)标签的出现,可以让这两个语句作用于指定的循环;

二.方法与数组

  方法是一组为了实现特定功能的代码块的集合,方法在语法上的功能主要有两种:

(1)结构代码块

     将代码按照功能进行组织,使代码的结构比较清晰,容易阅读和修改,也就是程序的可维护性强。

(2)减少代码重复

  一个固定的功能,可能会在程序中多次使用,在使用时只需要调用写好的方法,而不用重复书写对应的功能的代码。

方法在书写时要注意几点:

(1)       逻辑严谨

方法实现;一个完整的功能,所以在书写时要考虑到各种可能的情况,并对每种情况作出恰当的处理。

(2)       通用性强

方法实现的是一种功能,在实际实现时,可以根据需要,使方法具备一定的通用性,除非必要,否则不用写专用的方法。在java语言中,恰当的使用方法,将使程序更加优雅,便于阅读和使用。

方法就是一段可重复使用的代码段,程序中完成独立的功能的一段代码的集合。

2.       java中方法的格式

[修饰符]  返回值类型  方法名 ([参数类型  形式参数1,参数类型  形式参数2,……])

{

        执行语句;[return  返回值;]

}

参数列表(参数的类型,参数的个数,参数的顺序)

3.方法里的属性

访问控制符:访问控制符限定方法的可见范围,或者说是方法被调用的范围。方法的访问控制符有四种,按可见范围从大到小依次是:public 、protected  、无访问控制符 、private,无访问控制符不书写关键字即可。

形式参数:在方法被调用时用于接收外界输入的数据。

实参:调用方法时实际传给方法的数据。

返回值:方法在执行完后返还给调用它的环境的数据。

返回值类型:实现约定好返回指的数据类型,如无返回值,必须给出返回值类型,void

方法签名:方法名和方法的参数列表();

Java语言中调用方法:对象名.方法名(实参列表)。

实参的数目、数据类型和次序必须和所调用方法声明的形参列表匹配。

return  语句终止方法的运行并指定要返回的数据。

4.方法特点

   它可以实现独立的功能;

   必须定义在类里面;

   它只有被调用才能执行;

   它可以被重复使用;

方法结束后方法里的对象失去引用。

定义一个功能,并通过方法体现出来:

(1)       明确该功能运算后的结果,明确返回值类型;

(2)       明确在实现该功能过程中是否有未知内容参与运算,确定参数列表;

5.什么是方法的重载(overload)

  在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或参数类型或参数顺序不同即可。

存在的原因:

     屏蔽了一个对象的同一类方法由于参数不同所造成的差异。

特点:

与返回值类型无关,只看参数列表。

6.可变参数

  从java5开始出现了可变参数,这是对java方法及数组的扩展。

方法中可以接受的参数不再是固定的个数的,而是随着具体需求传递的多少来决定的。

 定义格式:返回值类型  方法名(参数类型…形式参数){}

可变参数的特点:

   只能出现在参数列表的最后;

   … 位于变量类型和变量名之间,前后无空格都可以;

   调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中,以数组的形式访问可变参数;

7.数组简介:

数组是java语言中内置的一种基本数据存储结构,通俗的理解,就是一组数的集合,目的是用来一次存储多个数据。数组是程序中实现很多算法的基础,可以在一定程度上简化代码的书写。

备注:(1)数组的好处:数组中的每个元素都有编号,编号从0开始,并且依次递增,方便操作这些元素;

(2)使用java数组,必须先声明数组,再给该数组分配内存;

(3)数组对应在内存中一段连续空间。

(4)数组元素必须是相同数据类型,也可以是引用数据类型,但是同一个数组中的元素必须是同一数据类型;

8.一维数组的声明与初始化

  可以理解为一列多行、类型相同的数据,其中每个数据被称为数组元素;

  声明方式:

       type  varName[];

     或type []varName;

数组的长度一旦确定就不能改变,数组是定长的;

数组的初始化

  Java中的数组必须先初始化才可以使用,即数组的数组元素分配内存,并为每个数组元素赋值。

数组初始化的两种方式:

  静态初始化:初始化时由我们指定每个元素的初始值,由系统决定需要的数组长度;

   格式:数组名=new 数组类型[]{元素1,元素2,元素3……元素n};

        简化格式:数组名={元素1,元素2,元素3……元素n};

  动态初始化:初始化时指定数组的长度,由系统为数组元素分配初始值;

格式:数组名=new 数组类型 [ 数组长度 ];

注意:不能同时指定数组长度和数组元素;

9.数组的使用

Java语言的数组索引是从0开始的,也就是说数组里的第一个元素的索引是0;第二个元素的索引是1,依次类推;

常见操作:

给数组元素赋值

   数组名[ 索引 ] = 数组类型的值;

访问数组元素

  数组类型  变量 = 数组名 [ 索引 ] ;

得到数组的长度

  int len =数组名.length;

遍历数组

数组元素的索引范围(0,length-1)

10.分配内存空间

数组名 = new 数据类型 [ 数组长度 ];

new关键字用来实现为数组或对象分配内存( 堆内存 )

数组具有固定的长度。

获取数组的长度:数组名.length

定义数组+分配内存空间

数据类型[ ]数组名 = new 数据类型[ 数组长度 ];

定义数组时不指定长度,分配内存空间时指定数组长度。

数组元素:

数组名[ 下标值 ]

数组下标从0开始;

数组的内存分配:栈内存  和  堆内存;

在方法中定义的变量,包括基本数据类型变量和引用数据类型变量,都将在栈内存中分配空间,当超过变量作用范围后,自动回收。

(初始化=定义数组+分配空间+赋值);

11.二维数组

其实是一个一维数组,它的每一个元素又是一个一维数组。

初始化:

  动态初始化:int [][] arr = new int [m][n];

  静态初始化:int [][] arr = new int [][]{ {  } , {  }};

              Int [][] arr={{ } , { } , { }};

12.操作数组的工具类Arrays

static int binarySearch(type[]a,type key)

使用二分搜索法搜索k元素在数组中的索引,若a数组不包括key,返回负数。(该方法必须已按升序排列后调用)

Static int binarySearch(type[]a, int fromIndex, int toIndex,type key)

使用二分搜索法搜索key元素在数组中从fromIndex到toIndex的索引;若数组不包括key,返回负数。(该方法已按升序排列后调用)

static Boolean[] copyOf ( type[]original , int newLength)

复制指定的数组

static byte [] copyOfRange ( type [] original, int from , int to )

将数组的指定范围复制到一个新数组

static Boolean equals (type [] a , type [] a2 )

如果两个数组长度相等且元素一一对应,则返回true

static void fill ( type [] a,type [] val )

将a数组中所有元素都赋值为val

static void fill ( type []a,int fromIndex,int toIndex,type all)

将a数组的指定范围内的元素都赋值为var

static void sort (type [] a)

sort( int [] arr )

对指定的数组按数字升序排序

static void sort ( type [] a,int fromIndex,int toIndex )

将a数组指定范围的元素按升序进行排序

static  String  toString (type [] a)

返回指定数组的字符串表示形式,多个数组元素之间用英文逗号或空格隔开

13.java5新特性对数组的支持

增强for循环—for each

for (参数类型 参数名:数组名)

{

       代码块

}

三. 面向对象

1.       什么叫面向对象

简称 OO,Object Oriented,就是一种常见的程序结构设计方法。

面向对象的思想的基础是将相关的数据和方法放在一起,组合成一种新的复合数据类型,然后使用新创建的复合数据类型作为项目的基础

面向对象是一个抽象的概念,它相对面向过程而言。

过程与对象都是一种解决问题的思想。

面向过程:强调的是功能行为,一种过程,先干啥,再干啥。

面向对象:将功能封装在对象中,强调的是具备某种功能的对象。

按照面向对象的思想,可以把任何的东西看做对象。

面向对象的三大特征:

      封装( Encapsulation)

      继承 (Inheritance  )

      多态 ( Polymorphism )

2.       类

类(class)是java语言的最小编程单位,也是设计和实现java程序的基础。

概念:

类是一组事物共有特征和功能的描述。是对于一组事物的总体描述,是按照面向对象技术设计的最小的单位。也是组成项目的最基本的模块。类的概念是抽象的,类似于建筑设计中的图纸,是对于现实需要代表的具体内容的抽象。类只包含框架结构,而不包含具体的数据。所以类代表的是总体,而不代表某个特定的个体。

类是抽象的,对象是具体的。

定义类,其实就是定义类里面的对象。

对象包含:

   状态(属性)

   功能,行为,方法,

通过类来描述对象:

状态---成员变量;

   功能、行为----方法。

3.       构造方法

用来构造类的实例(每个类都默认有一个无参的构造方法,得使用new调用)

字段:类或对象所包含的数据,对类状态的一种描述。

方法:类或对象的特征或行为。

作用:

给类中的字段进行初始化,可以用来创建对象。

特点:

    方法名与类名相同

    不用定义返回值类型

    不需要写return语句

构造方法的重载:

    this(实参);--------调用当前类的构造方法

    注意:this(实参);必须放在构造器的第一行

对象的产生格式:

    类名称 对象名 = new 类名称();

    因为有(),所以是方法,实际上它就是构造方法,并且是非私有的构造方法;

4.       static关键字

特点:

随着类的加载而加载;

优先于对象而存在;

被所有的对象所共享;

可以直接被类名调用;

   使用注意:

       静态方法只能访问静态成员;

       非静态成员可以访问非静态成员;

       静态方法中不可以使用this、super关键字;

       主方法是静态的。

可修饰字段、方法。

用static修饰的成员表示它属于这个类共有,而不是属于该类的单个实例。

      Static 修饰的字段 = 类字段;

      Static 修饰的方法 = 类方法;

没使用static修饰的字段和方法、成员属于类的单个实例,不属于类。

      没有static修饰的字段 = 实例字段;

      没有static修饰的方法 = 实例方法;

类和实例访问字段和方法的语法:

      访问类成员: 类.字段    类.方法

      访问实例成员: 实例.字段    实例.方法

Static修饰的字段和方法,既可以通过类调用,也可以使用实例调用;

没static修饰的字段和方法,只能使用实例来调用

Static关键字不能与this、super同时连用。

5.匿名对象

  一个没有名字的对象,创建了一个对象出来,没有赋给一个变量;

特点:

对方法或字段只进行一次调用;

可作为实际参数进行传递;

只在堆里面开辟区域;

只能使用一次,使用完就被销毁了;

5.       this关键字

特点:this表示当前对象。

               即正在调用实例成员的对象。

this用于方法间的相互调用;

this[参数] 必须写在构造方法第一行;

this 不能用在static修饰的方法里和static修饰的代码块里;

6.       封装

包含两个含义:

(1)       把对象的状态和行为看成一个统一的整体,将二者存放在一个独立的模块中(类);

(2)       “信息隐藏”,把不需要让外界知道的信息隐藏起来,尽可能隐藏对象功能实现细节,字段。

封装机制在程序中的体现是:把描述兑现的状态用字段表示,描述对象的行为用方法表示,把字段和方法定义在一个类中,并保证外界不能任意更改其内部的字段值,也不允许任意调用其内部的功能方法。

封装在程序中的体现是:通常将类中的成员变量私有化(private),通过对外提供方法,可对该变量进行访问。

注意:boolean类型的变量没有get()方法,只有is();

8.访问修饰符

   Private 类访问权限,本类内部可以访问,不能继承到子类;

   Default 什么都不写,包访问权限:本类内部可以访问,同包其他类也可以访问,同包可继承;

   Protected 子类访问权限:本类内部可以访问,子类可以访问,同包其他类也可以访问,能继承到子类;

   Public 公共访问权限:任何地方都可以访问,能继承到子类;

9.类的设计分析

分析思路:

      根据要求写出类所包含的字段;

      所有的字段都必须私有化;

      封装之后的字段可以通过set和get设置和获取

      按需求可添加若干构造方法;

      根据需求可添加相应的方法;

      类中的所有方法都不要直接处理(打印输出),而是交给调用者区处理;

10.继承

首先有反映一般事物特征的类,然后在次基础上反映出特殊事物的类;

   继承是一种从一般到特殊的关系;

特点:

(1)       提高了代码的复用性;

(2)       让类与类之间产生了关系,有了这个继承关系才有了多态的特性。

(3)       Java语言中只支持单继承;

因为多继承容易带来安全隐患(父类多了,如果功能项同,就会出现调用的而不确定性;如果重写一个方法,不确定到底写的谁的方法)

               注意:接口可以实现多继承;

(4)       java支持多层继承,object类是每个类的超类,实现树状结构;

 

  继承是多态的前提。对类而言,只支持单继承,接口可以实现多继承。

  我们把superClass称为父类或超类或基类;把subClass称为子类或派生类或拓展类;

Object类是直接父类或间接父类。

一个类只有一个直接父类;

一个类没显示的继承其他类的时候,默认的直接父类就是Object类;

一旦一个类显示的继承了其他的一个类的时候,此时默认的直接父类Object就会被取消;

子类对象实例化过程:

   子类对象在实例化之前必须首先调用父类中的构造方法之后再调用自身的构造方法。

11.子类访问父类和方法重写

  子类不能直接访问父类的私有成员;

   子类可以调用父类的非私有方法来间接访问父类的私有成员。

   子类拓展父类,子类是父类的一种特殊情况

  

  方法重写的原因:

当父类中某个方法不适合于子类时,子类出现父类一模一样的方法。

调用被覆盖的父类方法:使用super.方法名(实参);

方法重写时应遵循的原则:

方法签名必须相同;

子类方法的返回值类型必父类方法的返回值类型更小或相等;

自类方法声明抛出的异常应必父类方法声明抛出的更小或相等;

子类方法的访问权限应必父类的方法更大或相等;

12.super关键字和调用父类构造方法

表示父类对象的默认引用。

如果子类要调用父类被复写的实例方法,可用super作为调用者调用父类被覆盖的实例方法。

使用super调用父类的方法。

使用super调用父类的构造方法。

调用构造方法:

本类中调用另一个重载构造方法用this(参数列表);

子类构造方法调用父类构造方法用super(参数列表);

子类调用父类的构造方法时:

Super必须放在第一句;

Java在执行子类的构造方法前会调用父类无参的构造方法,其目的是为对继承自父类的成员做初始化操作。

子类在创建对象的时候,默认调用父类的无参构造方法,要是子类构造方法中显示指定调用父类其他构造方法,就调用指定的父类构造方法,取消调用父类无参构造方法。

13.面向对象之多态

     值同一个实体同时具有多种形式。

     编译时的类型由声明该变量时使用的类型决定,运行时的类型有实际赋给变量的对象决定。即编译看左边,运行看右边。如果编译时和运行时类型不同,就出现多态。

引用关系:父类变量指向子类实例对象。

实现多态的机制:

    父类的引用变量可以指向子类的实例对象,而程序调用的方法在运行时期才动态绑定,就是引用变量所指向的真正实例对象的方法,而不是引用变量的类型中定义的方法。

多态的作用:

    把不同的子类对象都当做父类来看,可以屏蔽掉不同子类对象之间的差异,写出通用的代码,作出通用的编程,以适应需求的不断变化。

    只修改方法的实现,不必修改方法的声明。

    继承是多态产生的前提条件;

分类:

    编译时多态:方法重载;

    运行时多态:方法重写;

14.引用变量类型转换

向上转型(子类-------父类):(自动完成)

   父类名称   父类对象 = 子类实例;

向下转型(父类-------子类):(强制完成)

   子类名臣  子类对象 = (子类名称)父类实例;

对象名  instanceof 类

判断指定的变量名此时引用的真正的类型是不是当前给出的类或子类;

对象的类型和类必须有继承关系;

四.面向对象(2)

1.       基本数据类型的包装类

基本数据类型            包装类

  byte                    Byte

  short                   Short

  int                     Integet

  long                    Long

  char                    Character

  float                    Float

  double                  Double

  boolean                  Boolean

除了Integer和Character定义的名称和对应的基本类型差异大,其他六种都是将首字母大写就可以了。

Integer,Byte,Float,Double,Short,Long都是Number类的子类。

Character和Boolean都是Object的直接子类;

八个类都是fanal修饰的(不可被继承);

2.       基本数据类型和包转类相互转换

把基本数据类型转换成包装类:

  通过对应包装类的构造方法实现;

  除了Character外,其他包装类都可以传入一个字符串参数构建包装类对象。

包装类----------转成基本数据类型

  包装类的实例方法:xxxValue();

Jdk5 开始出现的特性:

   自动装箱:可先把一个基本类型变量直接赋给对应的包装类对象或Object对象;

   自动拆箱:允许把包装类对象直接赋给对应的基本数据类型;

3.       基本类型和String之间的转换

String——基本数据类型,除了Character外所有的包装类提供parseXxx(String s)静态方法,用于把一个特定的字符串转换成基本类型变量;

基本类型——String,String类有静态方法ValueOf ( ),用于将基本类型的变量转换成String类型。

4.       Object类

所有的公共父类,一旦一个类没有显示地继承一个类,则其直接父类一定是Object。

一切数据类型都可用Object接收;

常见方法:

public Boolean equals(Object obj):对象比较;

public int hashCode():取得该对象的Hash码值

public String toString():对象描述

Object类的toString方法:对象的描述;

建议所有的类都重写此方法。

直接打印输出对象时,会调用该对象的toString方法。

打印对象的时候,实际调用的是对象实际指向的类的自我描述;

全限定类名+@+十六进制的hashCode值,等价于:

全限定类名+@+Integer.toHashString(该对象.hashCode)

equals也是判断是否指向同一个对象。没有实际意义,有必要可以重写。

String重写了Objectde 的equals方法:只比较字符的序列是否相同。

==用于判断两个变量是否相等。

基本类型:

引用类型:必须指向同一个对象,才会返回true;

只能比较有父子关系或平级关系的两个对象;

5.       代码块

指的是用{}括起来的一段代码,根据代码存在的位置可以分为4种:

普通代码块

构造代码块

静态代码块

同步代码块

代码块里变量的作用域:只在自己所在区域的{}内有效;

普通代码块:

    就是直接定义在方法或语句中定义的代码块;

构造代码块:

    直接写在类中的代码块;    优先于构造方法执行,每次实例化对象之前都会执行构造代码块。

静态代码块:

    使用static修饰的构造代码块;

    优先于主方法执行,优先于构造代码块执行,不管创建多少对象,静态代码块只执行一次,可用于给静态变量赋值;静态代码块优先于构造代码块执行。

6.       构造方法的私有化

为了避免外界创建某类的实例,就将某类的构造方法私有化,即将它的构造方法用private修饰。

外界如何用?提供构造方法。

7.       Singleton模式(单例模式)饿汉式和懒汉式

目的:整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例。

常见单例模式:

饿汉式:直接将对象定义出来;static 修饰,随着类的加载而加载,会损耗性能,但是方法相对简单。

懒汉式:只给出变量,并不将其初始化;第一次用的时候相对较慢,线程不安全。

8.       final关键字

(1)       final可以修饰类,方法,变量;

(2)       final修饰类不能别继承,但是可以继承其他类;

(3)       final修饰的方法不能被重写,但可以重写父类方法;

(4)       final修饰的变量称为常量,这些变量只能赋值一次;

(5)       内部类在局部时,只可以访问被final修饰的局部变量;

(6)       final修饰的引用类型变量,表示该变量的引用不能变,而不是该变量的值不能变。

9.       抽象类

当编写一个类时,我们往往会为该类定义定义一些方法,这些方法是用来描述该类的行为方式,这些方法都有具体的方法体。

但是有些时候,某个父类只是知道了子类应该包含怎么样的方法,但是无法准确知道子类如何实现这些方法。

定义:

通过abstract关键字来修饰的类称为抽象类。

可以定义被abstract修饰的抽象方法。

抽象方法只有返回类型和方法签名,没有方法体。

注意:

抽象类可以含有普通方法。

抽象类不能创建实例对象(不能new);

需要子类重写所有的抽象方法后才可以创建子类对象,否则子类也必须作为抽象类;

如几个常见抽象类:流的几个基本父类:InputStream  OutputStream   Reader    Writer

抽象类可以没有抽象方法。

抽象类是类的一种特殊情况,具有类的一切特点,但不能被实例化,一般的都得带有抽象方法。

抽象类不可以实例化,有时看到的近似实例化是多态机制的体现,并不是真正的实例化。

abstract方法

分析事物时,发现了共性内容,就出现了向上取舍。会有这样一种特殊情况,就是功能声明相同,但功能主体不同。

那么这时也可以抽取,但只抽取方法声明,不抽取方法主体,那么此方法就是一个抽象方法。

abstract 返回值类型  方法名称(参数列表);

抽象方法要存放在抽象类中。

抽象方法也可以存在于接口中。

10.抽象类的体现-模板模式

抽象类是多个具体子类抽象出来的父类,具有高层次的抽象性,以该抽象类作为子类的模板可以避免子类设计的随意性;

抽象类的体现就是模板模式设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行拓展,但是子类在总体上大致保留抽象类的行为方式。

编写一个抽象父类,该父类提供了多个子类的抽象方法,并把一个或多个抽象方法留给子类区实现,这就是模板设计模式。

模板模式应用的简单规则:

(1)       抽象父类可以只定义需要使用的某些方法,其余留给子类区实现;

(2)       父类提供的方法只是提供了一个普通的算法,其实现必须依赖子类的辅助;

如果父类不想被子类重写,那么可以在前面加上final关键字修饰。

10.   接口(interface)

引入:抽象类是从多个类中抽象出来的模板,若要将这种抽象进行得更彻底,就得用到一种特殊的抽象类:接口。

例子:

生活中所说过的usb接口其实并不是我们所看到的那些插槽,而是那些插槽所遵循的一种规范;而我们看到的是那些插槽是根据usb规范设计出来的实例而已,即插槽是usb的实例;对于不同型号的usb设备而言,他们各自的usb插槽都需要遵循一个规范,遵守这个规范就可以保证插入插槽的设备能与主板正常通信。对于同一型号的主板上的多个usb插槽,他们有相同的数据交换方式,相同的实现细节,可认为他们都是同一个类的不同实例。

接口只是定义了类应当遵循的规范,却不关心这些类的内部数据和其方法内的实现细节。接口只规定了这些类里必须提供的方法,从而分离了规范和实现,增强了系统的可拓展性和维护性。

使用接口的好处:

    拓展性,维护性更好。(相当于定义了一种标准)

接口定义:

    接口定义一种规范,定义一个类必须做什么,但没有规定如何去做。

[修饰符] interface 接口名 extends 父接口1,父接口2……

    没有构造方法,不能实例化;

    接口只能继承接口,不能继承类;

    接口里没有普通方法,方法全部是抽象的。

    接口里的方法的默认修饰符是:public  abstract;

    接口里的字段全是全局常量,默认修饰符是public abstract final

    接口里的成员包括:

      全局常量:公共的抽象方法,内部类(包括内部类,内部接口,内部枚举类)

     

12接口的使用

格式:public class SubImpl extends Super implements IA,IB

接口可以多继承,但是只能继承接口,不能继承类。

实现接口(支持多实现)

    [修饰符]class 类名 implements 接口1,接口2……

接口的实现必须在extends之后,实现接口的方法必须是public类型。

接口不能创建实例,但是可以声明引用类型的变量。此时,引用类型的变量必须指向其实现类对象。

接口与类之间的关系:

实现关系或是继承关系;

可以说是类实现了接口的方法,也可以说是类继承了接口的方法。

13.面向接口编程之制定标准和简单工厂模式

制定一个标准,让别人去实现或者是满足它;

简单工厂模式,构建一个工厂出来,在里面进行生产,用的时候直接拿。

屏蔽了不同子类实现的差异,提高代码的可拓展性和可维护性;

14.面向接口编程之适配器模式

使用一个现成的类,但是他的接口不完全符合你的要求,调用者只想要它其中的一个方法,不想重写其它的方法。

实现思路:定义一个适配器类去实现接口中所有的抽象方法,在定义一个类来继承这个适配器类,重写需要的方法。(其实是根据继承和接口的规则规范进行类和方法的模式设计)

15.接口和抽象类的比较

   相同点:

     都位于继承的顶端,用于被其它实现或继承;

     都不能被实例化;

     都包含抽象方法,其子类都必须重写这些抽象方法。

   区别:

     抽象类为部分方法提供实现,避免子类重复实现这些方法,提供代码复用性,接口只能包含抽象方法。

     一个类只能继承一个直接父类(可能是抽象类),却可以实现多个接口(弥补了java的单继承)

二者的选用:

     优先选用接口,尽量少用抽象类;

     需要定义子类的行为,又要为子类提供共性功能时才选用抽象类;

注意:

接口不能有构造函数,抽象类可以有构造函数;

abstract可以定义构造函数(包括带函数的构造函数),因为要确保其子类在创建的时候能够进行正确的初始化,但是abstract类不能被实例化。

如果不可以或没有创建对象,那么我们必须加上static修饰,不能用对象调用,就只好用类去调用。

16.匿名内部类

   适合只使用一次的类

   不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建匿名内部类的对象。匿名内部类不能定义构造器,因为匿名内部类没有类名。

格式:

   new 父类构造器(实参列表 或 接口)

   {

            匿名内部类的类体部分;

}

17.枚举类

   使用enum声明,默认直接继承了java.lang.Enum类,而不是Object类;

   枚举类的对象是固定的,实例个数有限,不可以再new(),枚举对象后可以跟();

   枚举元素必须位于枚举类体中的最开始部分,枚举元素后要有分号与其他成员分隔。

   枚举类的构造方法的权限修饰符默认是private;

   一旦枚举对象后面加上{},那么该对象实际是枚举匿名内部类对象;

   所有枚举类都提供一个静态的value()方法(返回该枚举类所有对象组成的数组),便于遍历所有枚举对象;

   所有枚举类都提供一个静态的ValueOf(String name)方法,返回枚举类中对象等于name的对象。

枚举类重写接口抽象方法的两种方式:

   在枚举类中实现接口的抽象方法;

   在枚举匿名内部类中实现接口的抽象方法;

注意:枚举不可以new(),反射也不行;

      一个类如果没有构造方法,那么一定有相对应的某个方法可以获取对象。

五.异常处理和异常类

1.异常

就是不正常,是指程序在运行时出现的不正常情况。其实就是程序中出现的问题。这个问题按照面向对象的思想进行描述,并封装成了对象。因为问题的产生有产生的原因、有问题的名称、有问题的描述等多个属性信息存在。当出现多属性信息最方便的就是将这些信息进行封装。异常就是java按照面向对象的思想将问题进行对象封装。这样就方便于操作问题以及处理问题。

出现的问题有很多种,比如角标越界,空指针等都是。对这些问题进行分类,而且这些问题都有共性内容,如:每一个问题都有名称,同时还有问题描述的信息,问题出现的位置,所以可以不断地向上抽取。形成了异常体系。

异常体系 Throwable

Error

   通常指jvm出现重大问题,如:运行的类不存在或内存溢出等。

   不需要编写针对代码对其处理,程序无法处理。

Exception

   在运行时出现的一些情况,可以通过try,catch,finally处理。

异常处理两种方式:

   1.捕获异常:try  catch   直接处理可能出现的异常

   2.声明异常:throws      声明告诉调用者可能的异常,暴露问题,调用者自己处理

总结:

   Exception 和 Error 的子类名大都是以父类名作为后缀;

   Java异常其实是对不正常情况的一种描述,并将其封装成对象;

   Java在设计异常体系时,将容易出现的异常情况都封装成了对象。

2.异常处理格式

   异常处理的五个关键字

try   catch   finllly   throw   throws 

注意:捕获异常:先捕获小异常,再捕获大异常;

      程序是调出来的,不是写出来的,多测试是程序员的必修课。

      异常处理后,程序不会因为出现异常而退出。

异常处理格式:

   try{

可能出异常的代码;

}catch(异常类  异常对象){

处理该异常类型的语句;

}finally{

    一定会执行的代码;(catch处使用System.exit();除外)

}

注意:当try语句块出现异常,程序会自动跳到catch语句块去找匹配的异常类型,并执行异常处理语句,finally语句块是异常的统一出口。

3.       多异常处理

声明异常时尽量声明具体类型,方便更好的处理;

方法声明几个异常就对应几个catch块;

若多个catch块中的异常出现继承关系,父类异常catch块放在最后;

在catch块语句使用Exception类作为异常类型时:

   所有子类实例都可以使用父类接收(向上转型),即所有的异常对象都可以使用Exception接收;

注意:在java处理多异常时捕获小范围的异常必须放在大范围异常之前。

4.       异常的分类

异常分类:

   编译时被检查异常;---------checked异常

   在程序中必须使用try……catch处理;

   编译时不被检测的异常;-----Runtime异常

      可以不使用try……catch处理,但一旦出现异常就将由jvm处理。

Runtime异常

   RuntimeException(运行时异常)是指因设计或实现方式不当而导致的问题。即是由程序员造成的。

   特点:

      这种异常java编译器不会检查它,也就是程序中出现这类异常的时候,即使不处理也没有问题,但是一旦出现异常,程序将异常终止,若采用异常处理,则会按照相应的程序执行处理。    

Checked异常

   除了RuntimeException以及其子类,其他的Exception及其子类都是受检查异常,我们也可以称为非RuntimeException异常。

   特点:java编译器会检查它,也就是程序一旦出现这类异常,要么是没有try catch进行捕获,要么是没有throws语句抛出它,编译不会通过,这种异常程序必须处理。

5.声明异常(throws)

   在可能出现异常的方法上声明抛出可能出现异常的类型:

      声明的时候尽可能声明具体的异常,方便更好的处理。

      当前方法不知如何处理这种异常时,可将该异常交给上一级调用者来处理(非RuntimeException类型的异常);

      方法一旦使用throws声明抛出方法内可能出现的异常类型,该方法就可以不再过问该异常了;

      一个方法调用另一个使用throws声明抛出的方法,自己要么try……catch,要么也throws;

格式:

   public 返回值类型  方法名(参数列表……)throws异常类A,异常类B……

{

  

}

6.throw

   自行抛出一个异常对象,抛出异常类的对象;

   若throw抛出的是Runtime异常:

      程序可以显示使用try  catch来捕获并处理,也可以不管,直接交给方法调用者处理;

   若throw抛出Checked异常:

      要么放在try里面自己处理,要么放在一个throws声明中的方法里 ,交给调用者处理;

throw 和throws的区别:

   throws用于在方法上声明该方法不需处理的异常类型。

   throw用于抛出具体异常类的对象。

   throws用在方法上,后面跟异常类名,可以是多个异常类。

   throw用在方法内,后面跟异常对象,只能是一个。

7.finally

   异常的同一出口:

   不管try块程序是否异常,也不管哪个catch执行,finally块总会执行。

   try语句块或会执行的catch语句块使用了JVM系统推出语句例外;(如Systm.exit())

   try块必须和catch块或和finally块同在,不能单独存在,二者必须出现一个。

注意:不要在finally中使用return或throw语句,否则将会导致try、catch中的return或throw失效。

8.throw和catch同时使用

   当异常出现在当前方法中,程序只对异常进行部分处理,还有一些处理需要在方法的调用者中才能处理完成,此时还应该再次抛出异常,这样就可以让方法的调用者也能捕获到异常;

9.常用类

  String

  String表示字符串,就是一连串的字符。

   String类是不可变类,一旦String对象被创建,包含在在对象中的字符序列(内容)是不可变的,直到对象被销毁;

常量池:JVM中一块独立的区域存放字符串常量和基本类型常量(public static final);

   String使用private final char value[]来实现字符串的存储,即String对象创建后,就不能再修改此对象中存储的字符串内容,即字符串的不变性。

String对象比较:

  单独使用“”创建的字符串都是常量,编译期就已经确定存储到常量池中;

  使用new String (“”)创建的对象会存储到堆内存中,是运行期新创建的;

  使用只包含常量的字符串连接符如“aa”+“bb”创建的也是常量,编译期就能确定,已经确定存储到常量池中;

  使用包含变量的字符串连接符如“aa”+s1创建的对象是运行期才创建的,存储在堆中;

10.String方法

String():

初始化一个新的String对象,使其表示一个空字符序列,并不是返回空(不等于null)

String(StringBuffer buffer)

根据StringBuffer对象来创建String对象

String(StringBuilder  builder)

根据StringBuilder对象来创建String对象

Char charAt(int index)

取字符串中指定位置的字符,index从0开始计算

String concat(String  str)

连接字符串,等同于“+”

boolean  equals(Object  obj)

将该字符串与指定对象比较,若二者包含的字符序列相等则返回true

boolean contentEquals(StringBuffer  buffer)

若二者包含的字符序列相同时就返true

boolean equalsIgnoreCase(String  anotherString)

将此String与另一个String比较,不考虑大小写

byte [] getBytes()

将该字符串转换成byte数组

。int indexOf(String s)

找出s字符串在该字符串中第一次出现的位置

。int indexOf(String  s,int fromIndex)

返回s字符串在此字符串中第一次出现的索引,从指定的索引开始

。int lastIndexOf(String  s)

返回指定的字符串在此字符串最后一次出现的索引

。int length()

返回当前字符串长度

String replace(char oldChar, char  newChar)

返回一个新的字符串,它是通过用newChar替换此字符串所有的oldChar得到的

String  replaceAll(String  regex, String  replacement)

使用给定的字符串replacement替换此字符串所有的regex字符串

。boolean startsWith(String prefix)

测试此字符串是否以指定的前缀开始

String[] split(String  regex)

把字符串按指定的字符串分隔开

String  substring(int  beginIndex)

返回一个新的字符串,从指定位置开始截取

String substring (int beginIndex,int endIndex)

返回一个新的字符串,从指定位置开始,截取到另一个指定位置

Char [] toCharArray()

将此字符串转换成一个新的字符数组

String toLowerCase()

将此字符串中的所有字符都转成小写

String toUpperCase()

将字符串中的所有字符转成大写

。static String valueOf(基本类型  obj)

把基本类型值转成字符串

String trim()

去掉字符串两端空格

11.   StringBuffer与StringBuilder

String是不可变类,一旦String对象被创建,包含在对象中的字符序列是不可变的,直到对象被销毁

StringBuffer与StringBuilder对象则是可变的。

StringBuffer是线程安全的;

StringBuilder是线程不安全的,性能高;(jdk1.5出现)

StringBuffer的字符序列是可变的(通过append等方法操作)

StringBuffer和String之间的转换

   String  toString()返回此序列中数据的字符串表示形式

   StringBuffer(String  s) 以指定的字符串创建StringBuffer对象

StringBuffer方法:

   。public StringBuffer()

   构造一个不带任何字符的StringBuffer对象

  

。StringBuffer(String  s)

   构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容

   StringBuffer append(Object  obj)

   将指定的任意对象追加到此StringBuffer对象中

   StringBuffer insert(int offset ,Object  obj)

   在字符串缓冲区指定位置插入数据

   StringBuffer  delete(int start,int end)

   删除字符串缓冲区指定区域的字符

   StringBuffer  deleteCharAt(int  index)

   删除字符串缓冲区中指定位置的字符

12.   Math和Random和UUID

Math类

      public final class Math extends Object

   对于double,float,int,long有共同的方法

      abs(Object obj)求绝对值

      max(Object  obj1, Object  obj2)求最大值

      min(Object  obj1, Object  obj2)求最小值

  public static double random() 返回带正号的double值,该值大于等于0.0且小于1.0.和使用new java.util.Random一样。

Math.PI   圆周率

Random类

   负责生成伪随机数;

   Random()创建一个新的随机数生成器

   int nextInt()返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的int值。

   int nextInt(int n)返回一个伪随机数,它是取自此随机数生成器的序列的、在0到n之间均匀分布的值。

UUID类

   用唯一标识符(UUID)的类。UUID 表示一个128位的值。

UUID(用来标示文件名等,避免因文件上传可能名字相同而被覆盖),可以保证全网唯一。

Universallly Unique Identifier:全局唯一标识符,是指一台机器上生成的数字,它保证对在同一时空中所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID 码和许多可能的数字。由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全国唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。

标准的UUID的格式:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx(8-4-4-4-12),其中每个x是0-9或a-f范围内的一个十六进制的数字。

UUID  uuid=UUID.randomUUID();

String  uid=uuid.toString();

13.   Date 和Calendar

处理日期,时间;

大部分的方法已过时,不推荐使用,但使用过时的方法也不会报错。

Date()分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒);

Date(long  date) 分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即1970年1月1日00:00:00 GMT)以来的指定毫秒数。

SimpleDateFormat

java.text.SimpleDateFormat

SimpleDateFormat 是一个与语言环境有关的方式来格式化和解析日期的具体类。它允许进行格式化(日期-à文本)、解析(文本-->日期)和规范化。

SimpleDateFormat(String  pattern) 用给定的模式和默认的语言环境的日期格式符号构造SimpleDateFormat。

public final String format(Date  date)将一个Date格式化为日期/时间字符串。

public Date parse(String  source)throws ParseException:把字符串source表示的时间按source的格式转成Date对象。

Calendar

推荐使用处理日期和时间的类Canlendar;

是抽象类,不能实例化,通过static Calendar getInstance()获得一个Calendar对象。

int get(int field):返回指定日历字段值

静态常量:

YEAR 表示年的字段数字

MONTH 表示月份字段数字,月份范围是(0-11)

DATE 表示一个月中的某天

DAY_OF_MONTH 表示一个月中的某天

DAY_OF_WEEK 表示一个星期中的某天

HOUR_OF_DAY/HOUR 表示第几小时

MINUTE 表示第几分钟

SECOND 表示第几秒

Date getTime() 返回一个表示此Calendar时间值的Date对象

void set(int year,int month ,int date ,int hour, int minute, int second)设置字段YEAR、MONTH、DAY_OF_MONTH、HOUR、MINUTE和SECOND的值。

abstract void add(int field,int amount)根据日历的规则,为给定的日历字段添加或减去指定的时间量。若amount为负数,则减去相应的天数;若amount是正数,则加上相应的天数。

14.System

   System类包含一些与系统相关的类字段和方法,它不能被实例化,类中所有属性和方法都是static,可直接被System调用。

常用方法:

   Static void exit(int status)终止虚拟机的运行,对于发生了异常情况而想终止虚拟机的运行,传递一个非0数值,对于正常情况下退出系统传递0值;该方法实际调用的是Runtime.getRuntime().exit(int status)

   static void arraycopy(Object src,int srcPOS,Object dest,int destPos,int length)数组拷贝

   static long currentTimeMillis()返回以毫秒为单位的当前时间

   String gettenv(String name)获得指定的环境边境变量

   Static void gc()运行垃圾回收器。实际上调用了Runtime中的gc()方法;

   Runtime.getRuntime().exec(String command)打开程序

   static Properties getProperties()取得当前的系统属性

   static String getProperty(String key)取得指定键指示的系统属性

   static String getProperty(String key,String def)获取用指定键描述的系统属性,def表示默认信息

六.线程技术

1.       进程和线程

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个进程。比如在Windows系统中,一个运行的xxx.exe就是一个进程。

Java程序的进程里有几个线程:主线程,垃圾回收线程(后台线程)

线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据。

多进程:操作系统中同时运行的多个程序。

多线程:在一个进程中同时运行的多个任务。

一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个控制单元,并发运行。

多线程存在一个特性:随机性;

造成的原因:cpu在瞬间不断切换区处理各个线程而导致的。可以理解为多个线程在抢cup的资源。

           多线程是为了同步完成多项任务,不是为了提供运行效率,通过提高资源使用效率来提高系统的效率。

      线程与进程的比较:

         线程具有许多传统进程所具有的特征,故又称为轻型进程(Light-Weight Process)或进程元;而把传统的进程称为重型进程(Heavy-Weight Process),它相当于只有一个线程的任务。在引入了线程的操作系统后,通常一个进程都有若干个线程,至少需要一个线程。

         区别:

(1)进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。

(2)线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响。

2.创建线程方式

   (1)继承Thread类

      子类重写父类中的run方法,将线程运行的代码存放在run中。建立子类对象的同时线程也被创建。

通过调用start方法开启线程。

(2)实现Runnable接口

   子类重写接口中的run方法。通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。

   Thread类对象调用start方法开启线程。可使用匿名内部类来写。

总结:

   Thread类中的run()方法和start()方法的区别如下:

run()方法:在本线程内调用该Runnable对象的run()方法,可以重复多次调用;

srart()方法:启动一个线程,调用该Runnable对象的run()方法,不能多次启动一个线程;

3.两种线程创建方式比较

(1)例:A extends Thread

   简单,单继承,不能再继承其他类了,同份资源不共享;

(2)例:A implements Runnable

多个线程共享一个目标资源,适合多线程处理同一份资源。该类还可以继承其他类,也可以实现其他接口。

疑问:为什么要重写run方法呢?

   Trhead类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。即thread类的run方法用于存储线程要运行的代码。

4线程的生命周期

   Thread类内部有个public的枚举Thread.State,里边将线程的状态分为:

   NEW--------新建状态,至今尚未启动的线程处于这种状态。

   RUNNABLE------运行状态,正在java虚拟机中执行的线程处于这种状态。

   BLOCKED--------阻塞状态,无限期地等待某个监视器锁的线程处于这种状态。

   WAITING------冻结状态,无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。

   TIMED_WAITING-------等待状态,等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。

   TERMINATED----------已退出的线程处于这种状态。

如何让线程结束:

   只有一种方法,run方法结束。开启多个线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,即线程结束。

5、控制线程

   Join方法:调用join方法的线程对象强制运行,该线程强制运行期间,其他线程无法运行,必须等到该线程结束后其他线程才可以运行。

后台线程:处于后台运行,任务是为其他线程提供服务,也称为守护线程或精灵线程。Jvm的垃圾回收就是典型的后台线程。特点:若所有的前台线程死亡,后台线程自动死亡。

设置后台线程:Thread对象setDaemon(true);

setDaemon(true)必须在start()之前调用。

判断是否是后台线程:使用Thread对象的isDaemon()方法;

Sleep

 线程休眠:让执行的线程暂停一段时间,进入阻塞状态。

  sleep(long millis)

  调用sleep()后,在指定时间段内,该线程不会获得执行的机会。

优先级:

   每个线程都有优先级, 优先级的高低只和线程获得执行机会的此数多少有关。并非线程优先级越高的就一定先执行,哪个线程的先运行取决于cpu的调度;默认情况下main线程具有普通的优先级,而它创建的线程也具有普通优先级。

Thread 对象的setPriority(int x)和getPriority(int x )来设置和获取优先级。最大优先级是10,最小优先级是1,主方法默认优先级是5;

yield

  线程礼让:暂停当前正在执行的线程对象,并执行其他线程;是Thread的静态方法,可以使当前线程暂停,但不会阻塞该线程,而是进入就绪状态。

6、多线程的安全问题

   导致安全问题出现的原因:

多个线程访问出现延迟;线程的随机性;

  如:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。解决办法:对多条操作共享数据的语句,只能让一个线程执行完,在执行过程中,其他线程不可以参与执行。

7、多线程安全问题的解决办法

   三种方法:

(1)       同步代码块:

(2)       同步方法:在方法上加上synchronized修饰符即可(一般不直接在run方法上加),同步方法的锁其实是this

(3)       静态方法的同步

     static 不能和this连用。静态方法的默认同步锁是当前方法所在类的.class对象。

8、线程通信

  我们的应用包含两个线程,一个线程不停象数据存储空间添加数据,另一个线程从数据空间取出数据;

 wait():让当前线程进入等待,直到被唤醒

 notify():唤醒同一对象调用wait()方法进入等待的第一个线程

 notifyAll():唤醒同意对象调用wait()方法进入等待的所有线程

这三个方法只能让同步监听器调用;这三个方法属于Object,不属于Thread:

   (1)、synchronized修饰的方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中调用这三个方法。

   (2)synchronized修饰的同步代码块,同步监视器即是括号里的对象,所以必须使用该对象调用这三个方法。

Lock代替了同步方法或同步代码块,Condition代替了同步监视器的功能;

   Condition对象通过Lock对象的newCondition()方法创建;方法包括:

     await():等价于同步监听器的wait()方法;

     signal():等价于监听器的notify()方法;

     signalAll():等价于同步监听器的notifyAll()方法;

七、集合框架一

1、  集合类和容器

为了方便对多个对象的操作,就要对对象进行存储,集合就是存储对象的最常用的一种方式。

数组虽然也可以存储对象,但长度是固定的,集合长度是可变的,数组中可以存储数据任意类型,集合只能存储对象。

集合类的特点:

   集合只用于存储对象,集合长度是可变的,集合可以存储不同的类型的对象。

   两大接口:

     Java集合类主要由两个接口派生出来:

   (1)、Collection

         Set     :不能存放重复对象;

         List     :可存放重复对象,有序;

         Queue   :队列;

         SortedSet :可对集合数据进行排序;

   (2)、Map

         SortedMap   :可对集合数据进行排序;

2、Collection接口

方法:

 boolean add(Object obj):该方法用于向集合里面添加一个元素,若集合对象 被添加操作改变了,返回true;

boolean addAll(Collection c):把集合里的元素添加到指定的集合里去,成功返true;

void clear():清除集合里面的所有元素,将集合长度变为0;

boolean contains(Object obj):判断集合中是否包含指定的元素;

boolean containsAll(Collection c):判断集合里是否包含集合c内的所有元素;

boolean isEmpty():判断集合是否为空;

Iterator iterator():返回一个Iterator对象,用于遍历集合中的元素;

boolean remove(Object obj):删除集合中指定元素;

boolean removeAll(Collection c):从集合中删除集合c中的元素,若删除一个或多个返回true

boolean retainAll(Collection c):从集合中删除集合c里不包含的元素;

   int size():得到集合元素的个数。

   Object[] toArray():把集合转成一个数组,集合的元素都变成数组元素;

3、Iterator接口

Iterator主要遍历Collection集合中的元素,也有被称为迭代器或迭代精灵。

boolean next():返回集合中的下一个元素;

void remove():删除集合上一次next()方法返回的元素。(若集合中有多个集合的元素,都可以删掉)

iterator对于集合才能用,for不同,只要是循环都可用。

迭代是取出集合中元素的一种方式,所以每一个子类集合对象都有迭代器。

迭代器在Collection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。迭代器的next方法返回值类型是Object,所以要记得类型转换。

4、集合遍历输出方式

   Iterator:迭代输出。首选。

   ListIterator:Iterator的子接口,专门输出List中的元素;

   Enumeration:古老的输出方式,迭代Vector元素,被Iterator取代;

   foreach:可输出数组和Iterable对象。

   for循环:实例化Iterable对象,进行遍历。

   先用toArray方法输出成为数组,再用Foreach循环!

5、set接口

Set是Collection的子接口;

Set是无序集合,不允许重复元素;

常用对象:hashSet散列存放;

          treeSet有序存放;

hashCode方法对于HashSet的作用;

   hashSet类是Set接口最常用的实现类,采用hash算法那存储数据,具有良好的存储和查找功能;

   散列存储:不记录添加顺序,排列顺序时,顺序可能发生变化;

线程不安全的,多个线程访问同一个HashSet要使用同步代码;

HashSet集合元素值允许是null,但最多只能有一个。

hash算法的功能:

   保证通过一个对象快速找到另一个对象;

   保证查询快速;

HashSet集合添加元素:

   当向集合存入元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,判断已经存储到集合中的对象的hashCode值是否与添加对象的hashCode值一致,若不一致,直接加进去,若一致,再进行equlas方法比较,equals方法若返回true,表明对象已经添加进去了,就不会再添加新的对象了,否则添加进去。

  若重写了equlas方法,也要重写hashCode方法。

  HashSet集合判断两个集合相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等。

6、TreeSet

  TreeSet是SortedSet接口唯一的实现,与HashSet相比额外的方法有:

     Comparator coamparator():返回当前Set使用的Comparator,若返回null,表示以自然顺序排序。

     Object first()返回此Set集合中的第一个元素

     Object last():返回此Set集合的最后一个元素

     SortedSet subset(Object fromElement,E toElement)返回此set的部子集

TreeSet的自然排序

   TreeSet会调用元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合里的元素按升序排列,此时需要排序元素的类必须实现Comparable接口,并重写CompareTo()方法;

   该方法用于比较对象,若obj1.compareTo(obj2)返回0,表示两个对象相等;

TreeSet的定制排序:

   要实现定制排序,需要在创建TreeSet的集合对象时,提供一个comparator对象,该对象负责集合元素的排序逻辑。

7.       List接口

Collection 子接口。是有序的集合,集合中每个元素都有相对应的顺序序列。List集合可使用重复元素,可以通过索引来访问指定位置的集合元素,List集合默认按元素的添加顺序设置元素的索引,比如第一个元素的索引是0;

方法:

   void add(int index,Object o):将元素添加到List集合中的指定位置处;

   boolean addAll(int index,Collection c):将集合所包含的所有元素都插入在List集合的index处

   Object get(int index):返回集合指定索引处的元素

   int indexOf(Object o):返回对象在List集合中第一次出现的索引

   int lastIndexOf(Object o):返回对象在List集合中最后一次出现的索引

   Object remove(int index):删除并返回指定索引处的元素

   Object set(int index,Object obj)替换集合指定索引处的元素

   List subList(int fromIndex,int toIndex):截取集合中的元素,返回该集合的子集合

   ListIterator  listIterator():返回ListIterator对象,ListIterator是Iterator的子接口,专门用于操作List集合的输出;

ListIterator中的方法:

   boolean  hasPrevious():逆向遍历列表,判断列表还有没有上一个元素

   Object  previous():逆向遍历列表,返回该迭代器的上一个元素

8.List接口中的常用类

   Vector:线程安全,但速度慢,基于数组实现的类,已被ArrayList替代;

   ArrayList:线程不安全,查询速度快,基于数组实现的类;

   LinkedList:链表结构,增删速度快。

取出List集合中元素的方式:

   get (int  index):通过角标获取元素。

   iterator():通过迭代方法获取迭代器对象。

   ArrayList是线程不安全的,可以通过Collections类中的方法获取到线程安全的集合。在Collections类中:static List synchronized(List list)返回指定列表支持的同步(线程安全的)列表

9、Map接口

   映射关系,又称字典。Map集合里存在两组值,一组是key,一组是value。Map里的key不允许重复,通过key总能找到唯一的value与之对应。

   Map里的key集的存储方式与对应的Set集合中的元素存储方式一致。

   Map.Entry是接口Map的内部接口,专门用来保存key-value内容。

   Map的常用方法:

     void clear():删除该集合中的所有元素。

     boolean containsKey(Object  key):查询Map中是否包含指定的键key;

     boolean containsValue(Object  value):查询Map集合中是否包含至少一个value值;

     Set entrySet():返回Map所包含的键值对所组成的Set集合,每个集合元素都是Map.Entry对象

     Object get (Object key):返回指定的键所对应的值,若此集合中不包含该键,返null

     boolean isEmpty():判断Map集合是否为空

     Set keyset():返回Map集合中所有的键所组成的Set集合;

     Object  put(Object key,Object value):添加一个键值对,若集合中存在与要添加的键值对相等的键值对,则覆盖原有的

     void  putAll(Map m):将m中的键值对赋值到当前集合中

     Object  remove(Object key):根据键,移除键值对,返回被删除之前的值

     int  size ():返回集合中键值对的个数

     Collection value():返回有当前集合中所有的值组成的Collection

Map.Entry

   Entry是Map接口里的一个内部接口;用于封装键值对,有三个方法:

     Object getKey():返回Entry里包含的键;

     Object getValue():返回Entry里包含的值;

     Object setValue(Object value):设置Entry里包含的Value值,返回新设置的值;

Map集合的输出:

   方法一:

     (1)、通过entrySet方法变成Set对象;

     (2)、调用Set的Iterator方法,此时每个Iterator对象是Map.Entry对象;

     (3)、对Map.Entry分离出key-value,用Entry接口的方法:getKey()、getValue()获取键、值;

   方法二:

     (1)、通过keySet得到存储Map中的key的Set集合;

     (2)、调用Set的Iterator方法,此时每个Iterator对象是key值;

     (3)、调用Map的方法get()得到相应的value值;

八、集合框架(二)

  1、Collections类

操作集合的工具类:

  static void reverse(List  list):反转当前的List集合的顺序;

  static void shuffle(List list):对集合元素随机排列;

  static void sort (List list):自然升序排列;

  static void swap(List list,int i,int j):将指定的List集合i处元素和j处元素进行交换;

  static void rotate (List list,int distance):若distance为正数,将list集合后的distance个元素移到前面;若distance为负数,将list集合前的distance个元素移到后面;

  static int binarySearch(List list,Object obj):使用二分搜索法搜索指定列表,获得指定对象,调用前需用Collections.sort(List list)完成自然排序;

  static Object max(Collection coll):根据给定的自然顺序,返回给定集合的最大元素;

  static Object min(Collection coll):根据元素的自然顺序,返回给定集合的最小元素;

  static void fill(List list,Object obj):使用指定元素替换列表中的所有元素;

  static int frequency(Collection coll,Object obj):返回指定集合中等于指定对象的元素的个数;

  static int indexOfSubList(List source ,List target):返回指定源列表中第一次出现指定目标列表的起始位置;若没有则返-1;

  static int lastIndexOfSubList(List source,List target):返回指定源列表中最后一次出现指定目标列表的起始位置,若没有则返-1;

  static boolean replaceAll(List list,Object oldVal,Object newVal):使用另一个值替换列表中出现的所有的某值

2、  Arrays

public static List asList(Object……a):返回一个受指定数组支持的固定大小的列表(返回的是不可变的List(长度固定))

3、  泛型(Geniric)

定义:java5开始出现的一种对于java语言类型的一种拓展,以支持创建可以按类型进行参数化的类。可以把类型参数看做是使用参数类型是指定的类型占位符,比如:方法的形式参数是实际参数的占位符。

泛型能保证大型应用程序类型安全和良好的维护性;

使用泛型的优势:

   类型安全,使编译器对泛型定义的类型做判断限制,,消除强制类型的转换。

4、  泛型的使用

泛型类:

  在类声明时通过一个标识符表示类中某个字段的类型或某个方法的返回值或参数的类型,这样在类声明或实例化的时候只要指定自己需要的类型即可。

声明带泛型的类:

   class 类名<泛型类型1,泛型类型2……>{

      泛型类型   变量名;

      泛型类型   方法名(){}

      返回指类型  方法名(泛型类型  变量名){}

   }

使用带泛型的类:

   类名<具体类> 对象 = new 类名<具体类>();

类型参数规范:推荐使用规范-常见的泛型,泛型只保存在源文件中,class文件中不存在;即在编译阶段就会丢失,泛型的擦除。基本数据类型不能作为泛型类型;

K 键,比如映射的键,key的类型;

V 键,比如Map的值,value类型

E 元素,比如Set<E> ,Element表示元素,元素的类型;

T 泛型,Type的意思。

5、声明多个泛型类型和通配符

   若一个类中多个字段需要不同的泛型声明,则在声明类的时候指定多个泛型类型即可。

  在进行引用传递的时候泛型类型必须匹配才可以传递,否则编译不通过。

  使用?,表示未知的类型的泛型对象;如:List<?> 表示未知元素的List的集合;这种带统配符的List仅表示各种泛型List的父类,并不能把元素添加入集合中。

6、泛型的上限和下限

   上限:

     设置泛型对象的上限使用extends,表示参数类型只能是该类型或该参数类型的子类:

     声明对象:类名<?extends 类> 对象名

     定义类:类名<泛型标签 extends 类>{}

   下限:

      设置泛型对象的下限使用super,表示参数类型只能是该类型或该类型的父类:

      声明对象:类名 <?super 类> 对象名称

      定义类:类名<泛型标签 extends 类> {}

7、  泛型接口和方法

Java5后,可以声明泛型接口,声明方式和声明泛型类是一样的。

泛型接口子类有两种方式:

   直接在子类后声明泛型;

   在子类实现的接口中给出具体的泛型类型;

泛型方法:

  方法中可定义泛型参数,形参的参数类型就是实参的类型。

  格式:

<泛型标签> 返回值类型 方法名([泛型标签  参数]……)

九、IO操作

   1、IO的概述和File方法

     IO流用来处理设备之间的数据传输

     Java对数据的操作是通过流的方式。Java用于操作流的对象都在IO包中。

 File类在整个IO包中与文件本省有关的操作类,所有的与文件本身有关指的是创建、删除文件等操作。在java.io包中的File类本身是一个跨平台的文件操作类,所以在操作中要更多的考虑到各个操作系统的区别。

File的相关方法:

   String getName():返回文件名或路径名(若是路径,返回最后一级子路径名)

   String getPath():返回对象对应的子路径名

   File getAbsoluteFile():返回绝对路径

   String getAbsolutePath():返回对象对应的绝对路径

   String getParent():返回文件目录的上一级目录名

   boolean canWrite():判断对象对应的文件或目录是否可写

   boolean exists():判断对象对应的文件或路径是否存在;

   boolean canRead():判断对象对应的文件或目录是否可读

   boolean isFile():判断对象是不是文件

   boolean isDirectory():判断对象的文件是否是一个目录;

   boolean isAbsolute():判断对象对应文件或目录是否是绝对路径名;

   boolean createNewFile():当且仅当不存在,创建一个该File对象所指定的新文件,成功返true

   boolean delete():删除File对象所对应的文件或路径;

   boolean mkdir():创建目录

   String [] list ():列出File对象的所有子文件名和路径名

   File[] listFiles():列出File对象的所有子文件和路径。

   static File [] listRoots():列出系统所有的根路径;

2、递归(Recursion)

   是程序调用自身的编程技巧。

   就是在方法里调用自身;在使用递归时,必须有有一个明确的递归结束条件,称为递归出口。

3、文件过滤器java.io.FilenameFileter

   File类里有方法:String[] list(FilenameFileter filter):返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。

   FilenameFilter(文件过滤器)该接口里包含accept(File dir,String name)方法,该方法依次对指定File的所有子目录、子文件夹进行迭代。

   dir –被找到的文件所在的目录。

   name –文件的名称。

   当且仅当该名称应该包含在文件列表中时返回true;否则返回false;

4、  流

数据写入数据可以使一段一段地向数据流管道中写入数据,这些数据会按先后顺序形成一个长长的数据流。

在程序中,所有的数据都是以流的方式进行传输和保存的。Java的IO是实现输入和输出的基础。Java把所有传统的流类型(类或抽象类)都放在java.io包中,用于实现输入和输出功能。输入和输出是一个相对的概念,我们一般是站在程序的角度来分析和处理问题。

程序需要数据-à读进来-à输入

程序保存数据---写进去 -à输出

流的分类:

   从不同角度分类:

按流向不同可以分为:输入流和输出流;

按处理数据的单位不同分为:字节流和字符流;

按功能不同可以分为节点流和处理流;   节点流:即直接操作目标设备,如磁盘和一块内存区域。处理流的存在是建立在一个已经存在的输入流或输出流的基础上的。

5、  操作流的步骤

File类本身是与文件操作有关的,但是想要操作内容则必须使用字节流或字符流完成。不管使用何种的输入输出流,器基本的操作的原理是一样的(以文件流为准):

(1)       使用File类找到一个文件对象,得到IO操作的源或目标;

(2)       使用字节流或字符流的子类创建对象,的到IO操作的通道;

(3)       进行读或写的操作;

(4)       关闭输入、输出流。

       由于流的操作是属于资源操作,所以在操作的最后一定要关闭以释放资源。

计算机访问外部设备,要比直接访问内存慢得多,若我们每次write方法调用都是直接写到外部设备(比如磁盘上的一个文件),CPU就要花费更多的时间去等待外部设备;我们可以开辟一个内存缓存区,程序每一此的write方法都是些到这个内存缓冲区中,只有这个缓冲区装满了之后,系统才将这个缓冲区中的内容一次集中写到外部设备。好处:有效提高了CPU的使用率,write方法并没有马上真正写到外部设备,我们还有机会回滚部分写入的数据;

6.字节流和字符流

  二者仅仅是操作单位不一样。InputStream和Reader是所有输入流的基类,他们都是抽象类,本身不能创建实例,但是他们是所有输入流的模板。一般来说,处理字符或字符串时使用字符流,处理字节或二进制对象时应使用字节流;

备注:字符流必须关闭资源,因为它中间有缓冲区!而字节流不需要,但是一般都会(最后)关闭资源!

字节流

   字节流主要是操作byte(字节)的类型数据;

   字节输出流: OutputStream;

   字节输入流:InputStream;

字符流

   Java中的字符是Unicode编码,是双字节的,1个字符等于2个字节;

   使用字节来处理字符文本就太不方便了,此时可以考虑使用字符流;

   字符流主要是操作 char的类型数据;

   字符输出流:Writer;

   字符输入流:Reader;

字节流和字符流的区别:

   字节流和字符流在使用上的代码结构都是非常类似的,但是其内部本身也是有区别的,因为在进行字符流操作的时候会使用到缓冲区(内存中),而字节流操作的时候是不会使用到缓冲区的。

   在输出的时候,OutputStream类即使最后没有关闭也可以输出。但是如果是Writer的话,则如果不关闭,最后一条内容是无法输出的,因为所有的内容都是保存在了缓冲区之中,每当调用了close()方法就意味着清空缓冲区了。那么可以证明字符流确实使用了缓冲区:

   字节流:程序-à文件;

   字符流:程序-à缓冲区(内存中)--à文件;

总结:

   两者相比,肯定是使用字节流更加方便,而且在程序中图片、MP3等都是采用字节的方式的保存,那么肯定字节流会比字符流使用的更广泛。

   但是需要说明的是:如果是想操作文本文件的话,字符流肯定是最好用的。(若使用字节流可能会出现乱码)

7、  字节--à字符转换流

OutputStreamWriter :把字节输出流对象转成字符输出流对象

InputStreamReader: 把字节输入流对象转成字符输入流对象

FileWriter和FileReader分别是OutputStreamWriter和InputStream的直接子类,而不是Writer和Reader的直接子类,区别于FileInputStream和InputStream。         

十、IO文件操作

   1.内存操作流

操作内存流的时候(从读取出来,注意一定要把真正的数据用toByteArray或toCharArray将数据读出来)。之前的文件操作流是以文件的输入输出为主的,当输出的位置变了内存,那么就称为内存操作流。此时要使用内存流完成内存的输入和输出操作。

如果运行中要产生一些临时文件,可采用虚拟文件方式实现;

直接操作磁盘的文件很耗性能,使用内存流可以提升性能;jdk里提供了内存流可实现类似于内存直接文件的功能。

ByteArrayInputStream:将内容写到内存中    CharArrayReader

ByteArrayOutputStream:将内存中的数据写出   CharArrayWriter

ByteArrayInputStream:构造方法;

public ByteArrayInputStream(byte[] buf) :全部内容

public ByteArrayInputStream(byte[] buf, int  offset,  int length): 指定范围的内容

2、打印流

   PrintWriter 、PrintStream

3、标准流

   标准输入流:System.in   默认表示的是键盘录入

   标准输出流:System.out  默认表示的是屏幕输出

4、  Scanner(简单文本扫描器)

Scanner(File source)构造一个新的Scanner,它生成的值是从指定文件扫描的。实现了Iterable接口。

5、  缓冲流

缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提供了读写的效率,同时增加了一些新的方法。

四种缓冲流:

   BufferedReader(Reader in)

   BufferedReader(Reader in, int size)表示自定义缓冲区大小

   BufferedWriter(Writer out)

   BufferedWriter(Writer out, int  size)

   BufferedInputStream(InputStream in)

   BufferedInputStream(InputStream in,int size)

   BufferedOutputStream(OutputStream out)

   BufferedOutputStream(OutputStream out, int size)

   BufferedReader提供readLine方法用于读取一行字符串。

   BufferedWriter提供了newLine方法用于写入一个分隔符。等价于//.writer(“\r\n”);

   对于输出的缓冲流,写出的数据会先在内存中缓冲,使用flush方法将会使内存中的数据立刻写出。

6、  合并流(SequenceInputStream)

需要两个源文件,还有输出的目标文件。

SequenceInputStream:将两个文件的内容合并成一个文件

SequenceInputStream(InputStream s1, InputStream s2):根据两个字节输入流对象来创建合并流对象。

十一、网络编程

1、  什么是网络编程?

网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机。数据传递本身没有多大的难度,就是把一个设备中的数据发送给另外一个设备,然后接受另外一个设备反馈的数据。现在的网络编程基本上都是基于请求/响应方式的,也就是一个设备发送请求数据给另外一个,然后接收另外一个设备的反馈。在网络编程中,发起连接程序,也就是发送第一次请求的程序,被称作客户端(Client),等待其他程序连接的程序被称作服务器(Server)。客户端程序可以在需要的时候启动,而服务器为了能够时刻响应连接,则需要一直启动。

网络模型

   OSI参考模型

   TCP/IP参考模型

2、  网络通讯要素

IP地址

端口号

传输协议

(1)IP地址:InetAddress

   网络中设备的标识;

   不易记忆,可用主机名;

   本地回环地址:127.0.0.1   ;

   主机名:localhost;

(2)端口号

     用与标识进程的逻辑地址,不同进程的标识;

     有效端口:0~65535,其中0~1024系统使用或保留端口。

     注意:此处端口不是所谓的物理端口!

(3)传输协议

         通讯的规则;

         常见的协议:TCP   UDP

3、  TCP和UDP的联系和用途

(1)区别

二者都是有用的和常用的,如果纯粹从概念上区分二者就比较费解了,我们直接从功能上进行区分,简单明了:

这两种传输协议也就适合于适配不同的业务和不同的硬件终端。

在使用中,类似于文本、程序、文件等要求可靠的数据最好就用TCP,但会牺牲一些速度。

对系统资源的要求:TCP要求较多,UDP要求较少;

程序结构:UDP程序结构较简单,TCP叫复杂。

流模式与数据包模式:TCP保证数据正确性,UDP可能丢包;TCP保证数据顺序,UDP不保证。

(2)、用途

         TCP是面向连接的,有比较高的可靠性,一些要求比较高的服务一般使用这个协议,如FTP、Telnet、SMTP、HTTP、POP3等,而UDP是面向无连接的,使用这个协议的常见服务有DNS、SNMP、QQ等。对于QQ必须另外说明一下,QQ2003以前是只使用UDP协议的,其服务器使用8000端口,侦听是否有信息传来,客户端使用4000端口,向外发送信息(这也不难理解在一般的显IP的QQ版本中显示好友的IP地址信息中端口常为4000或其后续端口的原因了),即QQ程序既接收服务又提供服务,在以后的QQ版本中也支持使用TCP协议了。

   UDP是一种面向无连接的通信协议,该协议使得数据传输的速度得到大幅度的提高。视频聊天语音聊天基本都是使用UDP协议。

总结:

   UDP:

(1)       将数据源和目的地封装到数据包中,不需要建立连接;

(2)       每个数据包的大小限制在64K以内;

(3)       因无连接,是不可靠协议;

(4)       不需要建立连接,速度快。

  例如:聊天、对讲机就是UDP的,面向无连接(不管在不在,知道不知道,只管发送,求速度),对数据也不管,速度快,数据被分成包。

   TCP:

     (1)、建立连接,形成传输数据的通道;

     (2)在连接中形成大量数据的传输;

     (3)通过三次握手完成连接,是可靠协议;

     (4)必须建立连接,效率会稍低。

     例如:电话通话,必须连接,对方同意才可以发送数据(不然就等待),不能丢失数据。

4、  InetAddress与Socket

InetAddress:构造方法私有,不能直接创建对象。

InetAddress getByName(String  host):在给定主机名的情况下确定主机的ip地址。

InetAddress getLocalHost():返回本地主机。

InetAddress[]getAllByName(String host):在给定主机名的情况下,根据系统上配置的名称服务返回其ip地址所组成的数组。

ip.getHostAddress():返回ip地址字符串。

ip.getHostName():获取此ip地址的主机名。

5、UDP传输

  (1)只要是网络传输,必须有socket。

  (2)数据一定要封装到数据包中,数据包中包括目的地的地址、端口、数据等信息。

  直接操作UDP不可能,对于java语言应该讲UDP封装成对象,易于我们的使用,这个对象就是DategramSocket,封装了UDP传输协议的socket对象。

  因为数据包中包含的信息较多,为了操作这些信息方便,也一样会将其封装成对象。这个数据包对象就是:DatagramPacket。通过这个对象的方法,就可以获取到数据包中的各种信息。DatagramSocket具备发送和接收功能,在进行UDP传输的时候,需要明确一个是发送端,一个是接收端。

  UDP的发送端:

(1):建立UDP的socket服务,创建对象时如果没有明确端口,系统会自动分配一个未被使用的端口。

(2):明确要发送的具体数据。

(3):将数据封装成了数据包。

(4):用socket服务的send方法将数据包发送出去。

(5):关闭资源。

  UDP的接收端:

(1)       创建UDP的socket服务,必须要明确一个端口,作用在于,只有发送到这个端口的数据才是这个接收段可以处理的数据。

(2)       定义数据包,用于存储接收到的数据。

(3)       通过socket服务的接收方法将接收到的数据存储到数据包中。

(4)       通过数据包的方法获取数据包中的数据内容,比如ip、端口、数据等。

(5)       关闭资源。

6、TCP传输

     两个端点的建立连接后会有一个传输数据的通道,这通道称为流,而且是建立在网络基础上的流,称之为socket流,该流中既有读取,也有写入。

TCP的两个端点:一个是客户端,一个是服务端。

客户端:对应的对象,Socket;

服务端:对应的对象,ServerSocket;

TCP客户端:

(1)       建立TCP的socket服务,最好明确具体的地址和端口。这个对象在创建时,就已经可以对指定的IP和端口进行连接(三次握手);

(2)       如果连接成功,就意味着通道建立了,socket流就已经产生了。只要获取到socket流中的读取刘和写入流即可,只要通过getInputStream和getOutputStream就可以获取两个流对象。

(3)       关闭资源。

TCP服务端:

(1)       创建服务端socket服务,并监听一个端口。

(2)       服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象。

(3)       可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。

(4)       如果通讯结束,关闭资源。注意:要先关客户端,再关服务端。

注意:对于UDP和TCP,既可以定义输出流也可以定义输入流,具体情况根据需要构建;比如:我们需要客户端给服务端发送数据,服务端再给客户端反馈数据;那么就要在客户端和服务端分别多加一个输入流和输出流,否则,发不出去,收不到。

十二、反射机制

1、反射的概念

      反射的引入:

        Object obj=new Student();

        若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:

(1)       若编译和运行类型都知道,使用instanceof判断后,强转。

(2)       编译时根本无法预知该对象属于什么类,程序只能靠运行时信息来发现对象的真实信息,这时就必须使用反射了。

(3)       要是想要得到对象真正的类型,就得使用反射。

什么是反射机制?

  简单的说,反射机制指的就是程序在运行时能够获取自身的信息,在java中,只要给定类的名字,那么就可以通过反射机制来获取类的信息。

静态编译:在编译时确定类型,绑定对象,即通过。

动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的耦合性。

反射机制的优点和缺点:

  反射机制的优点是:可以试想动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。

  反射机制的缺点是:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

Class类和Class类实例

   Java程序中的各个java类属于同一类事物,描述这类事物的java类就是Class类。

一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同类的字节码是不同的,所以他们在内存中的内容是不同的;

用类来描述对象,类就是描述数据的结构。

用元数据来描述Class,MetaData(元数据)就是描述数据结构的结构;

反射就是得到元数据的行为;(一个类在虚拟机中只有一份字节码)。

2、获得Class对象

   每个类被加载后,系统会为该类生成对应的Class对象,通过Class对象可以访问到JVM中的这个类。有三种方式:

(1)       调用某个类的class属性获取Class对象,如:Data.class会返回Data类对应的Class对象(其实就是得到一个类的一份字节码文件);

(2)       使用Class类的forName(String className)静态方法,className表示全限定名;如:String的全限定名:java.lang.String;

(3)       调用某个对象的getClass()方法。该方法属于Object类;

3、九个预定义Class对象

   基本的java类型(boolean、byte、char、short、int、long、float和double)和关键字void通过class属性也表示为Class对象;

   Class类中boolean isPrimitive():判定指定的Class对象是否表示一个基本类型。

   包装类和Void类的静态TYPE字段:

      Integer.TYPE=int.class;

      Integer.class=int.class;

   数组类型的Class实例对象:

      Class<String[]> clazz=String[].class;

   通过比较数组的维数和数组的类型,可以比较两个数组的Class对象是否相等;

   Class类中boolean isArray():判定此Class对象是否表示一个数组类型。

5、  Class中得到构造方法Constructor、方法Method、字段Field

常用方法:

   Constructor类用于描述类中的构造方法:

Constructor<T> getConstructor(Class<?>…parameterTypes):返回该Class对象表示类的指定的public构造方法;

Constructor<T> [] getConstructors():返回该Class对象表示类的所有public构造方法;

Constructor<T> getDecalaredConstructor(Class<?> …parameterTypes):返回该Class对象表示类的指定的构造方法,和访问权限无关;

Constructor<?>[] getDeclaredConstructors():返回该Class对象表示类的所有构造方法,和访问权限无关;

          Method类用于描述类中的方法:

           Method getMethod(String name,Class<?> …parameterTypes):返回该Class对象表示类和其父类的指定的public方法;

           Method[] getMethods():返回该Class对象表示类和其父类的所有public方法;

           Method getDeclaredMethod(String name,Class<?>…parameterTypes):返回该Class对象表示类的指定的方法,和访问权限无关,但不包括继承的方法;

           Method[] getDalcaredMethods():获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;

6、  利用反射创建对象  

创建对象:

(1)       使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参的构造方法。

(2)       使用Class对象获取指定的Costructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。 如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true;

使用指定的构造方法来创建对象的方式:

(1)       获取该类的Class对象;

(2)       利用Class对象的getConstructor()方法来获取指定的构造方法。

(3)       调用Constructor的newInstance()方法创建对象。

Accessible Object对象的setAccessible(boolean flag)方法,当flag为true的时候,就会忽略访问权限(可访问私有的成员)。 其子类有Field、Method、Constructor;若要访问对象的private成员,在调用之前使用setAccessible(true),Xxx x=getDeclaredXxxx();可以得到私有的类字段 。

总结步骤:

(1)    获取该类的Class对象;

(2)    利用Class对象的getConstructor()方法来获取指定的构造方法;

(3)    申请访问(设置为可访问);

(4)    调用Constructor(构造方法)的newInstance()方法创建对象。

7、  使用反射调用方法

每个Method的对象对应一个具体的底层方法。获得Method对象后,程序可以使用Method里面的invoke方法来执行该底层方法。

Object invoke(Object obj,Object …args):obj表示调用底层方法的对象,后面的args表示传递的实际参数。

如果底层方法是静态的,那么可以忽略指定的obj参数。该参数可以为null。

8、  使用反射调用可变参数方法

使用反射操作对象-调用可变参数方法。

要把可变参数都当做是其对应的数组类型参数。

若可变参数类型是引用类型:JDK内部接收到参数之后,会自动拆包取出参数再分配给该底层方法,为此我们需要把这个数组实参先包装成一个Object对象或把实际参数作为一个Object一维数组的元素再传递。

若可变参数元素类型是基本类型:JDK内部接收到参数之后,不会拆包,所以可以不必再封装。但是封装也不会出错。所以建议不管基本类型还是引用类型都使用Object[]封装一层,保证无误。

相关推荐