第五章 面向对象的特点
5.1 继承
面向对象的重要特点之一就是继承。类的继承使得能够在已有的类的基础上构造新的类,新类除了具有被继承类的属性和方法外,还可以根据需要添加新的属性和方法。继承有利于代码的复用,通过继承可以更有效地组织程序结构,并充分利用已有的类来完成复杂的任务,减少了代码冗余和出错的几率。
继承通过extends 来表示。
class A extends B 表示类A继承了类B,B是父类,A叫子类。A类有B类的相应功能,并且还可以自己定义新的功能(方法及属性)
对于父类与子类相同的方法签名来说,叫方法的覆盖,或重写,以代替父类功能,但父类功能不消失。
super(参数) 可以调用父类的构造方法。
super.xxx(参数) 可以调用父类的xxx方法。
5.1.1 方法的重写(覆盖)
重新编写与父类同名同特征值的的方法,叫方法的重写。
重写后父类方法推动作用。
5.2 封装
在前边介绍的类、变量和方法的声明中都遇到了访问限定符,访问限定符用于限定类、成员变量和方法能被其他类访问的权限,当时我们只是简单介绍了了其功能,且只使用了public(公有的)和默认(友元的)两种形式。
在有了包的概念之后,我们将几种访问限定总结如下:
1. 默认访问限定
如果省略了访问限定符,则系统默认为是 friendly(友元的)限定。拥有该限定的类只能被所在包内的其他类访问。
2. public 访问限定
由 public 限定的类为公共类。公共类可以被所有的其他类访问。使用 public 限定符应注意以下两点:
1)public 限定符不能用于限定内部类。
2)一个 Java 源程序文件中可以定义多个类,但最多只能有一个被限定为公共类。如果有公共类,则程序名必须与公共类同名。
3.private(私有的)访问限定
private 限定符只能用于成员变量、方法和内部类。私有的成员只能在本类(this)中被访问,即只能在本类的方法中由本类的对象引用。
4.protected(保护的)访问限定
protected 限定符也只能用于成员变量、方法和内部类。用 protected 声明的成员也被称为受保护的成员,它可以被其子类(包括本包的或其他包的)访问,也可以被本包内的其他类访问。
综合上述,以表 5-1 简要列出各访问限定的引用范围。其中“√”表示可访问,“×”表示不可访问。
表 5-1访问限定的引用域和访问范围
|
同一个类 |
同一个包 |
不同包的子类 |
不同包非子类 |
public |
√ |
√ |
√ |
√ |
protected |
√ |
√ |
√ |
× |
缺省 |
√ |
√ |
× |
× |
private |
√ |
× |
× |
× |
5.2.1 JavaBean
用Java语言描述的软件组织模型就是JavaBean,它是Java中一种特殊的类,JavaBean在程序设计过程中,一般用在数据对象中,比如数据库中的某个数据一条数据。他是在程序设计过程中,传递数据对象的。
特点如下:
1)有一个无参的公共构造方法。(public)
2)有属性,属性最好都定义为私有的(private)
3)有与属性相对应的get和set方法。
如定义一上学生的JavaBean
public class StudentBean { private String name;//一般定义为private private int age; public JavaBeanTest() { } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
public class TestJavaBean {
public static void main(String[] args) { // TODO Auto-generated method stub StudentBean st = new StudentBean (); st.setAge(3); st.setName("张三"); } } |
5.3 抽象
5.2.1 抽象类的定义
在 Java 中所谓的抽象类,即是在类说明中用关键字abstract 修饰的类。
一般情况下,抽象类中可以包含一个或多个只有方法声明而没有定义方法体的方法。
什么时候用
当遇到这样一些类,类中的某个或某些方法不能提供具体的实现代码时,可将它们定义成抽象类。
格式
定义抽象类的一般格式如下:
[访问限定符] abstract class 类名
{
//属性说明
…………
//抽象方法声明
…………
//非抽象方法定义
……………
}
其中,声明抽象方法的一般格式如下:
[访问限定符] abstract 数据类型 方法名([参数表]);
注意:抽象方法只有声明,没有方法体,所以必须以“;”号结尾。
有关抽象方法和抽象类说明如下:
1)所谓抽象方法,是指在类中仅仅声明了类的行为,并没有真正实现行为的代码。也就是说抽象方法仅仅是为所有的派生子类定义一个统一的接口,方法具体实现的程序代码交给了各个派生子类来完成,不同的子类可以根据自身的情况以不同的程序代码实现。
2)抽象方法只能存在于抽象类中,正像刚才所言,一个类中只要有一个方法是抽象的,则这个类就是抽象的。
3)构造方法、静态(static)方法、最终(final)方法和私有(private)方法不能被声明为抽象的方法。
4)一个抽象类中可以有一个或多个抽象方法,也可以没有抽象方法。如果没有任何抽象方法,这就意味着要避免由这个类直接创建对象。
5)抽象类只能被继承(派生子类)而不能创建具体对象即不能被实例化。 下边我们举例说明抽象类的定义。
抽象:表示的是可以不完整,不抽象就一定完整
package cn.huasheng.chouxiang;
abstract class DongWu {
public String Name; public int age; public int sex;
public abstract void say(); public abstract void run();
DongWu() {}
public void setName(String name) { this.Name = name; } }
class Man extends DongWu { public void say() { System.out.println("boy"); } public void run() {
}
}
abstract class Woman extends DongWu { public void say() { System.out.println("girl"); } } class Girl extends Woman{
@Override public void run() { // TODO Auto-generated method stub }
}
public class PersonTest { public static void main(String[] arg) { // DongWu dw = new DongWu();抽象类不可以实例化,用来定义对象,只能被继承 Man man1 = new Man(); new Girl().say(); man1.say();
} public static void test() {
} } |
5.4 接口
在 Java 中可以把接口看作是一种特殊的抽象类,它只包含常量和和抽象方法的定义,而没有变量和方法的实现,它用来表明一个类必须做什么,而不去规定它如何做。因此我们可以通过接口表明多个类需要实现的方法。由于接口中没有具体的实施细节,也就没有和存储空间的关联,所以可以将多个接口合并起来,由此来达到多重继承的目的。
5.4.1 接口的定义
与类的结构相似,接口也分为接口声明和接口体两部分。
定义接口的一般格式如下:
[public] interface 接口名 [extends父接口名列表] //接口声明
{
//接口体开始
//常量数据成员的声明及定义
数据类型 常量名=常数值;
……………
//声明抽象方法
返回值类型 方法名([参数列表]) [throw异常列表] ;
…………………
} //接口体结束
对接口定义说明如下:
1) 接口的访问限定只有 public 和缺省的。
2) interface 是声明接口的关键字,与class 类似。
3) 接口的命名必须符合标识符的规定,并且接口名必须与文件名相同。
4) 允许接口的多重继承,通过“extends父接口名列表”可以继承多个接口。
5) 对接口体中定义的常量,系统默认为是“staticfinal”修饰的,不需要指定。
6) 对接口体中声明的方法,系统默认为是“abstract”的,也不需要指定;对于一些特殊用途的接口,在处理过程中会遇到某些异常,可以在声明方法时加上“throw 异常列表”,以便捕捉出现在异常列表中的异常。
5.4.2 接口的实现
所谓接口的实现,即是在实现接口的类中重写接口中给出的所有方法,书写方法体代码,完成方法所规定的功能。
定义实现接口类的一般格式如下:
[访问限定符] [修饰符] class类名 [extends 父类名] implements 接口名列表
{
//类体开始标志
[类的成员变量说明] //属性说明
[类的构造方法定义]
[类的成员方法定义] //行为定义
/*重写接口方法*/
接口方法定义 //实现接口方法
} //类体结束标志下边我们距离说明接口的实现。
package cn.huasheng.jiekou; class Class1{
} interface Interface1 { final int A=10; int B = 20; void fun1(); void fun2(); } interface Interface2 { final int A=10; int D = 20; void fun3(); void fun4(); } interface Interface3 extends Interface1,Interface2{
} class Inter1 extends Class1 implements Interface1,Interface2{ public void fun1() { System.out.println("fun1"); } public void fun2() { System.out.println("fun2"); } public void fun3() { System.out.println("fun3"); } public void fun4() { System.out.println("fun4"); } } public class TestInterface{ public static void main(String [] args){ Inter1 i = new Inter1(); i.fun1(); i.fun2(); i.fun3(); i.fun4(); } } |
5.5 异常
5.5.1 什么是异常
异常:就是不正常,是指程序在运行时出现的不正常情况。其实就是程序中出现的问题。这个问题按照面向对象思想进行描述,并封装成了对象。因为问题的产生有产生的原因、有问题的名称、有问题的描述等多个属性信息存在。当出现多属性信息最方便的方式就是将这些信息进行封装。异常就是java按照面向对象的思想将问题进行对象封装。这样就方便于操作问题以及处理问题。
出现的问题有很多种,比如角标越界,空指针等都是。就对这些问题进行分类。而且这些问题都有共性内容比如:每一个问题都有名称,同时还有问题描述的信息,问题出现的位置,所以可以不断的向上抽取。形成了异常体系。网络突然中断,文件不存在……
5.5.2 异常处理的5个关键字
try ,catch,
finally
throw, throws
异常处理格式
try{
//可能出异常的代码
} catch(异常类 对象){
//处理该异常类型的语句
}
[finally] {
//一定会执行的代码
//catch块使用System.exit(1);除外
}
备注:当try语句块出现异常,程序会自动跳到catch语句块去找匹配的异常类型,并执行异常处理语句,finally语句块是异常的统一出口。
5.5.3多异常处理
声明异常时尽可能声明具体异常类型,方便更好的处理;
方法声明几个异常就对应有几个catch块;
若多个catch块中的异常出现继承关系,父类异常catch块放在最后;
在catch语句块使用Exception类作为异常类型时:
所有子类实例都可以使用父类接收(向上转型),即所有的异常对象都可以使用Exception接收;
注:在java处理多异常时捕获小范围的异常必须放在大范围异常之前。
java7 - 同时捕获多个异常类型
Java7之前:
try {
inta =1;
intb =0;
intc = a / b;
System.out.println(c);
} catch (NumberFormatException e)
{
e.printStackTrace();
} catch(ArithmeticException e)
{
e.printStackTrace();
}
Java7:将多个异常写到了同一个catch代码块
try {
Integer a = 1;
Integer b = 0;
Integer c = a / b;
System.out.println(c);
} catch (NumberFormatException
|ArithmeticException e ) {
e.printStackTrace();
}
5.5.4异常的分类
异常分类:
编译时被检查异常; ---> Checked异常
在程序中必须使用try...catch处理;
编译时不被检测的异常; ---> Runtime异常
可以不使用try...catch处理,但一旦出现异常就将由JVM处理。
Runtime异常
RuntimeException(运行时异常)是指因设计或实现方式不当而导致的问题.
说白了,就是程序员造成的,程序员小心谨慎是完全可以避免的异常.比如,事先判断对象是否为null就可以避免NullPointerException异常,事先检查除数不为0就可以避免ArithmeticException异常;
特点:
这种异常Java编译器不会检查它,也就说程序中出现这类异常的时候,即使不处理也没有问题,但是一旦出现异常,程序将异常终止,若采用异常处理,则会被相应的程序执行处理。
Checked异常
除了RuntimeException以及子类,其他的Exception及其子类都是受检查异常,我们也可以称为非RuntimeException异常.
特点:
Java编译器会检查它,也就说程序中一旦出现这类异常,要么是没有try-catch语句捕获,或throws语句没有声明抛出它,编译就不会通过,也就说这种异常,程序要求必须处理。
5.5.5声明异常(throws)
在可能出现异常的方法上声明抛出可能出现异常的类型:
声明的时候尽可能声明具体的异常,方便更好的处理.
当前方法不知道如何处理这种异常,可将该异常交给上一级调用者来处理(非RuntimeException类型的异常)。
方法一旦使用throws声明抛出方法内可能出现的异常类型,该方法就可以不再过问该异常了;
一个方法调用另一个使用throws声明抛出的方法,自己要么try...catch, 要么也throws;
格式:
public 返回值类型 方法名(参数列表...)throws 异常类A,异常类B... {
}
5.5.6抛出异常throw
自行抛出一个异常对象,抛出异常类的对象;
若throw抛出的是Runtime异常:
程序可以显示使用try...catch来捕获并处理,也可以不管,直接交给方法调用者处理;
若throw抛出Checked异常:
要么放在try里自己处理,要么放在一个throws声明的方法里面,交给调用者处理。
Eg:
publicstatic void main(String[] args) {
try{
fn1(1);
}catch (Exception e) { e.printStackTrace(); }
fn2(2);
}
publicstatic void fn1(int a) throws Exception{
if(a>0) { throw new Exception("fn1 -- a值不合法"); }
}
publicstatic void fn2(int a) {
if(a>0) { throw new RuntimeException("a值不合法"); }
}
throws & throw
throws用于在方法上声明该方法不需要处理的异常类型。
throw用于抛出具体异常类的对象。
throws与throw的区别:
thorws用在方法上,后面跟异常类名,可以是多个异常类。
throw用在方法内,后面跟异常对象,只能是一个。
5.5.7 finally
异常的统一出口:
不管try块程序是否异常,也不管哪个catch执行,finally块总会执行。
try语句块或会执行的catch语句块使用了JVM系统退出语句例外;//System.exit(1);
try块必须和 catch块或和finally同在,不能单独存在,二者必须出现一个。
不要在finally中使用return 或throw语句,否则将会导致try、catch中的return或throw失效。
finally代码块只在一种情况下不执行:System.exit(0);
Eg:
package reviewDemo;
public class Demo19 {
public static void main(String[] args) {
try{
System.out.println(17/0);
}catch(Exception e){
//e.printStackTrace();
System.out.println("程序错误,请修正!");
}finally{
System.out.println("这是finally代码块!");
}
}
}
输出:
程序错误,请修正!
这是finally代码块!
5.5.8、throw和catch同时使用
当异常出现在当前方法中,程序只对异常进行部分处理,还有一些处理需要在方法的调用者中才能处理完成,此时还应该再次抛出异常,这样就可以让方法的调用者也能捕获到异常;
例如:
public static void buy(String price) throwsException {
try{
if(price!= null)
Double.parseDouble(price);
}catch (Exception e) {
e.printStackTrace();
thrownew Exception("价格不能只能是数字组成");
}
}
public static void main(String[] args) {
try{
buy(null);
}catch (Exception e) {
System.out.println(e.getMessage());
}
}