第一节 Java 基础知识 java语言是解释执行,java源码是通过编译生成一种特殊的.class的中间字解码文件,然后再有JVM进行解释执行。
java语言对指针进行了上层的封装,它保证能够通过这个指针(引用),来访问有效的内存单元。java语言不允许多继承,使继承关系成树装图,每个类都只能由一个父类。java语言的开发效率高,但执行效率低(相当于c++的55%)。
java的垃圾回收机制,在java中new的对象不需要向c++一样进行delete操作,JVM会根据情况回收垃圾对象。(懒汉机制,等待资源没有的时候才回收)我们只能够建议JVM进行垃圾回收,例如∶System.gc() ,RunTime.gc()这两个方法就是建议JVM进行垃圾回收的方法。
JDK,java开发工具包(类库和运行命令),JRE,java运行环境,JVM,java虚拟机(解释执行的核心,对字节码进行翻译成运行环境的机器码,它可以屏蔽平台差异。JVM是不跨平台的。)
JAVA_HOME,指明JDK安装的位置,CLASSPATH,指明类文件的位置,PATH,指明命令的可执行文件的位置。
java源文件的文件名必须和文件中定义public class的类名(大小写页要相同)相同。
java源代码中的main方法是程序的入口,下面是main方法的定义写法。
public static void main(String[] args){
System.out.println("Hello world");
}
java源文件也要先编译,使用javac xxx.java格式的命令得来编译,使用java xxx来运行。
定义包结构要放在有效代码的第一行,package xxx.xxx,包的定义在一个程序中只能由一个,在加上包定义之后编译可以使用javac -d 路径 xxxx.java,这个-d这个命令行的参数可以指定包结构的位置“.”代表当前目录。在运行时要使用类的全名
java xxx.xxx.xxxx用包名以点分隔。运行时要在包结构的上一层目录来运行。
※java中的注释
单行注释 //...... 多行注释 /* .......*/
文档注释/** ........<p>(换行标签)*/,用javadoc命令可以根据原码中的文档注释生成注释文档(html格式)。文档注释中可以使用html标签。
javadoc -d 路径 (指定注释文档的保存路径)
文档注释一般写在类定义之前,方法之前,属性之前。在文档注释中可以用 @author 表示程序的作者,@version 表示程序的版本,前两个注释符号要写在类定义之前,用于方法的注释@param 对参数进行注释,@return 对返回值进行注释 @throws对抛出异常的注释。
※jar命令∶用于打一个xxx.jar文件
用法:jar {ctxu}[vfm0Mi] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...
选项:
-c 创建新的存档
-t 列出存档内容的列表
-x 展开存档中的命名的(或所有的〕文件
-u 更新已存在的存档
-v 生成详细输出到标准输出上
-f 指定存档文件名
-m 包含来自标明文件的标明信息
-0 只存储方式;未用ZIP压缩格式
-M 不产生所有项的清单(manifest〕文件
-i 为指定的jar文件产生索引信息
-C 改变到指定的目录,并且包含下列文件:
如果一个文件名是一个目录,它将被递归处理。清单(manifest〕文件名和存档文件名都需要被指定,按'm' 和 'f'标志指定的相同顺序
示例1:将两个class文件存档到一个名为 'classes.jar' 的存档文件中:
jar cvf classes.jar Foo.class Bar.class
示例2:用一个存在的清单(manifest)文件 'mymanifest' 将 foo/ 目录下的所有
文件存档到一个名为 'classes.jar' 的存档文件中:
jar cvfm classes.jar mymanifest -C foo/ .
一般在使用使用jar cvf 文件名.jar 文件所在路径(xxx/xxx/xxx.class)也可以压缩一个目录,只要在制定路径是指定为文件夹,jar命令的命令行参数在使用时可以以“-”开头,也可以不用。
java程序的运行过程,首先是启动java虚拟机,然后就是去找.class文件,先是从系统的类库中找(系统之会在跟目录下查找,所以需要完整类名),如果找不到的话会去CLASSPATH所设置的目录去找。然后加载到java虚拟机中。如果要使用到其他的在JAVA_HOME中没有的类或者是其他公司提供的第三方的.jar(jar包)文件时,要把它的路径及文件名加到CLASSPATH中。
系统会在每个java程序中隐含导入了java.lang这个包,import 包名,导入包中的类文件。
java.lang包,这是一个基础包。 java.util包,这个包是工具类的包。
java.io包,这个包是用于输入输出操作的 java.net包,这个包是用于网络编程。
java.awt,java.swing,javax.swing java.event包,这些包用于java的图形编程用的包。
applaction java的应用程序,java应用程序中必须有一个main()方法。
第二节标识符和关键字
Java代码中的“;”、“{}”、“ ”
Java语句以分号分隔,Java代码块包含在大括号内,忽略空格。
※标识符
1) 用以命名类、方法和变量、以及包遵守JAVA的命名规范类以每个单词。方法和变量第一个字母不大写,其他都以大写字母开头。2) 只能以字符、“_”或“$”开头; 3) 无长度限制。
※java中的关键字
goto和const在java中虽然不再使用但是还作为关键字存在。
java中没有sizeof关键字了,java中的boolean类型的值只能用true和false,且这两值也是关键字。java语言中没有无符号(unsigned)关键字。
第三节 java中的数据类型
1) 整型
byte 1字节 8位 -128到127
short 2字节 16位 -2^15到2^15-1
int 4字节 32位 -2^31到2^31-1
long 8字节 64位 -2^63到2^63-1
2) 浮点类型
float 4字节 32位
double 8字节 64位
3) 字符类型
char 2字节 16位
4) 布尔型
boolean false/true
注意:
1) char是无符号的16位整数,字面值必须用单引号括起来; ‘a’
2) String 是类,非原始数据类型;
3) 长整型数字有一个后缀为“L”或“l”,八进制前缀为“0”,十六进制前缀为“0x”;
4) 黙认浮点类型为double;
5) float数据类型有一个后缀为“f”或“F”,Double数据类型后可跟后缀“D”或“d”;
6)char类型也可以用通用转译字符,但是不能用ASCII码。可以用“\u0000”这种格式,因为char型中使用的是unicode编码方式。
注意:整型值存放,正数存放原码(二进制码),负数则存放补码(原码按位取反末位加一)。
注:实型值在存储时会损失精度,所以不要直接比较两个实型值。系统默认的实型都是double型,要使用float型时要在数据后加个f,或者强行转换,强转(占字节数大的类型转到占字节数小的类型)时会放弃高位值只取低位值。
java中的数字数据类型转换由占字节数小的类型到占字节数大的类型的可以有自动转换,反之则需要强行转换,char型和int型之间可以相互转换。char和short不能相互转换。
注意:隐式类型转换;
a 运算符 b ,如果a,b中有任意一个是double型,前面运算的结果就是double型,如果a,b中有任意一个是float型,前面运算的结果就是float型,如果a,b中有任意一个是long型,前面运算的结果就是long型,如果a,b中没有double、float、long型,那么其结果就为int型。
所有基本数据类型在使用时会事先分配空间,值本身就存在空间中,在传递时,就是值传递,不是引用传递。
在类中定义的方法在返回值前加上static修饰符就可以在main方法中调用了。如果不用static那就需要在main方法中创建对象,使用对象来调用对象的方法。例如;
public class Test{
public static void main(String[] args){
Test t=new Test(); int b=1; int c=2; int[] a=new int[10];
t.sqort(a); add(b,c)
}
public int[] sqort(int[] a){
.......
}
static int add(b,c){
.......
}
}
第四节 java中的运算符(java的运算符的优先级和结合性和c++相同)
System.out.println(3/2) 按整型计算 得1
1) >>= 前面是零补零,前面是一补一;
2) >>>= 无符号右移(强制右移都会移进一),
>>=和>>>=对于负数不一样
正数:右移n位等于除以2的n次方
负数:变成正数。
3) && 短路与,前面为假,表达式为假,后面的操作不会进行,& 会对所有条件进行判断。
4) || 短路或,前面为真,表达式为真,后面的操作不会进行,| 会对所有条件进行判断。
例:if(a<3&(b=a)==0) b赋值
if(a<3&&(b=a)==0) b不赋值
5)instanceof,是用于判断一个对象是否属于某个类型
6)java中的求余运算符“%”可以对两个实型变量求余
×?注意:按位与是为了让某些位置一,按位或是令某些位置零,按位异或是令某些位取反。
注意:使用左右位移和无符号右移运算符的使用方法是 变量名<<=位移位数 ,变量名>>=位移位数 (前两个运算符是不会忽略整形符号位,也称逻辑位移),变量名>>>=位移位数
注意:左右位移和无符号右移运算符只能用于整形及其兼容类型(byte,int,short,long)
第五节 java 语句
※java的流程控制
控制流
if()
if()….else
if()…..else if()….else
注意:else只是和其上面的同层的最近的if()来配对。
switch(){
case 'a':……..
case 1:……break;
default:
…………
}
注解:switch()内数据类型为byte short char int类型,只有以上四种类型的才可以在switch()中使用。case块中不加break时会按顺序执行下面的语句。
循环语句
for(int i=0;i<n;i++){}
while(){}
do{} while();-----------注意加分号
例子:
loop:for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(3==j){
break loop; /*loop为标签 只能用在循环语句中,循环
嵌套中用于跳到外层循环*/
}
}
}
辨析:
int x,a=6,b=7;
x=a++ + b++; // a=7,b=8,x=13
×?int x=6;x=~x; // 6的二进制0110 取反得11001 再转成补码(取反加一) 10111 = -7
break,跳出本层循环,执行后面的代码,continue,提前终止本次循环,再一次进行循环或循环条件满足或不满足后退出循环。break 标签名; continue 标签名;这两条语句知识表示跳出有标签的循环和提前终止本次有标签的循环,只能用在循环语句(多层循环嵌套)中,循环嵌套中用于跳到外层循环。
注意:for循环在使用时一定要注意不要忘记()中的两个";",死循环的写法for(;;){}或者是用while(true){}
注意:System.out.println("..."+a)在使用这个语句时,它会将其中非字符串(String)的值转换成字符串(不是所有数据类型都可以的)。
第六节数组
java中的数组Array,其包含两个部分,分别是数组的引用和数组的空间两部分。
声明数组
1) 一组相同类型(可以是类)数据的集合; 2) 一个数组是一个对象;
3) 声明一个数组没有创建一个对象; 4) 数组能以下列形式声明:
int[] i 或 int i[]
Car[] c 或 Car c[]
*C++中只能 Car c[]
*JAVA中推荐用 Car[] c;
5)数组的定义 如:
int[] a(数组引用声明)=new int[10](数组空间的声明,并把空间首地址赋值给数组的引用)
int[] a;
a=new int[20];
创建数组
1) 创建基本数据类型数组 int[] i = new int[2];
2) 创建引用数据类型数组 Car[] c = new Car[100];
3) 数组创建后有初始值。
数字类型为0 布尔类型为false 引用类型为null
注意:访问没有初始化的数组中的值,是会抛出异常的(NULLpointerException),java中只保证一位数组的地址是连续的,二维数组实际上是一维数组中有存储了一维数组的引用。
初始化数组
1) 初始化、创建、和声明分开
int[] i;
i = new int[2];
i[0] = 0;
i[1] = 1;
2) 初始化、创建、和声明在同一时间
int[] i = {0,1};
Car[] c = {new Car(),new Car()};
多维数组
1) 有效定义
int[][] i1 = new int[2][3]; (同时给定一维,二维的空间)
int[][] i2 = new int[2][]; (给定一维的空间,二维空间待定)
i2[0] = new int[2],i2[1] = new int[3];
*C++中 int[][] =new int[][3];有效
2) 无效定义
int[][] i1 = new int[][3];
3) 数组长度 -----数组的属性length(在二维数组中这个属性只代表第一维的长度)
int[] i = new int[5];
int len = i.length; //len = 5;
Student[][] st = new Student[4][6];
len = st.length; //len = 4;
len = st[0].length; //len = 6;
数组拷贝
System.arrayCopy(Object src, int srcPos, Object dest, int destPos, int length);
src源数组,srcPos从第几位开始拷贝,dest目标数组,destPos目标数组放置的起始位置,length,表示要拷贝的长度。拷贝一个数组到另一个数组。
类的对象的创建和对象数组
一个xxx.Java文件中可以定义多个类但是只能由一个public修饰的类,也只能以这个类的类名作为.java的文件名。
java中的类的对象的创建,要先创建这个对象的引用, 例如:Car c;然后用new这个关键字创建一个对象的实例(对象的空间) 例如:c=new Car();,然后对象的实例的空间首地址赋值给对象的引用。多个对象的引用可以同时引用自同一个对象的实例,但是对象的引用只能引用一个对象的实例。
对象的引用和对象的实例间就像是牵着气球的线和气球一样。
注意:只有一个没有被任何对象的引用所引用的对象的实例才会变成垃圾等待被垃圾回收。
对象数组
例:Car[] c=new Car[3];
c[0]=new Car();
注意:存放基本类型的数组的数据是直接存放在数组的空间中,而对象的数组在数组空间中存放的则是对象的引用。
定义在类中类的属性是实例变量,定义在类的方法中的变量是局部变量。实例变量是保存在对象空间中的,而局部变量则是在方法调用的分配空间,调用结束后就释放空间。
注意:在类的定义中属性的定义和方法的定义必须写在类里。
注意:系统会自动初始化实例变量,数字类型为0 ,布尔类型为false ,引用类型为null。局部变量需要初始化,必须赋初值。如果不赋初值无法通过编译。
Java中的方法调用中参数传递有两种,一个是对于参数是基本类型的使用的是值传递(直接传参数的值),另一个是引用传递,它是用于参数是类的对象,它传递的是这个对象的引用。
第二章面向对象的编程
第一节 面向对象的思想
anything is Object(万物皆对象)
抽象,从对具体的对象中抽取有用信息。
对象有其固有属性,对象的方法,即对象的行为(对象能做什么)。
对象本身是简单的(功能简单),多个对象可以组成复杂的系统(对象之间彼此调用对方的方法)。
对象应当是各司其职(功能简单),各尽所能(把自己的功能作到最好)。(弱耦合性实现了前面所述的对象的特点)
对象的耦合性,是对象之间的联系,对象和系统之间的联系。对象的耦合性要尽量的弱,也就是对象之间的联系尽可能的弱,对象和系统之间的联系尽可能的弱。
系统的可插入性,是在系统中加入新的对象之后的系统稳定性。
对象的可替换性,是在系统中替换原有的对象之后的系统的稳定性。
复用性,即对象可否被重复使用,对象的功能越简单,复用性就越好。(对象的耦合性弱,复用性就比较强)
面向过程是先有算法,后又数据结构(怎么解决问题)
面向对象是先有对象(数据结构),后有算法。(用什么做)
类是某些有着相同属性的集合的抽象。
类是一个类对象的模板,对象是类的具体化。
类是一个新的数据类型,类的对象。
注意:局部变量的作用范围是在定义它的代码块以内,局部变量要先赋值后使用,在以一个重合的作用于范围内不允许两个局部变量命名冲突。局部变量局部优先,且与实例变量同名时会覆盖局部变量。
变量 包括简单变量(原始数据类型),对象变量。
方法的定义:
1,方法的修饰符(多个修饰符出现的顺序无关) |
2,方法的返回值类型 |顺
3,方法名 |序
4,方法的参数表 |向
5,方法中允许抛出的异常 |下
java中不能够在返回语句后写任何代码。JVM+解释器=JRE,JRE+类库=JDK
java中方法的重载(overload)方法名相同,参数表不同,返回值类型可以不同。调用时要给出明确参数并确定调用某一方法。在编译时,编译器会根据参数选择适当的方法,所以重载也叫编译时多态。
就近向上匹配原则
如果方法的参数表中的数据类型和调用时给出的参数类型不尽相同时会根据向上匹配的就近原则。(类型就近向上转化匹配)
注意:调用时要给出明确参数并确定调用某一方法,否则编译会出错。
对象使用者(调用其他对象的方法)对象(对象中的方法被调用时根据参数进行自己进行选择)
一类方法,但跟据不同的参数会有差异,对象会根据参数判断,对对象调用者透明。
创建对象的过程,1,分配空间 2,初始化属性 3,调用构造方法(有前提,不考虑继承关系)。
构造方法的写法,没有返回值类型,构造方法的方法命名必须和类名相同。如果在类中不写构造方法,系统会提供一个无参的构造方法。
注意:最好在写类时提供一个无参的构造方法。
获得对象的方式
通过new(在堆空间中申请分配空间),new 类名(),可以通过这种形式获得一个对象,这时的对象是无法使用,必须把的它的地址存放进一个对象变量才能够使用。例如 :Car c=new Car();
有参的构造方法在被调用时,在用new关键字或的对象时初始化,例如:Car c=new Car("yellow")
对象变量中存放的是对象的引用(地址的封装形式)
this关键字,表示当前对象(哪个对象调用了方法,哪个对象就是当前对象),可以用来区分实例变量和局部变量。this(),表示调用本类其他的构造方法,注意,只能写在构造方法的第一行。
java中的参数传递,简单类型的变量传递的是数值,对象变量的传递则传递的一个引用(地址)。
第二节封装、继承、多态
面向对象的三大特征:封装、继承、多态。
※java中的封装
封装,一个对象和外界的联系应当通过一个统一的接口,应当公开的公开,应当隐藏的隐藏。(对象的属性应当隐藏),一个对象的内部是透明的,就是把对象内部的可透明性和隐藏的特性区分开,该透明的透明,该隐藏的隐藏。
(封装的属性)java中类的属性的访问权限的默认值不是private,要想隐藏该属性或方法,就可以加private(私有)修饰符,来限制只能够在类的内部进行访问。
对于类中的私有属性,要对其给出一对方法(getXxx(),setXxx())访问私有属性,保证对私有属性的操作的安全性。
方法的封装,对于方法的封装,该公开的公开,该隐藏的隐藏。方法公开的是方法的声明(定义),即(只须知道参数和返回值就可以调用该方法),隐藏方法的实现会使实现的改变对架构的影响最小化。。
封装会使方法实现的改变对架构的影响最小化。
完全的封装,类的属性全部私有化,并且提供一对方法来访问属性。
※java中的继承
继承,是对有着共同特性的多类事物,进行再抽象成一个类。这个类就是多类事物的父类。父类的意义在于可以抽取多类事物的共性。
java中的继承要使用extends关键字,并且java中只允许单继承,也就是一个类只能有一个父类。这样就使继承关系呈树状,体现了java的简单性。
子类只能继承在父类中可以访问的属性和方法(实际上父类中私有的属性和方法也会被继承但子类中无法访问罢了)。
※访问控制修饰符:(可以修饰属性和方法)
private修饰符,表示只有本类内部可以访问。
default修饰符,方法不加修饰符,会默认为default,表示在同一个包中可以访问,父子类在同一包中,子类可以继承父类的相应内容。(可以修饰类)
protected(保护)修饰符,表示同一包中可以访问,不同包的子类也可以访问继承。
public修饰符,表示公开,在任何地方都可以访问。(可以修饰类)
修饰符的权限是由上而下逐渐变宽的。
继承的意义,就在于子类可以在父类的基础之上对父类的功能进行发展,继承可以使系统的耦合性降低,也就是使对象间的联系便的松散,使多类对象间的联系用其父类对象代替。
注意:构造方法不能被继承。
父类的属性及方法的确定:要从子类的角度来看子类间的共性,当所有子类都有这个属性时,就应当考虑是否该放在父类中,方法也是如此,方法可以被看作是对象的行为,而类的方法这时这一类对象所共有的行为,所以也应当在方法的确定时注意是不是所有的子类型中都需要有这种方法,并且会根据不同的类型的行为的方式也不同才可以覆盖着个方法。
※java中方法的覆盖
子类中有和父类中可访问(可继承到子类)的同名同返回类型同参数表的方法,就会覆盖从父类继承来的方法。
注意:在jdk1.4以前要求方法的覆盖时,需要方法的返回值,参数表,方法名必须严格相同,而在jdk1.5中方法覆盖,子类中的覆盖的方法的返回值可以是父类中被覆盖的方法的返回值类型的子类型。
注意:子类的方法覆盖父类的方法时,方法的修饰符要么相同,要么子类中的方法的修饰符表示的访问权限要宽于父类。父类中的私有方法,不能被继承到子类,就是说子类中即使将其覆盖了也不会有多态。
覆盖的意义:对从父类中继承的方法的发展。
注意:父子类中有同名的属性不叫子类覆盖了父类的属性,这种情况较作属性的遮盖(shadow)。
当构造有继承关系的对象的步骤
1,递归的构造父类的对象
2,分配空间
3,初始化本类实例变量(属性)
4,调用本类的构造方法
注意:子类对象中其实包含着父类的对象,也就是父类对象加上子类对象,才是完整的子类对象的实例。
super关键字
super(),表示在子类的构造方法中调用父类的构造方法(可以通过这种方法在子类的构造方法中初始化父类中的属性),super()也只能出现在构造方法的第一句上。super(),在子类的构造方中指明构造父类时调用哪一个父类的构造方法构造父类。
super,这里所表示的是一个父类的对象,可以通过super来使用父类中可以访问的方法(可以在父类中定义setXxx(),getXxx()方法来访问父类中的私有属性),super可以屏蔽父子类中同名属性的冲突。
注意:在写类的时候,一定要写默认无参的构造方法,如果一个构造方法的第一句既不是this(),也不是super()时,那么就会在这里隐含的调用它的父类的无参的构造方法,即隐含的有super()。
少覆盖原则:既子类应当尽量少的覆盖父类方法,如果覆盖了父类的大多数方法,那就应当考虑是否应当有继承关系
※java中的多态(以子类覆盖了父类的方法为前提)
多态,把子类对象主观的看作是其父类型的对象,那么父类型就可以是很多种类型。
多态,编译时多态(方法的重载)
运行时多态(多态)
编译时类型,也就是可以被看作的类型,主观认定。
运行时类型,也就是实际的对象实例的类型,客观不可改变(也是被看作类型的子类型)
对于一个对象来说,在对象产生时,运行时类型就已经确定不会再改变,编译时类型可以和运行时类型不同。在对象变量声明时可以确定其运行时类型,但是编译时类型对象变量背后所指向运行时类型则可以是其本类型或者是其子类型。
多态三特性
1,对象实例确定则不可改变(客观不可改变)。
2,只能调用编译时类型所定义的方法。
3,运行时会根据运行时类型去调用相应类型中定义的方法。
多态的意义:在需要使用一类对象的共性时,可以用多来屏蔽掉其子类中的差异。
注意:类的属性是没有多态的,只会根据编译时类型访问。只有子类覆盖了父类的方法,且把子类对象当作父类类型来看时才会有多态。要注意区分子类中的方法重载。对于方法的重载,则是会使用编译时类型来进行相应的方法调用。
两种复用
白箱复用,也就是继承复用,父类中的可以被子类访问到的就可以被继承,这样会有些不需要的内容被继承下来,所以这种方式不太好。
黑箱复用,也叫组合复用,也就是把要复用代码的类的对象作为本类中的一个属性,然后再通过方法的委托来实现由选择的复用,方法的委托就是在本类的方法内部通过该类的对象调用要使用类的方法。
注意:尽量用组合复用替代继承复用。
多态的使用
多态用于参数,可以在方法的参数中传入其父类类型,在运行时会根据实际的运行时类型来在方法中进行相应的操作。
多态用于返回值,可以在方法的返回值类型上是用其实际返回值的父类型,在使用期返回值时也不必关心其实际类型。
多态可以使代码变得更通用,以适应需求的变化。也就是定义在父类中的方法,可以在子类中有不同的实现将其覆盖,在为父类型的对象变量赋值相应需要功能的子类的对象实例。
第三节 java中的修饰符
※static 表示静态,它可以修饰属性,方法和代码块。
1,static修饰属性(类变量),那么这个属性就可以用 类名.属性名 来访问,也就是使这个属性成为本类的类变量,为本类对象所共有。这个属性就是全类公有。(共有的类变量与对象无关,只和类有关)。
类加载的过程,类本身也是保存在文件中(字节码文件保存着类的信息)的,java会通过I/O流把类的文件(字节码文件)读入JVM(java虚拟机),这个过程成为类的加载。JVM(java虚拟机)会通过类路径(CLASSPATH)来找字节码文件。
类变量,会在加载时自动初始化,初始化规则和实例变量相同。
注意:类中的实例变量是在创建对象时被初始化的,被static修饰的属性,也就是类变量,是在类加载时被创建并进行初始化,类加载的过程是进行一次。也就是类变量只会被创建一次。
2,static修饰方法(静态方法),会使这个方法成为整个类所公有的方法,可以用类名.方法名 访问。
注意:static修饰的方法,不直接能访问(可以通过组合方式访问)本类中的非静态(static)成员(包括方法和属性),本类的非静态(static)方法可以访问本类的静态成员(包括方法和属性),可以调用静态方法。静态方法要慎重使用。在静态方法中不能出现this关键字。
注意:父类中是静态方法,子类中不能覆盖为非静态方法,在符合覆盖规则的前提下,在父子类中,父类中的静态方法可以被子类中的静态方法覆盖,但是没有多态。(在使用对象调用静态方法是其实是调用编译时类型的静态方法)
注意:父子类中,静态方法只能被静态方法覆盖,父子类中,非静态方法只能被非静态方法覆盖。
java中的main方法必须写成static的是因为,在类加载时无法创建对象,因为静态方法可以不通过对象调用
所以在类的main方法。所在在类加载时就可以通过main方法入口来运行程序。
注意:组合方式,就是需要在方法中创建一个所需要的对象,并用这个对象来调用任意所需的该对象的内容,不会再受只能访问静态的约束。
3,static修饰初始代码块,这时这个初始代码块就叫做静态初始代码块,这个代码块只在类加载时被执行一次。可以用静态初始代码块初始化一个类。
动态初始代码块,写在类体中的“{}”,这个代码块是在生成对象的初始化属性是运行。这种代码块叫动态初始代码块。
类在什么时候会被加载,构造(创建)对象时会加载类,调用类中静态方法或访问静态属性也是会加载这个静态方法真正所在的类。在构造子类对象时必会先加载父类,类加载会有延迟加载原则,只有在必须加载时才会加载。
※final修饰符,可以修饰变量,方法,类
1,final修饰变量
被fianl修饰的变量就会变成常量(常量应当大写),一旦赋值不能改变,(可以在初始化时直接赋值,也可以在构造方法里也可以赋值,只能在这两种方法里二选一,不能不为常量赋值),fianl的常量不会有默认初始值,对于直接在初始化是赋值时final修饰符常和static修饰符一起使用。
2,final修饰方法,被final修饰的方法将不能被其子类覆盖,保持方法的稳定不能被覆盖。
3,final修饰类,被final修饰的类将不能被继承。final类中的方法也都是final的。
注意:final,不能用来修饰构造方法,在父类中如果有常量属性,在子类中使用常量属性时是不会进行父类的类加载。静态常量如果其值可以确定,就不会加载该类,如果不能确定则会加载该常量所在的类。
不变模式,对象一旦创建属性就不会改变。用final修饰属性,也用final修饰类(强不变模式),用final修饰属性(弱不变模式)。
不变模式的典型体现:java.lang.String类,不变模式可以实现对象的共享(可以用一个对象实例赋值给多个对象变量。)
池化的思想,把需要共享的数据放在池中(节省空间,共享数据)
只有String类可以用“”中的字面值创建对象。在String类中,以字面值创建时,会到Java方法空间的串池空间中去查找,如果有就返回串池中字符串的地址,并把这个地址付给对象变量。如果没有则会在串池里创建一个字符串对象,并返回其地址付购对象变量,当另一个以字面值创建对象时则会重复上述过程。
如果是new在堆空间中创建String类的对象,则不会有上述的过程。
String类中的intern()方法会将在堆空间中创建的String类对象中的字符串和串池中的比对,如果有相同的串就返回这个串的串池中的地址。
不变模式在对于对象进行修改,添加操作是使相当麻烦的,会产生很多的中间垃圾对象。创建和销毁的资源的开销是相当大的。
String类在字符串连接时会先的效率很低,就是因为它所产生的对象的属性是不能够修改的,当连接字符串时也就是只能创建新的对象。
对于很多的字符串连接,应当使用StringBuffer类,在使用这个类的对象来进行字符串连接时就不会有多余的中间对象生成,从而优化了效率。
※abstract(抽象)修饰符,可以修饰类和方法
1,abstract修饰类,会使这个类成为一个抽象类,这个类将不能生成对象实例,但可以做为对象变量声明的类型,也就是编译时类型,抽象类就像当于类的半成品,需要子类继承并覆盖其中的抽象方法。
2,abstract修饰方法,会使这个方法变成抽象方法,也就是只有声明(定义)而没有实现,实现部分以";"代替。需要子类继承实现(覆盖)。
注意:有抽象方法的类一定是抽象类。但是抽象类中不一定都是抽象方法,也可以全是具体方法。
abstract修饰符在修饰类时必须放在类名前。
abstract修饰方法就是要求其子类覆盖(实现)这个方法。调用时可以以多态方式调用子类覆盖(实现)后的方法,也就是说抽象方法必须在其子类中实现,除非子类本身也是抽象类。
注意:父类是抽象类,其中有抽象方法,那么子类继承父类,并把父类中的所有抽象方法都实现(覆盖)了,子类才有创建对象的实例的能力,否则子类也必须是抽象类。抽象类中可以有构造方法,是子类在构造子类对象时需要调用的父类(抽象类)的构造方法。
final和abstract,private和abstract,static和abstract,这些是不能放在一起的修饰符,因为abstract修饰的方法是必须在其子类中实现(覆盖),才能以多态方式调用,以上修饰符在修饰方法时期子类都覆盖不了这个方法,final是不可以覆盖,private是不能够继承到子类,所以也就不能覆盖,static是可以覆盖的,但是在调用时会调用编译时类型的方法,因为调用的是父类的方法,而父类的方法又是抽象的方法,又不能够调用,所以上面的修饰符不能放在一起。
抽象(abstract)方法代表了某种标准,定义标准,定义功能,在子类中去实现功能(子类继承了父类并需要给出从父类继承的抽象方法的实现)。
方法一时间想不到怎么被实现,或有意要子类去实现而定义某种标准,这个方法可以被定义为抽象。(abstract)
※模板方法模式
用abstract把制订标准和实现标准分开,制定的标准就是模板,实现就是按模板标准来实现,也就是继承模板,实现模板中相应功能的方法。模板中不允许修改的方法可以用fianl来修饰,这个方法不能使抽象方法,为保证安全,封装,把模板中不公开的部分用protected(保护)修饰。
第四节 java中的接口
接口是一种程序结构,是特殊的抽象类。接口中的方法必须都是公开的抽象方法(public abstract),接口中的属性都是公开静态常量(public static final)。
声明一个接口用 interface 关键字,接口也是一种类型,编译之后也有生成相应字节码,它的声明规范也要符合类型的定义(一个源文件中只能有一个public interface,接口名和源文件名相同,有public interface,就不能在写public class了)。接口中的属性可以不加修饰符,方法也不用加修饰符。
接口也可以继承,但是只能由接口继承,在用类去继承时要换用 implements 关键字,这时类和接口也不叫做继承关系,而是实现关系,但其实质也是继承。
一个类可以继承也只能继承另外一个类,但是可以实现多个接口,其语法是在implements后面写接口名,多个接口以“,”分隔。
接口之间是可以多继承的,其语法和类的继承语法是相同的,在接口多继承时,在extends后写接口名如果要继承多个接口,接口名以“,”分隔,接口的继承关系只是把其父接口中的抽象方法继承到子接口中。要实现接口就必须实现接口中的所有方法。
一个类可以在继承一个类的同时,也可以实现一个或多个接口。采用接口就绕开了单继承限制。
接口类型也可以做为编译时类型使用,但其实际的运行时类型必须是完全实现接口的类的对象实例,这样就使多态变得很灵活了,
注意:实现接口时,在实现(覆盖)抽象方法时,注意必须要在方法的返回值类型前加public修饰符。如果没有完全实现接口中的方法,那么这个类就只能够是个抽象类,不能创建对象。接口的是实质就是特殊的抽象类。接口没有构造方法。
接口的意义:
1,接口可以实现多继承。
2,用接口可以实现混合类型(主类型,副类型),java中可以通过接口分出主次类型。主类型使用继承,副类型,使用接口实现。
3,接口进一步深化了标准的思想,接口本身就是一个标准,它起到了降低耦合性的作用,接口可以使方法的定义和实现相分离,也就是将接口的定义者和实现者相分离,接口也可以用于降低模块间或系统间的耦合性。针对接口编程可以屏蔽不同实现间的差异,看到的只是实现好的功能,
接口:定义标准,
接口的实现:实现标准
接口的调用者:标准的使用
针对接口编程原则,也就是按照标准实现。
先有接口的定义,再有接口使用者,最后把接口的实现对象纳入接口的使用者中,接口的使用者会通过接口来调用接口实现者的方法。
接口的定义者定义好了标准,接口的使用者先写好了使用代码,接口的实现者写好实现之后把实现对象传入接口的使用者中。它调用接口中方法也就是调用接口实现中的方法。这种过程叫做接口的回调。
尽量使用接口类型作为编译时类型,尽量将抽取到的共性行为写在接口中。
用若干个小接口取代一个大接口。(接口隔离原则)
把一个类的功能作成接口,只暴露想暴露的方法,接口隔离原则可以实现更高层次的封装,针对的对象不同,暴露的方法也不同。
第五节 java中的根类Object
java中所有的类的父类或直接或间接的或隐含的都是Object类。
java不允许循环继承,也就是互相继承是不可以的。
Object类中的finalize()一个对象被垃圾收集的时候, 一个对象被垃圾收集的时候,最后会由JVM调用这个对象的finalize方法
Object类中有一个String toString()方法,返回该对象的字符串表示。Object类中的toString()方法他返回的是类名加上它的地址的一个字符串。在子类中推荐覆盖toString()方法。
Object类中的boolean equals(Object o)方法是用来比较对象的内容是否相等,其返回值是boolean类型的值,相同为真,不同则为假。实际上还是比较对象地址是否相同。String类覆盖了equals()方法,它比较是对象中的内容是否相同。子类中也推荐覆盖Object类中继承的equals()方法
※equals()的覆盖原则,
自反性 x.equals(x) 为true
对称性 y.equals(x) 和 x.equals(y) 的值要相同,要么都为true,要么都为false。
传递性 x.equals(y)为true, y.equals(z)也为true ,那么x.equals(z)一定也为true。
※覆盖equals()方法的步骤
boolean equals(Object o){
if(this==o) return true; //1,看看是不是一个对象
if(o==null) return true; //2,看看对象是不是空
if(!(o instanceof 本类类名)) return false;//看看是不是本类对象
......//根据本类设计。
}
第六节封装类
JAVA为每一个简单数据类型提供了一个封装类,使每个简单数据类型可以被Object来装载。除了int(Integer)和char(Character),其余类型首字母大写即成封装类类型名。
转换字符的方式:
int I=10;
String s=I+” ”;
String s1=String.valueOf(i);
Int I=10;
Interger I_class=new integer(I);
封装类.字符串.基本类型
Interger--------------------(Double(x.toString))------------>Double
String -----------------(Integer.valueOf() )---------------->Integer
Integer-----------------(x.toString() )--------------------->String
int----------------------(100+“”)------------------------->String
String------------------(Integer.parseInt() )--------------->int
Integer-----------------(Integer.intValue() )--------------->int
学会查看javadoc的帮助文档。要先关注要使用方法的返回值类型,也就是要获得内容的类型,然后看方法名,JDK中的方法名基本上是见名知义,参数表,就是看需要什么才可以获得的需要的那些内容,也要看自己能够提供什么。
注意:“==”在任何时候都是比较地址,这种比较永远不会被覆盖。
程序员自己编写的类和JDK类是一种合作关系。(因为多态的存在,可能存在我们调用JDK类的情况,也可能存在JDK自动调用我们的类的情况。)
注意:类型转换中double\interger\string之间的转换最多。
第七节内部类
(注:所有使用内部类的地方都可以不用内部类,但使用内部类可以使程序更加的简洁,便于命名规范和划分层次结构)。
内部类是指在一个外部类的内部再定义一个类。
*内部类可为静态,可用PROTECTED和PRIVATE修饰。(而外部类不可以:顶级类只能使用PUBLIC和DEFAULT)。
*JAVA文件中没有public class 可以类名和文件不同名。
内部类:内部类也就是定义在类内部的类。
内部类的分类
成员内部类、局部内部类、静态内部类、匿名内部类(图形是要用到,必须掌握)。
※成员内部类
四个访问权限修饰符都可以修饰成员内部类。
内部类和外部类在编译时是不同的两个类,内部类对外部类没有任何依赖。
内部类是一种编译时语法,在编译时生成的各自的字节码文件,内部类和外部类没有关系。
内部类中可以访问外部类的私有成员。
作为外部类的一个成员存在,与外部类的属性、方法并列。
内部类和外部类的实例变量可以共存。
在内部类中访问实例变量:this.属性
在内部类访问外部类的实例变量:外部类名.this.属性。
在外部类的外部访问内部类,使用out.inner.
※成员内部类的特点:
1.内部类作为外部类的成员,可以访问外部类的私有成员或属性。(即使将外部类声明为private,但是对于处于其内部的内部类还是可见的。)
2.用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。
对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。
3.成员内部类不能含有静态成员。
建立内部类对象时应注意:
在外部类的内部可以直接使用inner s=new inner();(因为外部类知道inner是哪个类,所以可以生成对象。)
而在外部类的外部,要生成(new)一个内部类对象,需要首先建立一个外部类对象(外部类可用),然后在生成一个内部类对象。内部类的类名是外部类类名.内部类类名。
Outer o=new Outer();
Outer.Inner in=o.new.Inner()。
※静态内部类
(注意:前三种内部类与变量类似,所以可以对照参考变量)
静态内部类定义在类中,任何方法外,用static class定义。
静态内部类只能访问外部类的静态成员。
生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。
静态内部类的对象可以直接生成:
Outer.Inner in=new Outer.Inner();
而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。静态内部类不可用private来进行定义。
注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。
用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。
例子:
对于两个类,拥有相同的方法:
class People
{
run();
}
interface Machine{
run();
}
此时有一个robot类:
class Robot extends People implement Machine.
此时run()不可直接实现。
interface Machine
{
void run();
}
class Person
{
void run(){System.out.println("run");}
}
class Robot extends Person
{
private class MachineHeart implements Machine
{
public void run(){System.out.println("heart run");}
}
public void run(){System.out.println("Robot run");}
Machine getMachine(){return new MachineHeart();}
}
class Test
{
public static void main(String[] args)
{
Robot robot=new Robot();
Machine m=robot.getMachine();
m.run();
robot.run();
}
}
局部内部类
在方法中定义的内部类称为局部内部类。
与局部变量类似,在局部内部类前不加修饰符public和private,其范围为定义它的代码块。
注意:局部内部类不仅可以访问外部类私有实例变量,但可以访问外部类的局部常量(也就是局部变量必须为final的)
在类外不可直接访问局部内部类(保证局部内部类对外是不可见的)。
在方法中才能调用其局部内部类。
通过内部类和接口达到一个强制的弱耦合,用局部内部类来实现接口,并在方法中返回接口类型,使局部内部类不可见,屏蔽实现类的可见性。
局部内部类写法
public class TestLocalInnerClass{
public static void main(String[] args){
Outer o=new Outer();
final int a=9;
o.print(a);
}
}
class Outer{
private int index=100;
public void print(final int a){
final int b=10;
System.out.println(a);
class Inner{
public void print(){
System.out.println(index);
System.out.println(a);
System.out.println(b);
}
}
Inner i=new Inner();
i.print();
}
}
匿名内部类
匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口。
匿名内部类的特点:
1,一个类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的事先或是覆盖。
2,只是为了获得一个对象实例,不许要知道其实际类型。
3,类名没有意义,也就是不需要使用到。
注:一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。
因其为局部内部类,那么局部内部类的所有限制都对其生效。
匿名内部类是唯一一种无构造方法类。
大部分匿名内部类是用于接口回调用的。
匿名内部类在编译的时候由系统自动起名Out$1.class。
如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。
因匿名内部类无构造方法,所以其使用范围非常的有限。
当需要多个对象时使用局部内部类,因此局部内部类的应用相对比较多。匿名内部类中不能定义构造方法。
匿名内部类的写法:
interface A{
void ia();
}
class B{
public A bc(){
return new A{
void ia(){
}
};
}
}
使用匿名内部类:
B b=new B();
A a=b.bc();
a.ia();
Exception(例外/异常)
对于程序可能出现的错误应该做出预案。
例外是程序中所有出乎意料的结果。(关系到系统的健壮性)
JAVA会将所有的异常封装成为一个对象,其根本父类为Throwable。
异常的分类
Throwable有两个子类:Error和Exception。
一个Error对象表示一个程序错误,指的是底层的、低级的、不可恢复的严重错误。此时程序一定会退出,因为已经失去了运行所必须的物理环境。对于Error错误我们无法进行处理,因为我们是通过程序来应对错误,可是程序已经退出了。
我们可以处理的Throwable类中只有Exception类的对象(例外/异常)。
Exception有两个子类:Runtime exception(未检查异常)可以在编程时避免,可处理可不处理
非Runtime exception(已检查异常)必须进行处理。
注意:无论是未检查异常还是已检查异常在编译的时候都不会被发现,在编译的过程中检查的是程序的语法错误,而异常是一个运行时程序出错的概念。
在Exception中,所有的非未检查异常都是已检查异常,没有另外的异常!!
未检查异常是因为程序员没有进行必要的检查,因为他的疏忽和错误而引起的异常。一定是属于虚拟机内部的异常(比如空指针)。
应对未检查异常就是养成良好的检查习惯。
已检查异常是不可避免的,对于已检查异常必须实现定义好应对的方法。
已检查异常肯定跨越出了虚拟机的范围。(比如“未找到文件”)
异常的传递
如何处理已检查异常(对于所有的已检查异常都要进行处理):
首先了解异常形成的机制:
当一个方法中有一条语句出现了异常,它就会throw(抛出)一个例外对象(throw 异常对象),然后后面的语句不会执行返回上一级方法,其上一级方法接受到了例外对象之后,有可能对这个异常进行处理,也可能将这个异常转到它的上一级。
注意:当一个方法中出现了异常,没有进行异常处理,方法就会把异常对象作为返回值返回。如果有异常进入虚拟机,那么虚拟机就会立刻中止程序的执行。
异常的处理方式
非RuntimeException (已检查异常)这种异常必须处理。如果不处理编译出错。
对于接收到的已检查异常有两种处理方式:throws和try..catch(...){}方法。
注意:出错的方法有可能是JDK,也可能是程序员写的程序,无论谁写的,抛出一定用throw。
在方法的定义中声明方法可能抛出的异常,用(throws 异常类名,异常类名) ,声明这个方法将不处理异常,并把异常交给上一级方法处理。可以抛出的是实际产生异常的父类的异常对象。
例:public void print() throws Exception.
对于方法a,如果它定义了throws Exception。那么当它调用的方法b返回异常对象时,方法a并不处理,而将这个异常对象向上一级返回,如果所有的方法均不进行处理,返回到主方法,程序中止。(要避免所有的方法都返回的使用方法,因为这样出现一个很小的异常就会令程序中止)。
如果在方法的程序中有一行throw new Exception(),返回错误,那么其后的程序不执行。因为错误返回后,后面的程序肯定没有机会执行,那么JAVA认为以后的程序没有存在的必要。
try..catch捕获异常
对于try……catch格式:
try {可能出现错误的代码块} catch(exception e){进行处理的代码} ;
对象变量的声明
用这种方法,如果代码正确,那么程序不经过catch语句直接向下运行;
如果代码不正确,则将返回的异常对象和e进行匹配,如果匹配成功,则处理其后面的异常处理代码。(如果用exception来声明e的话,因为exception为所有exception对象的父类,所有肯定匹配成功)。处理完代码后这个例外就完全处理完毕,程序会接着从出现异常的地方向下执行(是从出现异常的地方还是在catch后面呢?利用程序进行验证)。最后程序正常退出。
try块中的代码如果没有出现异常,就会跳过catch,正常执行。
try中如果发现错误,即跳出try块去匹配catch,那么try后面的语句就不会被执行。
一个try可以跟进多个catch语句,用于处理不同情况。当一个try只能匹配一个catch。
我们可以写多个catch语句,但是不能将父类型的exception的位置写在子类型的excepiton之前,因为这样父类型肯定先于子类型被匹配,所有子类型就成为废话,java中是不允许写废话的,所以编译会出错。
在try,catch后还可以再跟一子句finally。其中的代码语句无论如何(无论有没有异常)都会被执行(因为finally子句的这个特性,所以一般将释放资源,关闭连接的语句写在里面)。finally中的代码在和try中的代码的冲突时,finally中的代码一定会被执行且会忽略try中的代码。但是System.exit(0);(虚拟机退出语句)则不会去执行fianlly中的代码。
try{..}catch(..){..}
try{..}catch(..){}finally{..}
try{..}finally{}
以上三种写法都可以。
如果在程序中书写了检查(抛出)exception但是没有对这个可能出现的检查结果进行处理,那么程序就会报错。而如果只有处理情况(try)而没有相应的catch子句,则编译还是通不过。
如何知道在编写的程序中会出现例外呢
1.调用方法,查看API中查看方法中是否有已检查错误。
2.在编译的过程中看提示信息,然后加上相应的处理。
Throwable有一个message属性。在使用catch的时候可以调用:
Catch(IOException e){System.out.println(e.message())};
Catch(IOException e){e.printStackTrace()};
以上两条语句都是可以打印出错的过程信息。告诉我们出错类型所历经的过程,在调试的中非常有用。
开发中的两个道理:
①如何控制try的范围:根据操作的连动性和相关性,如果前面的程序代码块抛出的错误影响了后面程序代码的运行,那么这个我们就说这两个程序代码存在关联,应该放在同一个try中。
②对已经查出来的例外,有throw(消极)和try catch(积极)两种处理方法。
对于throws把异常抛到try catch能够很好地处理例外的位置(即放在具备对例外进行处理的能力的位置)。如果没有处理能力就继续上抛。
当我们自己定义一个例外类的时候必须使其继承excepiton或者RuntimeException。
throw是一个语句,用来做抛出例外的功能。
而throws是表示如果下级方法中如果有例外抛出,那么本方法不做处理,继续向上抛出。
throws后跟的是例外类型。
注意:方法的覆盖中,如果子类的方法抛出的例外是父类方法抛出的例外的父类型,那么编译就会出错:子类无法覆盖父类。
结论:子类方法不可比父类方法抛出更多的例外。子类抛出的例外或者与父类抛出的例外一致,或者是父类抛出例外的子类型。或者子类型不抛出例外。如果父类型无throws时,子类型也不允许出现throws。此时只能使用try catch。
断言是一种调试工具(assert)
其后跟的是布尔类型的表达式,如果表达式结果为真不影响程序运行。如果为假系统出现低级错误,在屏幕上出现assert信息。
Assert只是用于调试。在产品编译完成后上线assert代码就被删除了。
java中的图形界面
GUI,图形化的用户接口,为了人机交互使用的。
构造图形界面的步骤
1,选择一个容器
2,设置容器的布局管理器
3,向容器添加组件
4,事件的监听
容器(Container)用于管理其他的组件的对象。组件必须放到容器里。
JFrame,这是一个最顶层的窗体容器,所有其他的组件必须放在顶层容器里。
JDialog 对话框容器,他要依附于其父组件,他不是一个顶层容器。
JPanel,他不是顶层容器,必须放在顶层容器中,任何一个容器都有add()方法,Panel面板是透明的(默认)。他也是一个组件。
布局管理:对于任何一个容器类中都有setLayout()方法,用容器对象调用这个方法,来设置容器的布局管理器(LayoutManager这是一个接口,所有布局管理器都实现了这个接口)。
可用的布局管理器:
FlowLayout,流式布局管。Panel的默认布局管理就是FlowLayout。
BorderLayout,按方位进行布局管理,(North,South,East,West,Middle)不明确指定,就会默认加载在中间(Middle),
add(Component comp,String place)这个方法是在指定的位置添加组件。
GridLayout,网格布局,通过行列,间距,来用网格分割,把组件放入如网格中,先行后列摆放组件。
CardLayout,卡片布局,面板重叠放置。
GridBogLayout,组件可以跨行跨列的网格布局。
注意:一定要在图形界面都其他功能都设置好之后才能设置可见性。
JButton :按钮
JTextField:单行文本域
JTextArea:多行文本区
JScrollPane:滚动窗体
JComboBox:下拉选择框
JRadioButton:单选按钮
JCheckBox:多选按钮
JList:多行列表
JLabel:标签
JPasswordField:密码输入框
JEditorPane:显示结构化文档
Border:边框
JMenuBar:菜单条
JMenu:菜单
JMenuItem:菜单项
JPopupMenu:弹出式菜单
JSlider:滑动条
JProgressBar:进度条
JTabbedPane:分层面板
JSplitPane:分隔面板
JToolBar:工具条
JFileChooser:文件选择器
JColorChooser:颜色选择器
显示对话框
JoptionPane 里面有很多静态方法可以弹出对话框
注意:具体的方法可以去参看Java2 SE的API文档。
awt事件模型(观察者模式)(重点)
事件模型中,包括事件源对象,事件处理者(事件监听者对象),事件对象。
事件源和事件处理者之间建立了授权关系,也就是在事件源类中有一个事件处理者的对象作为属性,也可能是一个事件处理者的集合。
事件对象
事件源————————〉事件处理者
这就是事件模型的机制,也就是由事件源对象发送一个消息(事件对象),然后事件处理者调用相应的方法处理事件。
在事件监听器接口中定义的方法,都要以事件对象为参数。
一个事件源可以注册多个同类型的监听器,也可以注册多种多个事件监听器,一个事件监听器也可以为多个事件源服务。
首先了解一下什么是发消息:A,B,C三个类,分别作为事件源,事件处理者,事件对象。在A类中有一个B类的属性或者是一个内容为B类对象的集合,也就是事件源和事件处理者之间的建立了授权关系,在B类需要实现一个自定义的接口,这个自定义的接口继承了EventListener,EventListener接口中没有定义任何方法,这只是一个标记接口。实现在自定义接口中定义好的用于事件处理的方法,C类要继承EventObject类。这些方法是以事件对象为参数的b(C c),而后在A类a(C c)方法中使用B类的对象调用B类中的b(C c)方法,并把事件对象作为参数,并在main方法中用A类的对象调用了a(c)方法,这也就叫做A类对象给B类发送了消息。
也就是说事件源对象间接调用了事件监听器的方法,并以事件对象为实参传到事件监听器的方法中,要就叫事件源给
java语言对指针进行了上层的封装,它保证能够通过这个指针(引用),来访问有效的内存单元。java语言不允许多继承,使继承关系成树装图,每个类都只能由一个父类。java语言的开发效率高,但执行效率低(相当于c++的55%)。
java的垃圾回收机制,在java中new的对象不需要向c++一样进行delete操作,JVM会根据情况回收垃圾对象。(懒汉机制,等待资源没有的时候才回收)我们只能够建议JVM进行垃圾回收,例如∶System.gc() ,RunTime.gc()这两个方法就是建议JVM进行垃圾回收的方法。
JDK,java开发工具包(类库和运行命令),JRE,java运行环境,JVM,java虚拟机(解释执行的核心,对字节码进行翻译成运行环境的机器码,它可以屏蔽平台差异。JVM是不跨平台的。)
JAVA_HOME,指明JDK安装的位置,CLASSPATH,指明类文件的位置,PATH,指明命令的可执行文件的位置。
java源文件的文件名必须和文件中定义public class的类名(大小写页要相同)相同。
java源代码中的main方法是程序的入口,下面是main方法的定义写法。
public static void main(String[] args){
System.out.println("Hello world");
}
java源文件也要先编译,使用javac xxx.java格式的命令得来编译,使用java xxx来运行。
定义包结构要放在有效代码的第一行,package xxx.xxx,包的定义在一个程序中只能由一个,在加上包定义之后编译可以使用javac -d 路径 xxxx.java,这个-d这个命令行的参数可以指定包结构的位置“.”代表当前目录。在运行时要使用类的全名
java xxx.xxx.xxxx用包名以点分隔。运行时要在包结构的上一层目录来运行。
※java中的注释
单行注释 //...... 多行注释 /* .......*/
文档注释/** ........<p>(换行标签)*/,用javadoc命令可以根据原码中的文档注释生成注释文档(html格式)。文档注释中可以使用html标签。
javadoc -d 路径 (指定注释文档的保存路径)
文档注释一般写在类定义之前,方法之前,属性之前。在文档注释中可以用 @author 表示程序的作者,@version 表示程序的版本,前两个注释符号要写在类定义之前,用于方法的注释@param 对参数进行注释,@return 对返回值进行注释 @throws对抛出异常的注释。
※jar命令∶用于打一个xxx.jar文件
用法:jar {ctxu}[vfm0Mi] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...
选项:
-c 创建新的存档
-t 列出存档内容的列表
-x 展开存档中的命名的(或所有的〕文件
-u 更新已存在的存档
-v 生成详细输出到标准输出上
-f 指定存档文件名
-m 包含来自标明文件的标明信息
-0 只存储方式;未用ZIP压缩格式
-M 不产生所有项的清单(manifest〕文件
-i 为指定的jar文件产生索引信息
-C 改变到指定的目录,并且包含下列文件:
如果一个文件名是一个目录,它将被递归处理。清单(manifest〕文件名和存档文件名都需要被指定,按'm' 和 'f'标志指定的相同顺序
示例1:将两个class文件存档到一个名为 'classes.jar' 的存档文件中:
jar cvf classes.jar Foo.class Bar.class
示例2:用一个存在的清单(manifest)文件 'mymanifest' 将 foo/ 目录下的所有
文件存档到一个名为 'classes.jar' 的存档文件中:
jar cvfm classes.jar mymanifest -C foo/ .
一般在使用使用jar cvf 文件名.jar 文件所在路径(xxx/xxx/xxx.class)也可以压缩一个目录,只要在制定路径是指定为文件夹,jar命令的命令行参数在使用时可以以“-”开头,也可以不用。
java程序的运行过程,首先是启动java虚拟机,然后就是去找.class文件,先是从系统的类库中找(系统之会在跟目录下查找,所以需要完整类名),如果找不到的话会去CLASSPATH所设置的目录去找。然后加载到java虚拟机中。如果要使用到其他的在JAVA_HOME中没有的类或者是其他公司提供的第三方的.jar(jar包)文件时,要把它的路径及文件名加到CLASSPATH中。
系统会在每个java程序中隐含导入了java.lang这个包,import 包名,导入包中的类文件。
java.lang包,这是一个基础包。 java.util包,这个包是工具类的包。
java.io包,这个包是用于输入输出操作的 java.net包,这个包是用于网络编程。
java.awt,java.swing,javax.swing java.event包,这些包用于java的图形编程用的包。
applaction java的应用程序,java应用程序中必须有一个main()方法。
第二节标识符和关键字
Java代码中的“;”、“{}”、“ ”
Java语句以分号分隔,Java代码块包含在大括号内,忽略空格。
※标识符
1) 用以命名类、方法和变量、以及包遵守JAVA的命名规范类以每个单词。方法和变量第一个字母不大写,其他都以大写字母开头。2) 只能以字符、“_”或“$”开头; 3) 无长度限制。
※java中的关键字
goto和const在java中虽然不再使用但是还作为关键字存在。
java中没有sizeof关键字了,java中的boolean类型的值只能用true和false,且这两值也是关键字。java语言中没有无符号(unsigned)关键字。
第三节 java中的数据类型
1) 整型
byte 1字节 8位 -128到127
short 2字节 16位 -2^15到2^15-1
int 4字节 32位 -2^31到2^31-1
long 8字节 64位 -2^63到2^63-1
2) 浮点类型
float 4字节 32位
double 8字节 64位
3) 字符类型
char 2字节 16位
4) 布尔型
boolean false/true
注意:
1) char是无符号的16位整数,字面值必须用单引号括起来; ‘a’
2) String 是类,非原始数据类型;
3) 长整型数字有一个后缀为“L”或“l”,八进制前缀为“0”,十六进制前缀为“0x”;
4) 黙认浮点类型为double;
5) float数据类型有一个后缀为“f”或“F”,Double数据类型后可跟后缀“D”或“d”;
6)char类型也可以用通用转译字符,但是不能用ASCII码。可以用“\u0000”这种格式,因为char型中使用的是unicode编码方式。
注意:整型值存放,正数存放原码(二进制码),负数则存放补码(原码按位取反末位加一)。
注:实型值在存储时会损失精度,所以不要直接比较两个实型值。系统默认的实型都是double型,要使用float型时要在数据后加个f,或者强行转换,强转(占字节数大的类型转到占字节数小的类型)时会放弃高位值只取低位值。
java中的数字数据类型转换由占字节数小的类型到占字节数大的类型的可以有自动转换,反之则需要强行转换,char型和int型之间可以相互转换。char和short不能相互转换。
注意:隐式类型转换;
a 运算符 b ,如果a,b中有任意一个是double型,前面运算的结果就是double型,如果a,b中有任意一个是float型,前面运算的结果就是float型,如果a,b中有任意一个是long型,前面运算的结果就是long型,如果a,b中没有double、float、long型,那么其结果就为int型。
所有基本数据类型在使用时会事先分配空间,值本身就存在空间中,在传递时,就是值传递,不是引用传递。
在类中定义的方法在返回值前加上static修饰符就可以在main方法中调用了。如果不用static那就需要在main方法中创建对象,使用对象来调用对象的方法。例如;
public class Test{
public static void main(String[] args){
Test t=new Test(); int b=1; int c=2; int[] a=new int[10];
t.sqort(a); add(b,c)
}
public int[] sqort(int[] a){
.......
}
static int add(b,c){
.......
}
}
第四节 java中的运算符(java的运算符的优先级和结合性和c++相同)
System.out.println(3/2) 按整型计算 得1
1) >>= 前面是零补零,前面是一补一;
2) >>>= 无符号右移(强制右移都会移进一),
>>=和>>>=对于负数不一样
正数:右移n位等于除以2的n次方
负数:变成正数。
3) && 短路与,前面为假,表达式为假,后面的操作不会进行,& 会对所有条件进行判断。
4) || 短路或,前面为真,表达式为真,后面的操作不会进行,| 会对所有条件进行判断。
例:if(a<3&(b=a)==0) b赋值
if(a<3&&(b=a)==0) b不赋值
5)instanceof,是用于判断一个对象是否属于某个类型
6)java中的求余运算符“%”可以对两个实型变量求余
×?注意:按位与是为了让某些位置一,按位或是令某些位置零,按位异或是令某些位取反。
注意:使用左右位移和无符号右移运算符的使用方法是 变量名<<=位移位数 ,变量名>>=位移位数 (前两个运算符是不会忽略整形符号位,也称逻辑位移),变量名>>>=位移位数
注意:左右位移和无符号右移运算符只能用于整形及其兼容类型(byte,int,short,long)
第五节 java 语句
※java的流程控制
控制流
if()
if()….else
if()…..else if()….else
注意:else只是和其上面的同层的最近的if()来配对。
switch(){
case 'a':……..
case 1:……break;
default:
…………
}
注解:switch()内数据类型为byte short char int类型,只有以上四种类型的才可以在switch()中使用。case块中不加break时会按顺序执行下面的语句。
循环语句
for(int i=0;i<n;i++){}
while(){}
do{} while();-----------注意加分号
例子:
loop:for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(3==j){
break loop; /*loop为标签 只能用在循环语句中,循环
嵌套中用于跳到外层循环*/
}
}
}
辨析:
int x,a=6,b=7;
x=a++ + b++; // a=7,b=8,x=13
×?int x=6;x=~x; // 6的二进制0110 取反得11001 再转成补码(取反加一) 10111 = -7
break,跳出本层循环,执行后面的代码,continue,提前终止本次循环,再一次进行循环或循环条件满足或不满足后退出循环。break 标签名; continue 标签名;这两条语句知识表示跳出有标签的循环和提前终止本次有标签的循环,只能用在循环语句(多层循环嵌套)中,循环嵌套中用于跳到外层循环。
注意:for循环在使用时一定要注意不要忘记()中的两个";",死循环的写法for(;;){}或者是用while(true){}
注意:System.out.println("..."+a)在使用这个语句时,它会将其中非字符串(String)的值转换成字符串(不是所有数据类型都可以的)。
第六节数组
java中的数组Array,其包含两个部分,分别是数组的引用和数组的空间两部分。
声明数组
1) 一组相同类型(可以是类)数据的集合; 2) 一个数组是一个对象;
3) 声明一个数组没有创建一个对象; 4) 数组能以下列形式声明:
int[] i 或 int i[]
Car[] c 或 Car c[]
*C++中只能 Car c[]
*JAVA中推荐用 Car[] c;
5)数组的定义 如:
int[] a(数组引用声明)=new int[10](数组空间的声明,并把空间首地址赋值给数组的引用)
int[] a;
a=new int[20];
创建数组
1) 创建基本数据类型数组 int[] i = new int[2];
2) 创建引用数据类型数组 Car[] c = new Car[100];
3) 数组创建后有初始值。
数字类型为0 布尔类型为false 引用类型为null
注意:访问没有初始化的数组中的值,是会抛出异常的(NULLpointerException),java中只保证一位数组的地址是连续的,二维数组实际上是一维数组中有存储了一维数组的引用。
初始化数组
1) 初始化、创建、和声明分开
int[] i;
i = new int[2];
i[0] = 0;
i[1] = 1;
2) 初始化、创建、和声明在同一时间
int[] i = {0,1};
Car[] c = {new Car(),new Car()};
多维数组
1) 有效定义
int[][] i1 = new int[2][3]; (同时给定一维,二维的空间)
int[][] i2 = new int[2][]; (给定一维的空间,二维空间待定)
i2[0] = new int[2],i2[1] = new int[3];
*C++中 int[][] =new int[][3];有效
2) 无效定义
int[][] i1 = new int[][3];
3) 数组长度 -----数组的属性length(在二维数组中这个属性只代表第一维的长度)
int[] i = new int[5];
int len = i.length; //len = 5;
Student[][] st = new Student[4][6];
len = st.length; //len = 4;
len = st[0].length; //len = 6;
数组拷贝
System.arrayCopy(Object src, int srcPos, Object dest, int destPos, int length);
src源数组,srcPos从第几位开始拷贝,dest目标数组,destPos目标数组放置的起始位置,length,表示要拷贝的长度。拷贝一个数组到另一个数组。
类的对象的创建和对象数组
一个xxx.Java文件中可以定义多个类但是只能由一个public修饰的类,也只能以这个类的类名作为.java的文件名。
java中的类的对象的创建,要先创建这个对象的引用, 例如:Car c;然后用new这个关键字创建一个对象的实例(对象的空间) 例如:c=new Car();,然后对象的实例的空间首地址赋值给对象的引用。多个对象的引用可以同时引用自同一个对象的实例,但是对象的引用只能引用一个对象的实例。
对象的引用和对象的实例间就像是牵着气球的线和气球一样。
注意:只有一个没有被任何对象的引用所引用的对象的实例才会变成垃圾等待被垃圾回收。
对象数组
例:Car[] c=new Car[3];
c[0]=new Car();
注意:存放基本类型的数组的数据是直接存放在数组的空间中,而对象的数组在数组空间中存放的则是对象的引用。
定义在类中类的属性是实例变量,定义在类的方法中的变量是局部变量。实例变量是保存在对象空间中的,而局部变量则是在方法调用的分配空间,调用结束后就释放空间。
注意:在类的定义中属性的定义和方法的定义必须写在类里。
注意:系统会自动初始化实例变量,数字类型为0 ,布尔类型为false ,引用类型为null。局部变量需要初始化,必须赋初值。如果不赋初值无法通过编译。
Java中的方法调用中参数传递有两种,一个是对于参数是基本类型的使用的是值传递(直接传参数的值),另一个是引用传递,它是用于参数是类的对象,它传递的是这个对象的引用。
第二章面向对象的编程
第一节 面向对象的思想
anything is Object(万物皆对象)
抽象,从对具体的对象中抽取有用信息。
对象有其固有属性,对象的方法,即对象的行为(对象能做什么)。
对象本身是简单的(功能简单),多个对象可以组成复杂的系统(对象之间彼此调用对方的方法)。
对象应当是各司其职(功能简单),各尽所能(把自己的功能作到最好)。(弱耦合性实现了前面所述的对象的特点)
对象的耦合性,是对象之间的联系,对象和系统之间的联系。对象的耦合性要尽量的弱,也就是对象之间的联系尽可能的弱,对象和系统之间的联系尽可能的弱。
系统的可插入性,是在系统中加入新的对象之后的系统稳定性。
对象的可替换性,是在系统中替换原有的对象之后的系统的稳定性。
复用性,即对象可否被重复使用,对象的功能越简单,复用性就越好。(对象的耦合性弱,复用性就比较强)
面向过程是先有算法,后又数据结构(怎么解决问题)
面向对象是先有对象(数据结构),后有算法。(用什么做)
类是某些有着相同属性的集合的抽象。
类是一个类对象的模板,对象是类的具体化。
类是一个新的数据类型,类的对象。
注意:局部变量的作用范围是在定义它的代码块以内,局部变量要先赋值后使用,在以一个重合的作用于范围内不允许两个局部变量命名冲突。局部变量局部优先,且与实例变量同名时会覆盖局部变量。
变量 包括简单变量(原始数据类型),对象变量。
方法的定义:
1,方法的修饰符(多个修饰符出现的顺序无关) |
2,方法的返回值类型 |顺
3,方法名 |序
4,方法的参数表 |向
5,方法中允许抛出的异常 |下
java中不能够在返回语句后写任何代码。JVM+解释器=JRE,JRE+类库=JDK
java中方法的重载(overload)方法名相同,参数表不同,返回值类型可以不同。调用时要给出明确参数并确定调用某一方法。在编译时,编译器会根据参数选择适当的方法,所以重载也叫编译时多态。
就近向上匹配原则
如果方法的参数表中的数据类型和调用时给出的参数类型不尽相同时会根据向上匹配的就近原则。(类型就近向上转化匹配)
注意:调用时要给出明确参数并确定调用某一方法,否则编译会出错。
对象使用者(调用其他对象的方法)对象(对象中的方法被调用时根据参数进行自己进行选择)
一类方法,但跟据不同的参数会有差异,对象会根据参数判断,对对象调用者透明。
创建对象的过程,1,分配空间 2,初始化属性 3,调用构造方法(有前提,不考虑继承关系)。
构造方法的写法,没有返回值类型,构造方法的方法命名必须和类名相同。如果在类中不写构造方法,系统会提供一个无参的构造方法。
注意:最好在写类时提供一个无参的构造方法。
获得对象的方式
通过new(在堆空间中申请分配空间),new 类名(),可以通过这种形式获得一个对象,这时的对象是无法使用,必须把的它的地址存放进一个对象变量才能够使用。例如 :Car c=new Car();
有参的构造方法在被调用时,在用new关键字或的对象时初始化,例如:Car c=new Car("yellow")
对象变量中存放的是对象的引用(地址的封装形式)
this关键字,表示当前对象(哪个对象调用了方法,哪个对象就是当前对象),可以用来区分实例变量和局部变量。this(),表示调用本类其他的构造方法,注意,只能写在构造方法的第一行。
java中的参数传递,简单类型的变量传递的是数值,对象变量的传递则传递的一个引用(地址)。
第二节封装、继承、多态
面向对象的三大特征:封装、继承、多态。
※java中的封装
封装,一个对象和外界的联系应当通过一个统一的接口,应当公开的公开,应当隐藏的隐藏。(对象的属性应当隐藏),一个对象的内部是透明的,就是把对象内部的可透明性和隐藏的特性区分开,该透明的透明,该隐藏的隐藏。
(封装的属性)java中类的属性的访问权限的默认值不是private,要想隐藏该属性或方法,就可以加private(私有)修饰符,来限制只能够在类的内部进行访问。
对于类中的私有属性,要对其给出一对方法(getXxx(),setXxx())访问私有属性,保证对私有属性的操作的安全性。
方法的封装,对于方法的封装,该公开的公开,该隐藏的隐藏。方法公开的是方法的声明(定义),即(只须知道参数和返回值就可以调用该方法),隐藏方法的实现会使实现的改变对架构的影响最小化。。
封装会使方法实现的改变对架构的影响最小化。
完全的封装,类的属性全部私有化,并且提供一对方法来访问属性。
※java中的继承
继承,是对有着共同特性的多类事物,进行再抽象成一个类。这个类就是多类事物的父类。父类的意义在于可以抽取多类事物的共性。
java中的继承要使用extends关键字,并且java中只允许单继承,也就是一个类只能有一个父类。这样就使继承关系呈树状,体现了java的简单性。
子类只能继承在父类中可以访问的属性和方法(实际上父类中私有的属性和方法也会被继承但子类中无法访问罢了)。
※访问控制修饰符:(可以修饰属性和方法)
private修饰符,表示只有本类内部可以访问。
default修饰符,方法不加修饰符,会默认为default,表示在同一个包中可以访问,父子类在同一包中,子类可以继承父类的相应内容。(可以修饰类)
protected(保护)修饰符,表示同一包中可以访问,不同包的子类也可以访问继承。
public修饰符,表示公开,在任何地方都可以访问。(可以修饰类)
修饰符的权限是由上而下逐渐变宽的。
继承的意义,就在于子类可以在父类的基础之上对父类的功能进行发展,继承可以使系统的耦合性降低,也就是使对象间的联系便的松散,使多类对象间的联系用其父类对象代替。
注意:构造方法不能被继承。
父类的属性及方法的确定:要从子类的角度来看子类间的共性,当所有子类都有这个属性时,就应当考虑是否该放在父类中,方法也是如此,方法可以被看作是对象的行为,而类的方法这时这一类对象所共有的行为,所以也应当在方法的确定时注意是不是所有的子类型中都需要有这种方法,并且会根据不同的类型的行为的方式也不同才可以覆盖着个方法。
※java中方法的覆盖
子类中有和父类中可访问(可继承到子类)的同名同返回类型同参数表的方法,就会覆盖从父类继承来的方法。
注意:在jdk1.4以前要求方法的覆盖时,需要方法的返回值,参数表,方法名必须严格相同,而在jdk1.5中方法覆盖,子类中的覆盖的方法的返回值可以是父类中被覆盖的方法的返回值类型的子类型。
注意:子类的方法覆盖父类的方法时,方法的修饰符要么相同,要么子类中的方法的修饰符表示的访问权限要宽于父类。父类中的私有方法,不能被继承到子类,就是说子类中即使将其覆盖了也不会有多态。
覆盖的意义:对从父类中继承的方法的发展。
注意:父子类中有同名的属性不叫子类覆盖了父类的属性,这种情况较作属性的遮盖(shadow)。
当构造有继承关系的对象的步骤
1,递归的构造父类的对象
2,分配空间
3,初始化本类实例变量(属性)
4,调用本类的构造方法
注意:子类对象中其实包含着父类的对象,也就是父类对象加上子类对象,才是完整的子类对象的实例。
super关键字
super(),表示在子类的构造方法中调用父类的构造方法(可以通过这种方法在子类的构造方法中初始化父类中的属性),super()也只能出现在构造方法的第一句上。super(),在子类的构造方中指明构造父类时调用哪一个父类的构造方法构造父类。
super,这里所表示的是一个父类的对象,可以通过super来使用父类中可以访问的方法(可以在父类中定义setXxx(),getXxx()方法来访问父类中的私有属性),super可以屏蔽父子类中同名属性的冲突。
注意:在写类的时候,一定要写默认无参的构造方法,如果一个构造方法的第一句既不是this(),也不是super()时,那么就会在这里隐含的调用它的父类的无参的构造方法,即隐含的有super()。
少覆盖原则:既子类应当尽量少的覆盖父类方法,如果覆盖了父类的大多数方法,那就应当考虑是否应当有继承关系
※java中的多态(以子类覆盖了父类的方法为前提)
多态,把子类对象主观的看作是其父类型的对象,那么父类型就可以是很多种类型。
多态,编译时多态(方法的重载)
运行时多态(多态)
编译时类型,也就是可以被看作的类型,主观认定。
运行时类型,也就是实际的对象实例的类型,客观不可改变(也是被看作类型的子类型)
对于一个对象来说,在对象产生时,运行时类型就已经确定不会再改变,编译时类型可以和运行时类型不同。在对象变量声明时可以确定其运行时类型,但是编译时类型对象变量背后所指向运行时类型则可以是其本类型或者是其子类型。
多态三特性
1,对象实例确定则不可改变(客观不可改变)。
2,只能调用编译时类型所定义的方法。
3,运行时会根据运行时类型去调用相应类型中定义的方法。
多态的意义:在需要使用一类对象的共性时,可以用多来屏蔽掉其子类中的差异。
注意:类的属性是没有多态的,只会根据编译时类型访问。只有子类覆盖了父类的方法,且把子类对象当作父类类型来看时才会有多态。要注意区分子类中的方法重载。对于方法的重载,则是会使用编译时类型来进行相应的方法调用。
两种复用
白箱复用,也就是继承复用,父类中的可以被子类访问到的就可以被继承,这样会有些不需要的内容被继承下来,所以这种方式不太好。
黑箱复用,也叫组合复用,也就是把要复用代码的类的对象作为本类中的一个属性,然后再通过方法的委托来实现由选择的复用,方法的委托就是在本类的方法内部通过该类的对象调用要使用类的方法。
注意:尽量用组合复用替代继承复用。
多态的使用
多态用于参数,可以在方法的参数中传入其父类类型,在运行时会根据实际的运行时类型来在方法中进行相应的操作。
多态用于返回值,可以在方法的返回值类型上是用其实际返回值的父类型,在使用期返回值时也不必关心其实际类型。
多态可以使代码变得更通用,以适应需求的变化。也就是定义在父类中的方法,可以在子类中有不同的实现将其覆盖,在为父类型的对象变量赋值相应需要功能的子类的对象实例。
第三节 java中的修饰符
※static 表示静态,它可以修饰属性,方法和代码块。
1,static修饰属性(类变量),那么这个属性就可以用 类名.属性名 来访问,也就是使这个属性成为本类的类变量,为本类对象所共有。这个属性就是全类公有。(共有的类变量与对象无关,只和类有关)。
类加载的过程,类本身也是保存在文件中(字节码文件保存着类的信息)的,java会通过I/O流把类的文件(字节码文件)读入JVM(java虚拟机),这个过程成为类的加载。JVM(java虚拟机)会通过类路径(CLASSPATH)来找字节码文件。
类变量,会在加载时自动初始化,初始化规则和实例变量相同。
注意:类中的实例变量是在创建对象时被初始化的,被static修饰的属性,也就是类变量,是在类加载时被创建并进行初始化,类加载的过程是进行一次。也就是类变量只会被创建一次。
2,static修饰方法(静态方法),会使这个方法成为整个类所公有的方法,可以用类名.方法名 访问。
注意:static修饰的方法,不直接能访问(可以通过组合方式访问)本类中的非静态(static)成员(包括方法和属性),本类的非静态(static)方法可以访问本类的静态成员(包括方法和属性),可以调用静态方法。静态方法要慎重使用。在静态方法中不能出现this关键字。
注意:父类中是静态方法,子类中不能覆盖为非静态方法,在符合覆盖规则的前提下,在父子类中,父类中的静态方法可以被子类中的静态方法覆盖,但是没有多态。(在使用对象调用静态方法是其实是调用编译时类型的静态方法)
注意:父子类中,静态方法只能被静态方法覆盖,父子类中,非静态方法只能被非静态方法覆盖。
java中的main方法必须写成static的是因为,在类加载时无法创建对象,因为静态方法可以不通过对象调用
所以在类的main方法。所在在类加载时就可以通过main方法入口来运行程序。
注意:组合方式,就是需要在方法中创建一个所需要的对象,并用这个对象来调用任意所需的该对象的内容,不会再受只能访问静态的约束。
3,static修饰初始代码块,这时这个初始代码块就叫做静态初始代码块,这个代码块只在类加载时被执行一次。可以用静态初始代码块初始化一个类。
动态初始代码块,写在类体中的“{}”,这个代码块是在生成对象的初始化属性是运行。这种代码块叫动态初始代码块。
类在什么时候会被加载,构造(创建)对象时会加载类,调用类中静态方法或访问静态属性也是会加载这个静态方法真正所在的类。在构造子类对象时必会先加载父类,类加载会有延迟加载原则,只有在必须加载时才会加载。
※final修饰符,可以修饰变量,方法,类
1,final修饰变量
被fianl修饰的变量就会变成常量(常量应当大写),一旦赋值不能改变,(可以在初始化时直接赋值,也可以在构造方法里也可以赋值,只能在这两种方法里二选一,不能不为常量赋值),fianl的常量不会有默认初始值,对于直接在初始化是赋值时final修饰符常和static修饰符一起使用。
2,final修饰方法,被final修饰的方法将不能被其子类覆盖,保持方法的稳定不能被覆盖。
3,final修饰类,被final修饰的类将不能被继承。final类中的方法也都是final的。
注意:final,不能用来修饰构造方法,在父类中如果有常量属性,在子类中使用常量属性时是不会进行父类的类加载。静态常量如果其值可以确定,就不会加载该类,如果不能确定则会加载该常量所在的类。
不变模式,对象一旦创建属性就不会改变。用final修饰属性,也用final修饰类(强不变模式),用final修饰属性(弱不变模式)。
不变模式的典型体现:java.lang.String类,不变模式可以实现对象的共享(可以用一个对象实例赋值给多个对象变量。)
池化的思想,把需要共享的数据放在池中(节省空间,共享数据)
只有String类可以用“”中的字面值创建对象。在String类中,以字面值创建时,会到Java方法空间的串池空间中去查找,如果有就返回串池中字符串的地址,并把这个地址付给对象变量。如果没有则会在串池里创建一个字符串对象,并返回其地址付购对象变量,当另一个以字面值创建对象时则会重复上述过程。
如果是new在堆空间中创建String类的对象,则不会有上述的过程。
String类中的intern()方法会将在堆空间中创建的String类对象中的字符串和串池中的比对,如果有相同的串就返回这个串的串池中的地址。
不变模式在对于对象进行修改,添加操作是使相当麻烦的,会产生很多的中间垃圾对象。创建和销毁的资源的开销是相当大的。
String类在字符串连接时会先的效率很低,就是因为它所产生的对象的属性是不能够修改的,当连接字符串时也就是只能创建新的对象。
对于很多的字符串连接,应当使用StringBuffer类,在使用这个类的对象来进行字符串连接时就不会有多余的中间对象生成,从而优化了效率。
※abstract(抽象)修饰符,可以修饰类和方法
1,abstract修饰类,会使这个类成为一个抽象类,这个类将不能生成对象实例,但可以做为对象变量声明的类型,也就是编译时类型,抽象类就像当于类的半成品,需要子类继承并覆盖其中的抽象方法。
2,abstract修饰方法,会使这个方法变成抽象方法,也就是只有声明(定义)而没有实现,实现部分以";"代替。需要子类继承实现(覆盖)。
注意:有抽象方法的类一定是抽象类。但是抽象类中不一定都是抽象方法,也可以全是具体方法。
abstract修饰符在修饰类时必须放在类名前。
abstract修饰方法就是要求其子类覆盖(实现)这个方法。调用时可以以多态方式调用子类覆盖(实现)后的方法,也就是说抽象方法必须在其子类中实现,除非子类本身也是抽象类。
注意:父类是抽象类,其中有抽象方法,那么子类继承父类,并把父类中的所有抽象方法都实现(覆盖)了,子类才有创建对象的实例的能力,否则子类也必须是抽象类。抽象类中可以有构造方法,是子类在构造子类对象时需要调用的父类(抽象类)的构造方法。
final和abstract,private和abstract,static和abstract,这些是不能放在一起的修饰符,因为abstract修饰的方法是必须在其子类中实现(覆盖),才能以多态方式调用,以上修饰符在修饰方法时期子类都覆盖不了这个方法,final是不可以覆盖,private是不能够继承到子类,所以也就不能覆盖,static是可以覆盖的,但是在调用时会调用编译时类型的方法,因为调用的是父类的方法,而父类的方法又是抽象的方法,又不能够调用,所以上面的修饰符不能放在一起。
抽象(abstract)方法代表了某种标准,定义标准,定义功能,在子类中去实现功能(子类继承了父类并需要给出从父类继承的抽象方法的实现)。
方法一时间想不到怎么被实现,或有意要子类去实现而定义某种标准,这个方法可以被定义为抽象。(abstract)
※模板方法模式
用abstract把制订标准和实现标准分开,制定的标准就是模板,实现就是按模板标准来实现,也就是继承模板,实现模板中相应功能的方法。模板中不允许修改的方法可以用fianl来修饰,这个方法不能使抽象方法,为保证安全,封装,把模板中不公开的部分用protected(保护)修饰。
第四节 java中的接口
接口是一种程序结构,是特殊的抽象类。接口中的方法必须都是公开的抽象方法(public abstract),接口中的属性都是公开静态常量(public static final)。
声明一个接口用 interface 关键字,接口也是一种类型,编译之后也有生成相应字节码,它的声明规范也要符合类型的定义(一个源文件中只能有一个public interface,接口名和源文件名相同,有public interface,就不能在写public class了)。接口中的属性可以不加修饰符,方法也不用加修饰符。
接口也可以继承,但是只能由接口继承,在用类去继承时要换用 implements 关键字,这时类和接口也不叫做继承关系,而是实现关系,但其实质也是继承。
一个类可以继承也只能继承另外一个类,但是可以实现多个接口,其语法是在implements后面写接口名,多个接口以“,”分隔。
接口之间是可以多继承的,其语法和类的继承语法是相同的,在接口多继承时,在extends后写接口名如果要继承多个接口,接口名以“,”分隔,接口的继承关系只是把其父接口中的抽象方法继承到子接口中。要实现接口就必须实现接口中的所有方法。
一个类可以在继承一个类的同时,也可以实现一个或多个接口。采用接口就绕开了单继承限制。
接口类型也可以做为编译时类型使用,但其实际的运行时类型必须是完全实现接口的类的对象实例,这样就使多态变得很灵活了,
注意:实现接口时,在实现(覆盖)抽象方法时,注意必须要在方法的返回值类型前加public修饰符。如果没有完全实现接口中的方法,那么这个类就只能够是个抽象类,不能创建对象。接口的是实质就是特殊的抽象类。接口没有构造方法。
接口的意义:
1,接口可以实现多继承。
2,用接口可以实现混合类型(主类型,副类型),java中可以通过接口分出主次类型。主类型使用继承,副类型,使用接口实现。
3,接口进一步深化了标准的思想,接口本身就是一个标准,它起到了降低耦合性的作用,接口可以使方法的定义和实现相分离,也就是将接口的定义者和实现者相分离,接口也可以用于降低模块间或系统间的耦合性。针对接口编程可以屏蔽不同实现间的差异,看到的只是实现好的功能,
接口:定义标准,
接口的实现:实现标准
接口的调用者:标准的使用
针对接口编程原则,也就是按照标准实现。
先有接口的定义,再有接口使用者,最后把接口的实现对象纳入接口的使用者中,接口的使用者会通过接口来调用接口实现者的方法。
接口的定义者定义好了标准,接口的使用者先写好了使用代码,接口的实现者写好实现之后把实现对象传入接口的使用者中。它调用接口中方法也就是调用接口实现中的方法。这种过程叫做接口的回调。
尽量使用接口类型作为编译时类型,尽量将抽取到的共性行为写在接口中。
用若干个小接口取代一个大接口。(接口隔离原则)
把一个类的功能作成接口,只暴露想暴露的方法,接口隔离原则可以实现更高层次的封装,针对的对象不同,暴露的方法也不同。
第五节 java中的根类Object
java中所有的类的父类或直接或间接的或隐含的都是Object类。
java不允许循环继承,也就是互相继承是不可以的。
Object类中的finalize()一个对象被垃圾收集的时候, 一个对象被垃圾收集的时候,最后会由JVM调用这个对象的finalize方法
Object类中有一个String toString()方法,返回该对象的字符串表示。Object类中的toString()方法他返回的是类名加上它的地址的一个字符串。在子类中推荐覆盖toString()方法。
Object类中的boolean equals(Object o)方法是用来比较对象的内容是否相等,其返回值是boolean类型的值,相同为真,不同则为假。实际上还是比较对象地址是否相同。String类覆盖了equals()方法,它比较是对象中的内容是否相同。子类中也推荐覆盖Object类中继承的equals()方法
※equals()的覆盖原则,
自反性 x.equals(x) 为true
对称性 y.equals(x) 和 x.equals(y) 的值要相同,要么都为true,要么都为false。
传递性 x.equals(y)为true, y.equals(z)也为true ,那么x.equals(z)一定也为true。
※覆盖equals()方法的步骤
boolean equals(Object o){
if(this==o) return true; //1,看看是不是一个对象
if(o==null) return true; //2,看看对象是不是空
if(!(o instanceof 本类类名)) return false;//看看是不是本类对象
......//根据本类设计。
}
第六节封装类
JAVA为每一个简单数据类型提供了一个封装类,使每个简单数据类型可以被Object来装载。除了int(Integer)和char(Character),其余类型首字母大写即成封装类类型名。
转换字符的方式:
int I=10;
String s=I+” ”;
String s1=String.valueOf(i);
Int I=10;
Interger I_class=new integer(I);
封装类.字符串.基本类型
Interger--------------------(Double(x.toString))------------>Double
String -----------------(Integer.valueOf() )---------------->Integer
Integer-----------------(x.toString() )--------------------->String
int----------------------(100+“”)------------------------->String
String------------------(Integer.parseInt() )--------------->int
Integer-----------------(Integer.intValue() )--------------->int
学会查看javadoc的帮助文档。要先关注要使用方法的返回值类型,也就是要获得内容的类型,然后看方法名,JDK中的方法名基本上是见名知义,参数表,就是看需要什么才可以获得的需要的那些内容,也要看自己能够提供什么。
注意:“==”在任何时候都是比较地址,这种比较永远不会被覆盖。
程序员自己编写的类和JDK类是一种合作关系。(因为多态的存在,可能存在我们调用JDK类的情况,也可能存在JDK自动调用我们的类的情况。)
注意:类型转换中double\interger\string之间的转换最多。
第七节内部类
(注:所有使用内部类的地方都可以不用内部类,但使用内部类可以使程序更加的简洁,便于命名规范和划分层次结构)。
内部类是指在一个外部类的内部再定义一个类。
*内部类可为静态,可用PROTECTED和PRIVATE修饰。(而外部类不可以:顶级类只能使用PUBLIC和DEFAULT)。
*JAVA文件中没有public class 可以类名和文件不同名。
内部类:内部类也就是定义在类内部的类。
内部类的分类
成员内部类、局部内部类、静态内部类、匿名内部类(图形是要用到,必须掌握)。
※成员内部类
四个访问权限修饰符都可以修饰成员内部类。
内部类和外部类在编译时是不同的两个类,内部类对外部类没有任何依赖。
内部类是一种编译时语法,在编译时生成的各自的字节码文件,内部类和外部类没有关系。
内部类中可以访问外部类的私有成员。
作为外部类的一个成员存在,与外部类的属性、方法并列。
内部类和外部类的实例变量可以共存。
在内部类中访问实例变量:this.属性
在内部类访问外部类的实例变量:外部类名.this.属性。
在外部类的外部访问内部类,使用out.inner.
※成员内部类的特点:
1.内部类作为外部类的成员,可以访问外部类的私有成员或属性。(即使将外部类声明为private,但是对于处于其内部的内部类还是可见的。)
2.用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。
对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。
3.成员内部类不能含有静态成员。
建立内部类对象时应注意:
在外部类的内部可以直接使用inner s=new inner();(因为外部类知道inner是哪个类,所以可以生成对象。)
而在外部类的外部,要生成(new)一个内部类对象,需要首先建立一个外部类对象(外部类可用),然后在生成一个内部类对象。内部类的类名是外部类类名.内部类类名。
Outer o=new Outer();
Outer.Inner in=o.new.Inner()。
※静态内部类
(注意:前三种内部类与变量类似,所以可以对照参考变量)
静态内部类定义在类中,任何方法外,用static class定义。
静态内部类只能访问外部类的静态成员。
生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。
静态内部类的对象可以直接生成:
Outer.Inner in=new Outer.Inner();
而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。静态内部类不可用private来进行定义。
注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。
用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。
例子:
对于两个类,拥有相同的方法:
class People
{
run();
}
interface Machine{
run();
}
此时有一个robot类:
class Robot extends People implement Machine.
此时run()不可直接实现。
interface Machine
{
void run();
}
class Person
{
void run(){System.out.println("run");}
}
class Robot extends Person
{
private class MachineHeart implements Machine
{
public void run(){System.out.println("heart run");}
}
public void run(){System.out.println("Robot run");}
Machine getMachine(){return new MachineHeart();}
}
class Test
{
public static void main(String[] args)
{
Robot robot=new Robot();
Machine m=robot.getMachine();
m.run();
robot.run();
}
}
局部内部类
在方法中定义的内部类称为局部内部类。
与局部变量类似,在局部内部类前不加修饰符public和private,其范围为定义它的代码块。
注意:局部内部类不仅可以访问外部类私有实例变量,但可以访问外部类的局部常量(也就是局部变量必须为final的)
在类外不可直接访问局部内部类(保证局部内部类对外是不可见的)。
在方法中才能调用其局部内部类。
通过内部类和接口达到一个强制的弱耦合,用局部内部类来实现接口,并在方法中返回接口类型,使局部内部类不可见,屏蔽实现类的可见性。
局部内部类写法
public class TestLocalInnerClass{
public static void main(String[] args){
Outer o=new Outer();
final int a=9;
o.print(a);
}
}
class Outer{
private int index=100;
public void print(final int a){
final int b=10;
System.out.println(a);
class Inner{
public void print(){
System.out.println(index);
System.out.println(a);
System.out.println(b);
}
}
Inner i=new Inner();
i.print();
}
}
匿名内部类
匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口。
匿名内部类的特点:
1,一个类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的事先或是覆盖。
2,只是为了获得一个对象实例,不许要知道其实际类型。
3,类名没有意义,也就是不需要使用到。
注:一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。
因其为局部内部类,那么局部内部类的所有限制都对其生效。
匿名内部类是唯一一种无构造方法类。
大部分匿名内部类是用于接口回调用的。
匿名内部类在编译的时候由系统自动起名Out$1.class。
如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。
因匿名内部类无构造方法,所以其使用范围非常的有限。
当需要多个对象时使用局部内部类,因此局部内部类的应用相对比较多。匿名内部类中不能定义构造方法。
匿名内部类的写法:
interface A{
void ia();
}
class B{
public A bc(){
return new A{
void ia(){
}
};
}
}
使用匿名内部类:
B b=new B();
A a=b.bc();
a.ia();
Exception(例外/异常)
对于程序可能出现的错误应该做出预案。
例外是程序中所有出乎意料的结果。(关系到系统的健壮性)
JAVA会将所有的异常封装成为一个对象,其根本父类为Throwable。
异常的分类
Throwable有两个子类:Error和Exception。
一个Error对象表示一个程序错误,指的是底层的、低级的、不可恢复的严重错误。此时程序一定会退出,因为已经失去了运行所必须的物理环境。对于Error错误我们无法进行处理,因为我们是通过程序来应对错误,可是程序已经退出了。
我们可以处理的Throwable类中只有Exception类的对象(例外/异常)。
Exception有两个子类:Runtime exception(未检查异常)可以在编程时避免,可处理可不处理
非Runtime exception(已检查异常)必须进行处理。
注意:无论是未检查异常还是已检查异常在编译的时候都不会被发现,在编译的过程中检查的是程序的语法错误,而异常是一个运行时程序出错的概念。
在Exception中,所有的非未检查异常都是已检查异常,没有另外的异常!!
未检查异常是因为程序员没有进行必要的检查,因为他的疏忽和错误而引起的异常。一定是属于虚拟机内部的异常(比如空指针)。
应对未检查异常就是养成良好的检查习惯。
已检查异常是不可避免的,对于已检查异常必须实现定义好应对的方法。
已检查异常肯定跨越出了虚拟机的范围。(比如“未找到文件”)
异常的传递
如何处理已检查异常(对于所有的已检查异常都要进行处理):
首先了解异常形成的机制:
当一个方法中有一条语句出现了异常,它就会throw(抛出)一个例外对象(throw 异常对象),然后后面的语句不会执行返回上一级方法,其上一级方法接受到了例外对象之后,有可能对这个异常进行处理,也可能将这个异常转到它的上一级。
注意:当一个方法中出现了异常,没有进行异常处理,方法就会把异常对象作为返回值返回。如果有异常进入虚拟机,那么虚拟机就会立刻中止程序的执行。
异常的处理方式
非RuntimeException (已检查异常)这种异常必须处理。如果不处理编译出错。
对于接收到的已检查异常有两种处理方式:throws和try..catch(...){}方法。
注意:出错的方法有可能是JDK,也可能是程序员写的程序,无论谁写的,抛出一定用throw。
在方法的定义中声明方法可能抛出的异常,用(throws 异常类名,异常类名) ,声明这个方法将不处理异常,并把异常交给上一级方法处理。可以抛出的是实际产生异常的父类的异常对象。
例:public void print() throws Exception.
对于方法a,如果它定义了throws Exception。那么当它调用的方法b返回异常对象时,方法a并不处理,而将这个异常对象向上一级返回,如果所有的方法均不进行处理,返回到主方法,程序中止。(要避免所有的方法都返回的使用方法,因为这样出现一个很小的异常就会令程序中止)。
如果在方法的程序中有一行throw new Exception(),返回错误,那么其后的程序不执行。因为错误返回后,后面的程序肯定没有机会执行,那么JAVA认为以后的程序没有存在的必要。
try..catch捕获异常
对于try……catch格式:
try {可能出现错误的代码块} catch(exception e){进行处理的代码} ;
对象变量的声明
用这种方法,如果代码正确,那么程序不经过catch语句直接向下运行;
如果代码不正确,则将返回的异常对象和e进行匹配,如果匹配成功,则处理其后面的异常处理代码。(如果用exception来声明e的话,因为exception为所有exception对象的父类,所有肯定匹配成功)。处理完代码后这个例外就完全处理完毕,程序会接着从出现异常的地方向下执行(是从出现异常的地方还是在catch后面呢?利用程序进行验证)。最后程序正常退出。
try块中的代码如果没有出现异常,就会跳过catch,正常执行。
try中如果发现错误,即跳出try块去匹配catch,那么try后面的语句就不会被执行。
一个try可以跟进多个catch语句,用于处理不同情况。当一个try只能匹配一个catch。
我们可以写多个catch语句,但是不能将父类型的exception的位置写在子类型的excepiton之前,因为这样父类型肯定先于子类型被匹配,所有子类型就成为废话,java中是不允许写废话的,所以编译会出错。
在try,catch后还可以再跟一子句finally。其中的代码语句无论如何(无论有没有异常)都会被执行(因为finally子句的这个特性,所以一般将释放资源,关闭连接的语句写在里面)。finally中的代码在和try中的代码的冲突时,finally中的代码一定会被执行且会忽略try中的代码。但是System.exit(0);(虚拟机退出语句)则不会去执行fianlly中的代码。
try{..}catch(..){..}
try{..}catch(..){}finally{..}
try{..}finally{}
以上三种写法都可以。
如果在程序中书写了检查(抛出)exception但是没有对这个可能出现的检查结果进行处理,那么程序就会报错。而如果只有处理情况(try)而没有相应的catch子句,则编译还是通不过。
如何知道在编写的程序中会出现例外呢
1.调用方法,查看API中查看方法中是否有已检查错误。
2.在编译的过程中看提示信息,然后加上相应的处理。
Throwable有一个message属性。在使用catch的时候可以调用:
Catch(IOException e){System.out.println(e.message())};
Catch(IOException e){e.printStackTrace()};
以上两条语句都是可以打印出错的过程信息。告诉我们出错类型所历经的过程,在调试的中非常有用。
开发中的两个道理:
①如何控制try的范围:根据操作的连动性和相关性,如果前面的程序代码块抛出的错误影响了后面程序代码的运行,那么这个我们就说这两个程序代码存在关联,应该放在同一个try中。
②对已经查出来的例外,有throw(消极)和try catch(积极)两种处理方法。
对于throws把异常抛到try catch能够很好地处理例外的位置(即放在具备对例外进行处理的能力的位置)。如果没有处理能力就继续上抛。
当我们自己定义一个例外类的时候必须使其继承excepiton或者RuntimeException。
throw是一个语句,用来做抛出例外的功能。
而throws是表示如果下级方法中如果有例外抛出,那么本方法不做处理,继续向上抛出。
throws后跟的是例外类型。
注意:方法的覆盖中,如果子类的方法抛出的例外是父类方法抛出的例外的父类型,那么编译就会出错:子类无法覆盖父类。
结论:子类方法不可比父类方法抛出更多的例外。子类抛出的例外或者与父类抛出的例外一致,或者是父类抛出例外的子类型。或者子类型不抛出例外。如果父类型无throws时,子类型也不允许出现throws。此时只能使用try catch。
断言是一种调试工具(assert)
其后跟的是布尔类型的表达式,如果表达式结果为真不影响程序运行。如果为假系统出现低级错误,在屏幕上出现assert信息。
Assert只是用于调试。在产品编译完成后上线assert代码就被删除了。
java中的图形界面
GUI,图形化的用户接口,为了人机交互使用的。
构造图形界面的步骤
1,选择一个容器
2,设置容器的布局管理器
3,向容器添加组件
4,事件的监听
容器(Container)用于管理其他的组件的对象。组件必须放到容器里。
JFrame,这是一个最顶层的窗体容器,所有其他的组件必须放在顶层容器里。
JDialog 对话框容器,他要依附于其父组件,他不是一个顶层容器。
JPanel,他不是顶层容器,必须放在顶层容器中,任何一个容器都有add()方法,Panel面板是透明的(默认)。他也是一个组件。
布局管理:对于任何一个容器类中都有setLayout()方法,用容器对象调用这个方法,来设置容器的布局管理器(LayoutManager这是一个接口,所有布局管理器都实现了这个接口)。
可用的布局管理器:
FlowLayout,流式布局管。Panel的默认布局管理就是FlowLayout。
BorderLayout,按方位进行布局管理,(North,South,East,West,Middle)不明确指定,就会默认加载在中间(Middle),
add(Component comp,String place)这个方法是在指定的位置添加组件。
GridLayout,网格布局,通过行列,间距,来用网格分割,把组件放入如网格中,先行后列摆放组件。
CardLayout,卡片布局,面板重叠放置。
GridBogLayout,组件可以跨行跨列的网格布局。
注意:一定要在图形界面都其他功能都设置好之后才能设置可见性。
JButton :按钮
JTextField:单行文本域
JTextArea:多行文本区
JScrollPane:滚动窗体
JComboBox:下拉选择框
JRadioButton:单选按钮
JCheckBox:多选按钮
JList:多行列表
JLabel:标签
JPasswordField:密码输入框
JEditorPane:显示结构化文档
Border:边框
JMenuBar:菜单条
JMenu:菜单
JMenuItem:菜单项
JPopupMenu:弹出式菜单
JSlider:滑动条
JProgressBar:进度条
JTabbedPane:分层面板
JSplitPane:分隔面板
JToolBar:工具条
JFileChooser:文件选择器
JColorChooser:颜色选择器
显示对话框
JoptionPane 里面有很多静态方法可以弹出对话框
注意:具体的方法可以去参看Java2 SE的API文档。
awt事件模型(观察者模式)(重点)
事件模型中,包括事件源对象,事件处理者(事件监听者对象),事件对象。
事件源和事件处理者之间建立了授权关系,也就是在事件源类中有一个事件处理者的对象作为属性,也可能是一个事件处理者的集合。
事件对象
事件源————————〉事件处理者
这就是事件模型的机制,也就是由事件源对象发送一个消息(事件对象),然后事件处理者调用相应的方法处理事件。
在事件监听器接口中定义的方法,都要以事件对象为参数。
一个事件源可以注册多个同类型的监听器,也可以注册多种多个事件监听器,一个事件监听器也可以为多个事件源服务。
首先了解一下什么是发消息:A,B,C三个类,分别作为事件源,事件处理者,事件对象。在A类中有一个B类的属性或者是一个内容为B类对象的集合,也就是事件源和事件处理者之间的建立了授权关系,在B类需要实现一个自定义的接口,这个自定义的接口继承了EventListener,EventListener接口中没有定义任何方法,这只是一个标记接口。实现在自定义接口中定义好的用于事件处理的方法,C类要继承EventObject类。这些方法是以事件对象为参数的b(C c),而后在A类a(C c)方法中使用B类的对象调用B类中的b(C c)方法,并把事件对象作为参数,并在main方法中用A类的对象调用了a(c)方法,这也就叫做A类对象给B类发送了消息。
也就是说事件源对象间接调用了事件监听器的方法,并以事件对象为实参传到事件监听器的方法中,要就叫事件源给