Java:
1、一种跨平台面向对象的程序设计语言。
2、1995年由Sun公司推出,Java之父是詹姆斯-戈士林(博士),Java最初名字为OAK,1995年后改为Java。
3、Java通过解释方式来执行,与C++语法类似
4、Java语言编写的程序既是编译型的,又是解释型的:Java程序代码经编译后转换为Java字节码的中间语言,Java虚拟机(JVM)对字节码进行解释和运行后以机器码形式存在,然后由计算机来执行。编译只进行一次,解释在每次运行程序时都执行。这也是JVM的工作原理:
Java版本:
Java按应用范围划分,分为三个版本:JavaEE、Java SE、Java ME
JavaEE:Java的标准版,主要用于桌面应用程序开发,是Java的基础,包含Java语言基础、JDBC、IO、网络通信、多线程等
JavaSE:Java的企业版,开发企业级分布式网络程序,核心是EJB(企业Java组件模型)
JavaME:嵌入式系统开发
API:
ApplicationProgramming Interface(应用程序编程接口),主要包括类的继承结构、成员变量、成员方法、构造方法、静态成员的详细说明和描述信息。
Java语言特点:
1、 简单:如Java使用接口替代了多重继承,并取消了指针,Java实现垃圾自动回收
2、 面向对象:面向对象是Java语言的基础,Java语言最外部的数据类型是对象,所有元素都需要通过类和对象来访问。
3、 分布性:包括操作分布和数据分布。操作分布:在多个不同主机上布置操作;数据分布:将数据存放在不同主机上
4、 可移植性:与平台无关,只要有JVM环境就可运行
5、 解释型:解释执行
6、 安全性:如Java语言删除了类似C语言中的指针和内存释放等语法,有效避免了非法操作内存
7、 多线程:使应用程序同一时间执行多项任务,且对应的同步机制使不同线程正确共享数据
8、 健壮性
9、 高性能
10、 多态
JDK安装:
JDK安装时会安装JRE,JRE全称Java Runtime Environment,是Java运行环境,负责Java程序的运行,而JDK不仅包括JRE,还包括Java程序开发所需的编译、测试环境和JDK源码
JDK安装完成后要配置环境变量:
新建系统变量:JAVA_HOME,为JDK安装路径
修改系统变量:PATH,在最前面加上.;%JAVA_HOME%\bin;
然后通过 开始》运行》javac 检测环境是否配置成功
JAVA程序运行:
开始》运行》javac xxx.java
.java为编译前的java类文件
.class为编译后的java字节码文件
IDE:集成开发工具
Eclipse:IBM公司开发,已开放源代码,平台体系结构是在插件基础上构建的
Eclipse中的透视图:Eclipse工作台提供的附加组织层,可以简单理解为多个视图的组织结构
Eclipse编辑器字体:窗口》首选项》常规》外观》颜色和字体》Java/Java编辑器字体,可以更改为Courier New(若在电脑的控制面板字体中找不到该字体,可网上下载;若有该字体但未显示出来,则更改电脑中该字体的设置信息,默认为“隐藏”,改为”显示”)
Eclipse调试:
F8运行或启动调试
F6:单步跳过(不进方法内部)
F5:单步跳入(进方法内部)
注:Java编译器每次遇到断点,都会将当前线程挂起,即暂停当前程序的执行
Java语言基础
Java语言是面向对象的程序设计语言,基本组成单元是类,类包括属性和方法两部分,每个程序都有一个main方法的主类,Java语言严格区分大小写。
类文件名和类名必须一致,当Java类文件包括多个类时,只能有一个public的类,且public的类名必须跟文件名一致,大小写也要一致
package为包的关键字,一般在类的最上方
继承类的关键字为extends
继承接口的关键字为implements
引用其他类的关键字为import
Java程序中的main方法必须声明为public staticvoid main
通常将类的属性称为类的全局变量或成员变量
将方法的属性称为局部变量
Java中的基本数据类型:
Java中共有8种基本数据类型,用以存放数值、字符和布尔值,这8种基本数据类型为:
char,boolean,byte,short,int,long,float,double
不能以0作为十进制数的开头(0除外)
八进制必须以0开头(从右向左计算,满8前一位进1)
十六进制必须以0X或0x开头(从右向左计算,满16前一位进1)
对于long型值,若赋给的值大于int型的最大值或小于int型的最小值,即赋值不在int型范围中,在赋值的最后必须加l或L进行标识;赋值也在int型范围中时,可不加
默认情况下,小数为double型,若使用float型小数,需要在小数后加F或f标识
字符类型为char,存储单个字符,占16位的内存空间,以单引号表示;String类声明的是字符串,以双引号表示,字符串不是基本数据类型
同c和c++一样,Java语言也可以把字符作为整数对待,如char a=97; unicode编码采用无符号编码,可以存储65536个字符(0x0000~0xffff),所以Java中的字符几乎可以处理所有国家的文字,如汉字;通过显示转换,可以进行字符与unicode表中对应数值的相互转换,如char a=’a’;int i=(int)a;
char b=(char)i;
各类型内存中所占空间如下:
转义字符:
转义字符是一种特殊的字符变量,以反斜线(\)开头,将转义字符赋值给字符型变量时,同字符型变量赋值,char a=’//’;
Java中的布尔类型的值,不能与整数类型相互转换;其他语言在转换时,0(啥都没有)为false,1为true
变量与常量
变量与常量的命名都必须使用合法的标识符
标识符:标识符可以简单理解为一个名字,由字符、下划线(_)、美元符号($)和数字组成,且第一个字符不可为数字,标识符也不能为Java中的关键字
常量(constant):在整个程序中只能被赋值一次,不可更改;
以final关键字标识常量,常量名一般使用大写字母,当常量为成员变量时,必须在定义时就赋值
成员变量:亦称全局变量,类体中定义的变量,分为实例变量和静态变量;静态变量前加static关键字,可通过类名.静态变量名 调用;实例变量必须通过实例名.实例变量名 调用。
局部变量:方法中定义的变量,当局部变量和成员变量名字相同时,方法中有效的是局部变量,且方法中对变量值的修改,不会影响到成员变量
运算符
自增自减运算符:如int i=4;int a=i++;//a为4,i为5
int b=++i;//b为5,i为4
逻辑运算符:
包括逻辑与(&&和&)、逻辑或(||)、逻辑非(!)
&&:从左向右判断,第一个为false,则不再判断第二个
&:从左向右判断,两个都要判断(&可读作and)
位运算
内存中二进制数最右边为符号位,0为正,1为负,整数在内存中都为二进制,负数采用补码表示,如8和-8
8:00000000 00000000 0000000000001000
-8:11111111 1111111111111111 1111000
按位与运算:运算符为&,相同位都为1,才为1,如4&6
按位或运算:运算符为|,相同位存在1即为1,否则为0
按位取反运算:运算符为~,位上为1则取0,为0取1,如~7
按位异或运算:运算符为^,相同位相同为0,否则为1,如5^7
移位操作:
运算符<<,左移,右侧空位补0,如2<<3,2左移3位值为16
运算符>>,右移,当最高位为0,左侧空位补0,否则补1
运算符>>>,无符号右移,不分正负数,左侧空位直接补0
三元运算符:条件式?值1:值2 当条件式为true,取值1,否则取值2
运算符的优先级:
数据类型转换:
隐式转换:低精度转成高精度,不会失败
显式转换:高精度转低精度,强制进行转换,精度会丢失,若超出低精度类型的取值范围,会造成转换的值不正确
数据类型精度由低到高:
byte<short<int<long<float<double
其中char可以往int及其后转换
程序注释:
//当行注释
/* … */ 多行注释,多行注释中可嵌套单行注释,但不可嵌套多行注释
/** … */ 文档注释
复合语句:{}及其中包含的语句,如可将类中某段代码放入{}中
switch多分支语句:
语法:
switch(表达式)
{
case常量值1:语句块;break;
case常量值2:语句块;break;
…
Default:语句块;break;
}
switch语句中,表达式的值必须为整型、字符型,在jdk1.7中还允许为字符串,当与常量值有匹配后,执行后面语句块且碰到break后才会跳出,所以要在语句块后进行break,避免执行其他常量对应的语句块,常量值可为整型,不可为小数。
while循环语句和do..while循环语句
while(条件表达式)
{
执行语句;
}
while语句,循环判断条件表达式是否为true,为true一直反复执行,直到为false,退出执行;先判断条件表达式,再确定是否去执行,注意while(条件表达式)后无分号,多加了分号,会无限循环。
do
{
执行语句;
}
whilie(条件表达式);
do..while语句,先执行一次,然后判断条件表达式,表达式为true继续执行,为false停止执行,注意while(条件表达式)最后有分号结束。
for循环:
语法:
for(初始化表达式;循环条件表达式;循环后操作表达式)
{执行语句;}
for循环有种特殊的形式可进行无限循环,可使用break在满足特定条件后,跳出循环
for(;;)
{
if(x>20)break;
x++;
}
***两个相邻但不嵌套的for循环可以定义相同的变量,嵌套的for循环不可以定义同名变量。
foreach语句
foreach语句是for语句的特殊简化版本,可用于遍历数组,还是使用的for关键字,语法:
for(元素变量 x:变量对象obj)
{执行语句;}
字符串
在Java语言中将字符串作为对象来处理,可以通过java.lang包中的String类来创建字符串对象(new String)
String类的构造方法:
1、String(char a[])如char a={‘n’,’i’};Stringstr=new String(a);
2、String(char a[],intoffset,int length)
Offset数组中开始截取的位置,length截取长度
Stringstr1=”wo”;
Stringstr2=”wo”;
此时str1和str2引用相同的字符串常量,因此具有相同的实体。
Java中一个引号下的字符串只能写在同一行,当字符串通过+号与其他数据类型连接时,会将这些数据自动转成字符串,然后再连接。
字符串查找
计算机中String对象是用数组表示的,所以下标从0开始
str.indexOf(substr)查找substr在str中首次出现的索引位置
str:任意字符串
substr:要搜索的字符串
方法返回值为int,查不到返回-1
str.indexOf(“”)返回0
str.lastIndexOf(substr)查找substr在str中最后一次出现的索引位置
str:任意字符串
substr:要搜索的字符串
方法返回值为int,查不到返回-1
str.lastIndexOf(“”)返回str的长度
获取字符串中指定索引位置的字符:
charc=str.charAt(int index);
字符串截取:
str.substring(intbeginIndex)
从指定索引位置(包含)开始截取直到该字符串结尾
str.substring(intbeginIndex,int endIndex)
从指定索引位置(包含)开始截取至指定索引位置(不包含)
字符串替换:
str.replace(charoldChar,char newChar)
参数可为char,也可以为String
替换的字符区分大小写
判断字符串的开始和结尾
str.startsWith(Stringprefix)
判断字符串是否以指定的内容开始,返回值为boolean
str.endsWith(Stringsuffix)
判断字符串是否以指定的内容结束,返回值为boolean
判断字符串是否相等:
字符串之间的比较,不能简单的使用比较运算符==,这是比较的两个字符串的内存地址,而不是比较的内容,比较内容使用str.equals(Stringotherstr)或str.equalsIgnoreCase(Stringotherstr),前者比较内容时区分大小写,后者不区分
str.compareTo(Stringotherstr) 按字符串中各个字符的unicode编码序号来比较字符串内容,若相等返回0
字符串大小写转换
str.toLowerCase() 转小写
str.toUpperCase() 转大写
字符串分割
split(Stringsign)
根据指定的分隔符对字符串拆分成String数组
split(Stringsign,int limit)
根据指定的分隔符对字符串进行拆分,并限制分割次数为limit,如”a,b,c,d”按,拆分两次为a, b,c,d
格式化字符串
String类的静态方法format用于创建格式化的字符串
format(Stringformat,Object…args)
日期和时间字符串格式化
Datedate=new Date();
Stringsdate=String.format(“%te”,date);
常用的日期和时间格式化转换符如下:
转换符 | 说明 | 示例 |
%tb | 指定语言环境的月份简称 | Feb(英文)、二月(中文) |
%tB | 指定语言环境的月份全称 | February、二月 |
%ta | 指定语言环境的星期几简称 | Mon、星期一 |
%tA | 指定语言环境的星期几全称 | Monday、星期一 |
%tc | 包括全部日期和时间信息 | 星期二 三月 25 11:11:11 CST 2005 |
%ty | 两位年份 | 05 |
%tY | 4位年份 | 2005 |
%tm | 月份 | 03 |
%td | 一个月中的第几天,日期 | 02 |
%tH | 两位数字的24时制的小时 | 02 |
%tI | 两位数字的12时制的小时 | 11 |
%tM | 2位数字的分钟 | 05 |
%tS | 2位数字的秒数 | 06 |
%tF | “年-月-日”格式(4位年份) | 2011-01-01 |
%tD | “年/月/日”格式(2位年份) | 13/01/01 |
%tr | “时:分:秒 PM(AM)”(12小时制) | 03:02:06 PM |
%tT | “时:分:秒”(24小时制) | 13:12:11 |
%tR | “时:分”(24小时制) | 15:30 |
正则表达式
正则表达式通常用于判断语句中,用来检查某一字符串是否满足某一格式,正则表达式是含有一些具有特殊意义字符的字符串,这些特殊意义字符称为正则表达式的元字符
元字符 | 正则表达式中的写法 | 意义 |
. | . | 代表任意一个字符 |
\d | \\d | 代表0~9的任意一个数字 |
\D | \\D | 代表任何一个非数字字符 |
\s | \\s | 代表空白字符,如’\t’,’\n’ |
\S | \\S | 代表非空白字符 |
\w | \\w | 代表可用作标识符的字符,但不包括$ |
\W | \\W | 代表不可用作标识符的字符 |
\p{Lower} | \\p{Lower} | 代表小写字母a~z |
\p{Upper} | \\p{Upper} | 代表大写字母A~Z |
| [abc]4 | a4,b4,c4都能匹配 |
| [^456] | 代表4,5,6之外的任意字符 |
| [a~r] | 代表a~r中的任意一个字符 |
| [a~zA~Z] | 可代表任意一个英文字母 |
| [a~e[h~m]] | 代表a~e或h~m中的任意字母(并集) |
| [a~d&&[b~c]] | 代表b,c(交集) |
|
|
|
限定修饰符 | 意义 | 示例 |
? | 0次或1次 | A? 代表A可以在字符串中出现0次或1次 |
* | 0次或多次 | A* |
+ | 1次或多次 | A+ |
{n} | 正好出现n次 | A{2} |
{n,} | 至少出现n次 | A{2,} |
{n,m} | 出现n~m次 | A{2,6} |
正则表达式中.代表任意字符,想使用.时,用转义符,如\\.
可变字符序列(实现可变长度字符串)
创建成功的字符串对象,长度是固定的,内容不会改变和编译,当使用+修改内容时,是产生一个新的String实例,故频繁修改字符串内容,会加大系统开销,使用StringBuilder实现频繁变动字符串内容,包含append(),insert(int offset,””),delete(intstart,int end)等方法
数组
数组声明有下列两种方式:
数组元素类型 数组名字[];(如int iarr[]这种方式较常用)
数组元素类型[] 数组名字;
为数组分配内存空间:
intiarr[]=new int[5];
整型数组默认初始值都为0
数组初始化的方式:
inta[]=new int[]{1,2,3};([]里不能再定义长度的)
inta[]={1,2,3};
java.util包的Arrays类中包含了操作数组的各种方法
替换数组元素:
Arrays.fill(inta[],int value)将数组每个元素都替换为value
Arrays.fill(inta[],1,3,int value)将数组a中下标为1(包括)至下标为3(不包括)的项替换成value
数组排序
Arrays.sort(intiarr[]);从小到大进行排序
复制数组
Arrays.copyOf(arr,intnewlength)
arr:要进行复制的数组
newlength:复制后的新数组长度,若大于原数组长度,整型数组用0填充,字符型用null填充
Arrays.copyOfRange(arr,intfromIndex,int endIndex)
arr:要复制的数组
fromIndex:复制开始的索引位置,包括该索引
endIndex:复制结束的索引位置,不包括该索引,开大于原数组长度
***当声明好一个数组后,这个数组的长度就是固定的了,数组不提供直接增加新元素的方法,可以新建个数组,长度比这个数组长度大1,然后复制该数组,修改最后一项的值。
数组查询
Arrays.binarySearch(arr,ifrom,iend,key)
arr:查找的数组
ifrom:从该索引开始查找(包括),该参数可省略
iend:至该索引结束查找(不包括),该参数可省略
key:要查找的项,当该项与数组中的某一项一样时,返回索引,否则返回-1或插入点,是与数组中的项一样,不是包括字符就行,可判断返回值是否大于-1
类
类:实质上就是封装对象属性和行为的载体
对象:是类抽象出来的一个实例
类中对象的行为是以方法的形式定义的
类中对象的属性是以成员变量的形式定义的
封装是面向对象编程的核心思想,以类为载体将对象的属性和行为封装起来,且通常因此实现的细节,保证了内部数据结构的完整性,便于维护。
继承性主要是利用特定对象之间的共有属性,进行复用。
将父类对象应用于子类的特性就是多态?
权限修饰符:
Java中的权限修饰符包括:private,protected,public
当类不写权限修饰符时,默认为protected,即同一个包下的其他类或同一个包下的子类可以访问这个类,另外类的修饰符会约束类中变量的修饰符,变量修饰符为public的protected类,也相当于protected
访问包位置 | Private | protected | public |
本类 | 可见 | 可见 | 可见 |
同包下的其他类或子类 | 不可见 | 可见 | 可见 |
其他包下的类或其他包下的子类 | 不可见 | 不可见 | 可见 |
this关键字代表本类对象的引用,当方法返回类型为本类的对象时,this还可以作为返回值,返回类的对象。
构造方法:
对象的创建是通过构造方法来完成的,每当类实例化一个对象时,类就会调用相应的构造方法。构造方法无返回值,名称必须与类名一样,构造方法的修饰符一般都是public。
如果在类中定义的构造方法都是有参的构造方法,编译器不会为类设置一个默认的无参构造方法,只有当类中不定义任何构造方法时,编译器才会为类自动创建一个无参构造方法。在无参构造方法的第一句,必须是第一句,有this关键字可调用有参的构造方法,如this.(“”);在new对象时,根据有无参数,只运行对应的构造方法。另外,当类中存在static静态区域时,new对象后先运行static静态区域,再运行对应构造方法,static静态区域语法:
static{执行语句;}
静态方法
以static关键字修饰的变量、常量和方法称为静态成员,直接通过类名.静态成员 进行使用,不建议对象.静态成员使用,这样容易混淆静态成员和非静态成员。静态成员同样受权限修饰符public等的约束。
Java中对静态方法规定如下:
静态方法中不可以使用this关键字
静态方法中不可以直接调用非静态方法(new对象后,对象.方法调用)
*Java中规定不能将方法体中的局部变量声明为static
对象
Java语言中使用new操作符调用构造方法创建对象,对象被创建出来时,就是一个对象的引用,这个引用在内存中为对象分配了内存空间。引用只是存放对象的内存地址,并非存放一个对象。
当成员变量被声明为static时,若一个实例改变变量值,其他实例对应的该变量值自动变。
对象的比较有两种方式,==运算符和equals()方法,==运算符比较的是两个对象引用的地址是否相等;equals()方法比较的是两个对象引用所指的内容是否相等,如String s1=new String(“s”);
Strings2=new String(“s”);String s3=s1;则s3==s1;s1.equals(s2)结果为true。
Java拥有一套完整的垃圾回收机制,垃圾回收器将回收无用的但占用内存的资源,被Java虚拟机视为垃圾的情况如下:
1、对象引用超过其作用范围,如方法中创建了对象,方法外回收
2、将对象赋值为null,如String str=new String(“c”);
str=nul;
垃圾回收器只能回收那些由new操作符创建的对象,如果某些对象不是通过new操作符在内存中获取一块内存区域,这种对象可能不能被垃圾回收机制所识别,所以Java提供了一个finalize()方法,它是object类的方法,声明为protected,当用户在类中定义了finalize()方法,在垃圾回收时会首先调用该方法,在下一次垃圾回收动作发生时,才能真正被回收。垃圾回收或finalize()方法清理垃圾时间不确定,也不保证一定会发生,如虚拟机内存损耗殆尽。此外,Java提供了System.gc()方法强制启动垃圾回收器,告诉垃圾回收器进行清理。
包装类
Java中不能定义基本类型(primitive type)对象,为了能将基本类型视为对象进行处理,并能连接相关的方法,Java为每个基本类型都提供了包装类,如int的包装类Integer,通过包装类就可以基本类型转换为对象处理了,Java可以直接处理基本类型,但有些情况下需要将其视为对象处理时,就需要转换为包装类了,如Integer int=new Integer(inti)。
数字处理类
如DecimalFormat类(用于格式化数字),
Math类(为各种数学计算如三角函数方法等提供工具方法),
Random类(处理随机数),
BigInteger类(针对大整数的处理类),
BigDecimal类(针对大小数的处理类)
Java中没有格式化的数据默认遵循以下原则:
若数据绝对值在0.001和10000000之间,Java以常规小数显示
若数据绝对值不在0.001和10000000之间,使用科学计数法表示
Java中使用java.text.DecimalFormat对浮点数据进行格式化操作,格式化操作根据格式化模板进行格式化,组成格式化模板的特殊字符中0,#较常用,0表示数字,若该位不存在数字显示0;#表示数字,若该位不存在数字,则不显示。
格式化有两种方式:
Math类中提供了很多数学函数方法,如三角函数方法,指数函数方法,取整函数方法,取最大值、最小值、平均值的函数方法等,这些方法都定义的是static的,此外还有一些常量,如PI,E等
比较常用的方法:
doublesqrt(double a):取a的平方根,a不能为负值
doublecbrt(double a):取a的立方根
double pow(doublea,double b):取a的b次方
doubleceil(double a):返回大于等于参数的最小整数
doublefloor(double a):返回小于等于参数的最大整数
doublerint(double a):返回与参数最近的整数,若同样接近,返回偶数
int round(floata):四舍五入取整数
int abs(int i):取绝对值
随机数
Java中提供了两种方式产生随机数:Math类的random()方法和Random类
Math类的random()方法默认生成大于等于0小于1的double型随机数,进行处理后可产生任意范围的随机数,如:
inti=(int)(2+Math.random()*30);产生2~32之间的随机数
(char)(char1+Math.rondom*(char2-char1+1))可用于产生任意字符间的随机字符
Math.random()产生的随机数,是通过当前时间作为随机数生成器的参数,经过复杂运算得到的数,也可以理解为伪随机数。
实例化Random对象创建随机数生成器,当调用无参构造方法实例化时,Java编译器以系统时间作为随机数生成器的种子,也可以设置生成器种子进行实例化,Random类提供了获取各种数据类型随机数的方法如:
int nextInt(10):返回一个大于等于0小于10的随机整数
doublenextDouble():返回随机double型值
java.math.BigInteger类用于处理大整数,需要实例化后进行处理(带参构造方法实例化),常用方法如下:
BigIntegeradd(BigInteger val):加法运算
BigIntegersubtract(BigInteger val):减法运算
BigIntegermultiply(BigInteger val):乘法运算
BigIntegerdivide(BigInteger val):除法运算
BigIntegerremainder(BigInteger val):取余运算
java.math.BigDecimal类处理大小数,支持任意精度的小数,带参实例化后使用,除了加,减,乘法外,除法比较特殊,可设置保留的小数位
BigDecimaldivide(BigDecimal bd,int scale,int imode)
db:除数
scale:小数点后小数位数
imode:处理模式,如BigDecimal.ROUND_HALF_UP该参数就是对商进行四舍五入处理。
接口、继承和多态
继承机制的使用可以复用一些定义好的类,减少重复代码
多态机制的使用可以动态调整对象的调用,降低对象之间的依存关系
Java中使用extends关键字来标识两个类的继承关系,(使用implements关键字标识类继承接口,最多只能直接继承一个类,但可同时继承多个接口)
即可以在子类的构造方法中使用super()语句调用父类的构造方法,也可以在子类中使用super().成员方法()调用父类的成员方法,但子类没有权限调用父类中被修饰为private的方法,只可以调用父类中修饰为public或protected的成员方法
子类继承父类时,可以重写父类中的成员方法,将方法名保留,重写方法的:
实现内容、
更改方法的存储权限(子类重写父类方法时,修饰符权限只能从小范围到大范围改变)、
修改返回值类型(j2se5.0以上支持,重写后的返回值类型是父类方法返回值类型的子类,如父类返回父类实例,子类可返回子类实例)
重构:继承关系中一种特殊形式的方法重写,子类和父类的成员方法返回值,方法名称,参数类型及个数完全相同,唯一不同的是方法实现内容,这种重写即是重构
在实例化子类对象时,Java编译器会在子类的构造方法中自动调用父类的无参构造方法。子类构造方法中使用super()调用,可省略不写,(可使用super(参数)修改为调用父类有参构造方法,不再调用无参构造方法,调用构造方法的顺序是顶级父类,然后是上一级父类,然后是子类,也就是在实例化子类对象时首先要实例化父类对象,然后在实例化子类对象)
使用finalize()方法对对象进行清理,需要确保子类的finalize()方法的最后一个动作是调用父类的finalize()方法。
Java中所有的类都直接或间接继承java.lang.Object类,该类可以说是所有类的父类
在Object类中主要包括clone(),finalize(),equals()(比较内容是否一致),toString()等方法,其中常用的是equals()和toString()方法,Object类中的这些常用方法都可以被重写;Object类中的getClass(),notify(),notifyAll(),wait()等方法不能被重写,因为这些方法被定义为final。
getClass()方法是Object类定义的方法,它会返回对象执行时的Class实例,然后使用此实例调用getName()方法可以取得类的名称
当一个类重写toString()方法后,直接输出new 类名()时,会自动调用重写的toString()方法中的内容,不重写toString()方法,输出的是类实例转换的一些代码(数字字母组成的一串码)
对象类型的转换包括向上转型和向下转型操作
向上转型:就是把子类对象赋值给父类实例。向上转型就是把具体类转换成较抽象的类,它总是安全的
向下转型:把父类对象赋值给子类实例。向下转型将较抽象类转换为较具体类,它是不安全的,向下转型时要使用instanceof操作符判断父类是否为子类对象,判断成功后再使用显示类型转换进行强制转换类型。如果直接进行显示类型转换,不使用instanceof,可能会转换失败,抛出ClassCastException异常。
instanceof语法格式:
父类实例 instanceof 子类类名(注意一个是父类实例,一个是子类类名)
返回值为布尔值,instanceof为Java中关键字,都为小写。
没有继承关系的两个类使用instanceof时,编译器无法通过,提示类型不兼容。
重载:(方法的重载起源于构造方法,)方法的重载就是同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数,参数类型,参数(类型)顺序不同即可,跟返回值无法。
编译器利用方法名,方法各参数类型,参数个数,参数顺序来确定类中方法是否唯一。
方法名(参数类型…参数名称)(如Test(int…A)),表示该方法中参数为不定长参数,编译器会将不定长参数(int…A)看作是数组(int[]A)
多态:多个类继承与一个父类,通过实例化子类以达到调用父类同一方法进行对应操作而不必在各个子类中分别实现这一方法,避免代码的重复。(对所有子类对象进行通过的处理)
(多态,如父类某方法参数为父类类型,父类实例调用该方法时可传入不同的子类实例,方法中判断传入的子类类型进行对应处理)
抽象类
抽象类:使用abstract关键字定义的类为抽象类,抽象类不可以被实例化对象,抽象类中可以包含抽象方法和非抽象方法,抽象方法没有方法体,只要类中存在抽象方法,该类就要被标记为抽象类,承载抽象方法的抽象类必须被继承,实际上抽象类除了被继承外没有任何意义;抽象类被继承后需要实现其中所有的抽象方法,也就是保证相同的方法名称,参数列表和相同返回值类型创建出非抽象方法(或抽象方法),继承抽象类的所有子类需要将抽象类中的所有抽象方法进行覆盖。
抽象方法存在的类必须被标识为抽象类,抽象类中的非抽象方法可以有方法体
接口
接口:接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体
接口中定义的方法必须被定义为public或abstract形式,private和protected权限修饰符不被Java编译器认可,即使不将方法声明为public形式,它也是public的,(其中abstract可写可不写),在接口中定义的字段都自动是static和final的
Java中无论是将一类向上转型为父类对象,还是向上转型为抽象父类对象,或者向上转型为该类实现的接口,都是可以。(转型为接口并调用存在于接口中的方法时,执行转型子类的中覆盖的该方法)
接口和抽象类的区别:
1、 抽象类可以有构造方法,接口不可以
2、 抽象类可以有普通成员变量,接口中所有成员变量都是public staticfinal,即接口中所有成员变量都是静态常量
3、 抽象类中可以包含抽象方法和非抽象方法,接口中所有方法都是抽象的
4、 抽象类中的抽象方法修饰符可以是public或protected,接口中抽象方法修饰符只能是public,并且默认即为public abstract类型
5、 抽象类中可以包含静态方法,接口中不能包含静态方法
6、 抽象类和接口中都可以有静态成员变量,抽象类中静态成员变量修饰符可任意,接口中只能是public的
7、 一个类只能继承一个抽象类,但可同时实现多个接口
类的高级特性
Java中提供了一个管理类文件的机制,就是类包。
只要保证同一类包中的类不同名,就可以有效避免同名类冲突的情况,对于同一个类包的类而言,当同一个类文件中存在多个类的这种不规范的情况,这些类名都不能与包中的其他类名一样;但是某个类中的内部类(如成员内部类)可以与包中的其他类名相同。
同一个包中的类相互访问时,可以不指定包名;同一个包中的类不必存放在同一个位置,如可以放置在不同磁盘中,只要将CLASSPATH分别指向这两个位置即可。
在实际开发中,应该为所有的类设置包名,在类中指定包名时需要将package表达式放置在程序的第一行,它必须是文件中的第一行非注释代码;Java包的命名规则是全部使用小写字母,Java中定义包名时通常使用创建者的Internet域名的反序。
如果一个类定义中已经导入了com.lzw.Math类,在类体中再使用其他包中的Math类时,就必须写完整的带有包格式的类名(如java.lang.Math)
当使用import指定了一个包中的所有类时,并不会指定这个包的子包中的类,若需使用子包中的类,需要再单独引用子包中的类。
使用Eclipse编译器,并在创建项目时设置了源文件与输出文件的路径,编译后的类文件会自动保存在输出文件的路径中。
如果不能在程序所在的根目录下使用javac.exe命令,注意在path环境变量中设置Java编译器所在的位置,假如是c:\Java\jkd1.6\bin,可以使用setpath=c:\Java\jdk1.6\bin;%path%命令在dos中设置path环境变量。
import关键字除了导入包之外,还可以导入静态成员,这是JDK5.O以上版本提供的新功能,如导入java.lang.System类的out这个静态成员变量,在类中可以使用out.println(“”);
final
通常由final定义的变量为常量,且final关键字定义的变量必须在声明时对其进行赋值,声明赋值后再改变变量的值,编译器不接受,final不仅可以定义变量,还可以定义引用,当一个对象引用被修饰为final后,它只能恒定指向一个对象,无法再指向其他对象;一个既是static又是final的字段占据一段不能改变的存储空间;
final在编译器中被理解为终态的,如提示”不能对终态字段赋**值”;
数组可以被看作一个对象来引用,被定义为final的对象引用只能指向唯一一个对象,由于对象本身的值是可以改变的,所以为了使一个常量真正做到不可更改,将常量声明为static final,声明为static final的数据,在内存中开辟了一个恒定不变的区域,是在装载时被初始化的,而声明为final的在每次创建新对象时可能被初始化(如类中存在final字段,每次初始化取随机数)
Java中定义全局常量,通常使用static final修饰,这样的常量只能在定义时被赋值
程序中可以定义为final的情况
1、final成员变量不可更改,(要求在声明时即赋值)
2、final成员变量声明时未赋值,会提示异常,可在构造方法中为空白final赋值
3、方法的参数设置为final时,不可以改变参数的值
4、局部变量定义为final时,不可以改变其值
定义为final的方法不能被重写,将方法定义为final类型可以防止子类修改该类的定义和实现方式,同时final方法的执行效率要高于非final方法;定义为private方法子类无法访问,所以一个定义为private的方法隐式被指定为final类型,这样无须将一个定义为private的方法再定义final类型(当然都定义也没问题)
父类中private( final)方法,子类中也可以存在同名的方法,但并不是重写的父类中的该方法,而是一个新建的方法
当子类重写父类的方法时,若子类向上转型为父类(父类 实例=子类实例;)并调用父类中的被覆盖的方法时,还是只运行子类中覆盖的方法,并不运行父类中的那个方法。
重写必须满足一个子类对象向上转型为它的基本类型并能调用相同方法,(若子类向上转型为父类但无法看到并调用相同方法,则方法是子类新建的方法)
定义为final的类不能被继承,若一个类不允许任何类继承,并且不允许其他人对这个类进行任何改动,可以将类设置为final类型,当一个类设置为final形式后,类中的所有方法都被隐式设置为final形式,但是final类中的成员变量可以被定义为final或非final类型
内部类
类体中定义的类称为内部类,内部类可分为成员内部类、局部内部类、匿名内部类
成员内部类:在内部类中可以随意使用外部类中的成员方法以及成员变量,但外部类不可以直接访问内部类成员;内部类的实例一定要绑定在外部类的实例上,也就是说成员内部类实例依赖外部类实例而存在
内部类的实例化方式:
外部类名.内部类名 内部类实例=外部类实例.new 内部类名();
Java中的Swing编程中经常使用到的技巧就包括内部类向上转型为接口,定义多个内部类以不同的方式实现接口中的同一个方法,在Swing编程中的实现是一个类中做出多个不同的响应事件
一个类中的成员内部类可直接继承类或接口
内部类最基本的用途:
为编写类的人留下一个接口和一个外部类,可以调用接口中方法,但方法的具体实现过程却被很好地隐藏了
在内部类中使用this.成员变量 调用内部类的成员变量,使用 外部类名.this.成员变量 方式调用外部类成员变量
在内存中所有对象均被放置在堆中,方法以及方法中的形参或局部变量放置在栈中
内部类也可以在类的局部位置定义,如在类的方法或任意的作用域中,方法中定义的内部类,方法的外部不能访问该内部类,但内部类可以访问方法中的常量和外部类的所有成员。
匿名内部类的作用就是创建一个实现了某个接口的匿名类的对象,格式:
returnnew 接口名(){匿名类类体};
匿名内部类编译后,会产生以”外部类名$序号”为名称的.class文件,序号以1~n排列,分别代表1~n个匿名内部类
静态内部类:
在内部类前增加static修饰符,静态内部类可以声明静态成员和非静态成员,非静态内部类不可以声明静态成员;静态内部类有一个最大的特点,就是不可以使用外部类的非静态成员,故在程序开发中较少用到
静态内部类特点:
1、创建静态内部类的对象,不需要其外部类对象
2、不能从静态内部类对象中访问外部类非静态对象
内部类继承:
当某个类继承内部类时,必须硬性给予这个类一个带参数的构造方法,并且构造方法的参数是外部类的引用,同时在构造方法中使用a.super();语句,如:
异常处理
Java语言的异常捕获结构由try、catch和finally这三部分组成,无论try块中的代码是否正常执行完成,都会执行finally块中内容。
catch语句块中可以获取异常的有关信息,包括:
getMessage()函数:输出错误性质
toString():给出异常的类型和性质
printStackTrace():指出异常的类型、性质、栈层次及程序中位置
finally语句块无法执行到的情况:
在finally语句块中发生了异常
在前面的代码中使用了System.exit()退出程序
程序所在的线程死亡
关闭CPU
关于try、catch、finally块
某一带有返回值的方法,若使用了try、catch、finally块结构处理异常、则:
1、 若try中进行返回值,则catch中也要返回值(异常了也能进行返回)
2、 finally中进行返回值
3、 try、catch、finally结构中都不进行返回,在结构外进行返回
*个人感觉,一般用法应该是在try、catch、finally结构前声明变量,在结构中得到值或赋值,在结构外进行return
执行顺序:try>(catch)>finally>结构外代码
throw动词,在方法体中抛出异常,在调用了该方法的位置再处理;程序在执行到throw语句时立即终止,它后面的语句都不执行
throws写在方法名后,声明抛出异常的类型,标识方法会抛出异常,提醒调用者注意,让调用该方法的方法捕获
Throwable类是Error和Exception类的父类,Exception类是所有异常类的父类,当自定义异常类时,要么继承Java提供的异常类,要有继承Exception这个异常父类,总的来说都是直接或间接继承Exception类;当程序中对异常进行多次捕获时,必须把Exception写到最后,由于Exception是父类,无法执行写在Exception后的异常捕获(也就是catch方法中的参数类型)
处理异常可遵循的原则:
一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类
如果父类抛出多个异常,则覆盖方法必须抛出那些异常的一个子集(不多于父类抛出的异常类型),不能抛出新异常
异常链:
在某个异常被捕获后,用新异常进行包装,再进行抛出,这样最后得到的异常也能往前追溯最开始的异常是哪里引起的。
通过 异常实例.initCause(e); 得到这个异常实例是由哪个异常引起的
或使用 异常 异常实例=new 异常(e);throw 异常实例;
集合类
集合类和数组都可以看做是容器,集合类和数组的不同之处是数组的长度是固定的,集合类的长度是可变的;数组用来存放基本类型的数据,集合类除了存放基本类型的数据外,还可以存放对象的引用;常用的集合有List集合、Set集合和Map集合,其中List与Set继承了Collection接口;
集合类的继承关系如下:
Collection接口是层次结构的根接口,Collection接口通常不能直接使用,List接口和Set接口都继承了Collection接口,Collection接口中的常用方法如下:
方法 | 功能描述 |
add(E e) | 将指定的元素添加到该集合中 |
remove(Object o) | 将指定的元素从该集合中移除 |
isEmpty() | 返回boolean值,用于判断当前集合是否为空 |
iterator | 返回在此Collection元素上进行迭代的迭代器,用于遍历集合中的对象 |
size() | 返回int型值,获取集合中元素的个数 |
遍历集合都是通过迭代器来实现,Iterator的next()方法返回值是Object,hasNext()返回值是boolean
List集合包括List接口和List接口的所有实现类,List集合中的元素允许重复,各元素的顺序就是对象插入的顺序,类似数组,可通过索引访问集合元素,索引从0开始;
List集合除了实现Collection接口方法外,还有两个重要方法:
get(intindex):获取指定索引位置的元素
set(intindex,Object obj):将集合中指定索引位置的对象修改为指定的对象obj
List接口的常用实现类是ArrayList和LinkedList
ArrayList类实现了可变的数组,允许保存所有元素,包括null,可以根据索引对集合元素快速访问;缺点是向指定索引位置插入或删除对象速度较慢
LinkList类采用链表结构保存对象,有点是便于向集合中插入或删除对象;缺点是随机访问集合元素速度较慢,也允许null
使用List集合时,通常声明为List类型,可通过不同的实现类来实例化集合,如:
List<int>list=new ArrayList<int>();
List<int>list2=new LinkList<int>();
实例化后,使用相应实例list或list2;注意<int>必须在List和其实例之间
迭代器的使用:
Set集合中的对象不按指定的方式排序,只是简单的把对象加入集合中,但set集合不能包含重复对象
Set接口常用的实现类有HashSet和TreeSet
HashSet类实现了Set接口,由哈希表(实际上是一个HashMap实例)支持,它不保证Set的迭代顺序,特别是它不保证该顺序恒久不变,此类允许使用null元素
TreeSet类不仅实现了Set接口,还实现了java.util.SortedSet接口,TreeSet类实现Set集合在遍历集合时按自然顺序递增排序或按指定比较器递增排序;不允许使用null元素
TreeSet类增加的方法:
方法 | 功能描述 |
first() | 返回此Set中当前第一个元素 |
last() | 返回此Set中最后一个元素 |
comparator() | 返回对此Set中的元素进行排序的比较器,若为自然排序,返回null |
headset(E e) | 返回一个新Set集合,新集合包含e(不包括)元素之前的所有元素 |
subSet(E e1,E e2) | 返回一个新Set集合,新集合包含e1(包括)和e2(不包括)之间的所有元素 |
tailSet(E e) | 返回一个新Set集合,新集合包含e(包括)对象之后的所有对象 |
Map集合提供的是key到value的映射,Map中不能包含相同的key,每个key只能映射一个value;Map集合允许值对象为null,且可以同时存在多个相同的value值,只要key不同即可;key还决定了存储对象在映射中的存储位置,但不是由key对象本省决定的,是通过一种”散列技术”产生散列码,散列码当做偏移量对应分配给映射到内存中的起始位置,进行确定存储位置
Map接口除了size()、isEmpty()、remove(key k)方法外,常用方法还包括:
方法 | 功能描述 |
put(K key,V value) | 向集合中添加指定的key和value的映射关系 |
containsKey(Object key) | 如果集合中包含指定key的映射,则返回true |
containsValue(Object value) | 如果集合中包含指定value的映射,则返回true |
get(Object key) | 如果存在指定的key对象,则返回对象对应的value值,否则返回null |
keySet() | 返回该集合中的所有key对象形成的Set集合 |
values() | 返回该集合中所有value值对象形成的Collection集合 |
Map接口常用的实现类有HashMap和TreeMap,建议使用HashMap来实现Map集合,因为由HashMap类实现的Map集合添加和删除映射关系的效率更高,HashMap通过哈希码对其内部的映射关系进行快速查找;TreeMap的映射关系存在一定的顺序;
HashMap类是基于哈希表的Map接口的实现,允许使用null键和null值,但需要保持键的唯一性;不保证映射顺序恒久不变
TreeMap类还实现了java.util.SortedMap接口,映射关系具有一定的顺序,在添加、删除和定位映射关系时较慢,不允许null键
可以通过HashMap类创建Map集合,当需要顺序输出时,再创建一个完成相同映射关系的TreeMap实例
多线程
多个相处并发执行
Windows为多任务操作系统,以进程为单位,每个独立执行的程序都称为进程;操作系统为每个进程分配一小段时间使用CPU(CPU时间片),由于CPU转换很快,相当于是同时执行;
线程是进程中的执行流程,一个线程占一小段CPU时间片
Java提供了两种方式实现线程:
继承java.lang.Thread类:
常用构造方法:public Thread();和public Thread(StringthreadName);
如:
实现java.lang.Runnable接口
实现Runnable接口的程序会创建一个Thread对象,通过Thread类中的以下两个构造方法,将Runnable对象与Thread对象相关联:
publicThread(Runnable r)
publicThread(Runnable r,String name)
使用Runnable接口启动新的线程的步骤:
建立Runnable对象>使用参数为Runnable对象的构造方法创建Thread实例>调用start()方法启动线程
如:
实现Runnable接口的匿名类的方式:
实现线程功能的代码写在run()方法中,通过start()方法产生一个新的线程,该线程运行run()方法;在调用start()方法前,Thread对象只是一个实例,而非线程;只能通过start()方法启动线程,不调用start()方法,线程永远不会启动
run()方法必须是public void run()格式
线程的生命周期:
线程的生命周期包括7种状态:
出生状态:使用线程实例调用start()方法之前
就绪状态:调用start()方法后,线程处于就绪状态(可执行状态)
运行状态:线程得到系统资源后
等待状态:调用wait()方法后,进入等待状态;等待状态的线程必须要线程实例调用notify()方法唤醒(notifyAll()唤醒所有等待线程)
休眠状态:调用Thread类的sleep(1000);方法
堵塞状态:运行状态下进行输入/输出请求
死亡状态:run()方法执行完成
使线程处于就绪状态的方法:
调用sleep()方法
调用wait()方法
等待输入/输出
使线程处于运行状态的方法:
调用notify()或notifyAll()方法
调用interrupt()方法
线程休眠结束
输入/输出结束
当线程进入就绪状态后,在无其他情况下,线程就在就绪状态和运行状态进行来回切换
休眠状态的线程休眠结束后,并不能保证一定会进入运行状态,只能保证它进入就绪状态
线程加入:
线程实例.join()方法,使当前调用方法的线程先执行,其他线程在该线程执行完成后执行
线程中断:
在线程调用start()方法运行后,线程实例调用interrupt()方法中断调用方法线程的执行,使线程离开run方法并抛出InterruptedException异常,在catch中可用break结束线程的执行
线程礼让调用yield()方法,当不保证当前线程会将资源礼让
线程优先级:
线程实例.setPriority(int); 可用设置线程的优先级,范围是1~10,越大越优先
线程同步
线程同步是为了解决多个线程同时访问同一资源对象时数据不同步,资源冲突的情况
线程同步的实现:
在run方法中加个synchronized同步块
synchronized(Object(如””)){}
同步方法,run方法中调用加了synchronized的同步方法,如
publicsynchronized void T(){}
使用Lock锁
要注意及时释放锁,通常放在finally代码块中
Socket网络通信
TCP/IP协议栈中有两个高级协议:
TCP:传输控制协议
UDP:用户数据包协议
TCP协议是一种以固接连线为基础的协议,它提供两台计算机间可靠的数据传送,能保证数据确实到达,顺序不变,协议认证上比TCP存在额外耗费
UDP是无连接通信协议,不保证可靠数据的传输,但能够向若干个目标发送或接收数据,UDP以独立发送数据包的方式进行,不保证顺序不变,适合对传输速度和实效要求高的方面,如网络聊天室,在线影院
网络程序设计的端口并非真实的物理存在,而是一个假象的连接装置,端口被规定为一个在0~65535之间的整数,通常0~1023之间的端口用于知名的网络服务和应用,开发的普通应用应使用1024之上的端口
网络程序中的套接字用于将应用程序和端口连接起来,是一个假象的连接装置
服务器端程序创建一个ServerSocket(服务器端套接字),调用accept()方法等待客户机来连接
客户端程序创建一个Socket,请求与服务器建立连接
服务器接收客户端的连接请求,同时创建一个新的Socket与客户端连接,服务器端继续等待新的请求
数据库操作
连接oracle,mysql,sqlserver数据库的方式:
处理数据:
IO操作
Servlet
Servlet对象主要封装了对HTTP请求的处理,并且它的运行需要Servlet容器的支持(如tomcat)
通常编写的Servlet类都继承与HttpServlet对象,HttpServlet是Servlet的实现类,提供了Http请求的处理方法
Servlet对象在Servlet容器启动时被初始化,当第一次被请求时,Servlet容器将其实例化,此时它驻存于内存中,如果存在多个请求,Servlet不会再被实例化,仍然由此Servlet对其进行处理,每一个请求是一个线程,处理是高效的