您的位置:首页 > 其它

6. 面对对象(高级) Part 2 --- 学习笔记

2014-06-17 17:14 232 查看
6.4 final 关键字


final在java中表示的意思是最终,也可以称为完结器。

可以使用final关键字声明类、属性、方法,但在声明时需要注意以下几点:

1. 使用final声明的类不能有子类,也就是说不能被继承。

2. 使用final声明的方法不能被子类所覆写。(父类中有方法使用final声明,那么子类不能覆写该方法)

3. 使用final声明的变量即成为常量,常量不可以被修改。

*******在使用final声明变量时,要求全部的字母大写,如INFO,这点在开发中是非常重要的********

如果一个程序中的变量使用 public static final声明,则此变量将称为全局常量!!

6.5 抽象类的基本概念

1. 抽象类的作用类似“模板”,其目的是要设计者依据它的格式来修改并创建新的类。但是不能直接由抽象类创建对象,只能通过抽象类派生出新的类,再由它的派生类(抽象类的子类)来创建对象。在抽象类的使用中同样存在单继承的限制,即: 一个子类智能继承一个抽象类。

2. 抽象类的定义及使用规则如下:

I. 包含一个抽象方法的类必须是抽象类

II. 抽象类和抽象方法都要使用abstract关键字声明

III. 抽象方法只需声明,而不需要实现

IV. 抽象类必须被子类继承,子类(如果不是抽象类)必须覆写抽象类中的全部抽象方法

abstract class 抽象类名称{

属性;

访问权限 返回值类型 方法名称(参数列表){

[return 返回值];

}

访问权限 abstract 返回值类型 方法名称(参数列表){

//在抽象方法中是没有方法体的

}

}

3. 由上面抽象类的定义格式可以发现,抽象类的定义比普通类多了一些抽象方法,其他地方与普通类的组成基本上都是一样的

********************子类必须覆写抽象类中的全部抽象方法***************************

4. 思考!!!

a. 抽象类可以使用final关键字声明吗?

Answer: 不行!!!!用final关键字声明的类不能被继承~ 而抽象类又必须被子类覆写~矛盾体。

PS:抽象方法不要使用private声明。 在使用abstract关键字声明抽象方法时不能使用private修饰,因为抽象方法必须被子类覆写,而private声明的方法又无法被子类所覆写。

b. 抽象类中可以定义构造方法吗?

Answer: 可以!!!抽象类中是允许构造方法的存在,因为抽象类依然使用的是类的继承关系,而且抽象类中也存在各个属性,所以子类在实例化之前必须先要对父类进行实例化。

PS: 个人理解,抽象类中不是所有的方法都是抽象的,一些其他操作需要做抽象处理的才会将它抽象化。

5. 抽象类与普通类

通过抽象类和普通类的定义格式可以发现,抽象类实际上就是比普通类多订一个抽象方法,除了不能直接进行对象的实例化操作外没有任何的不同。

6.6 接口的基本概念

1. 接口可以被理解为一种特殊的类,是由全局常量和公共的抽象方法所组成。

2. 接口的定义格式: 在接口中的抽象方法必须定义为public访问权限,这是绝对不可改变的!!!!!!

interface 接口名称{

全局常量;

抽象方法;

}

3. 在接口中如果没有写权限修饰符,默认的是public访问权限。在接口中不管写与不写权限修饰符,接口中的方法永远是public。

 例子:

interface A{

public static final String AUTHOR = "forfan06"; //定义全局常量

public abstract void print(); //定义抽象方法

public abstract String getInfo(); //定义抽象方法

}

由于在接口的基本概念中已经明确地声明了接口是由全局常量和抽象方法组成的,所以上面的接口定义可以简化成如下的形式:

interface A{

String AUTHOR = "forfan06";

void print();

String getInfo(); //与上面的三条语句完全一一对应。等价关系

}

4. 与抽象类一样,接口若要使用也必须通过子类,子类通过implements关键字实现接口!

实现接口格式:

class 子类 implements 接口A, 接口B, ...{

}

从接口实现的格式可以发现,一个子类可以同时实现多个接口(摆脱了单继承的局限),但是子类必须同时覆写所有接口中的全部抽象方法!

5. 子类既要实现接口又要继承抽象类, 定义格式如下:

class 子类 extends 抽象类 implements 接口A, 接口B, ... {

}

同样,子类必须覆写接口和抽象类中的所有抽象方法。

6. 抽象类可以实现多个接口

当抽象类实现了接口时,抽象类的子类就必须覆写抽象类和接口中的所有抽象方法。

7. 接口是不允许继承抽象类的,但是允许一个接口继承多个接口,格式如下:

interface 子接口 extends 接口A, 接口B, ...{

}

6.7 对象的多态性

1. 多态性在面向对象中是一个很重要的概念,在java中主要有以下两种主要体现:

I: 方法的重载与覆写

II: 对象的多态性


2. 方法的重载与覆写,Part 1中有讲道

3. 对象的多态性主要分为以下两种类型:

I: 向上转型: 子类对象 --> 父类对象

II: 向下转型: 父类对象 --> 子类对象

4. 对于向上转型,程序会自动完成; 而对于向下转型时,必须明确地指明要转型的子类类型。 格式如下:

对象向上转型: 父类 父类对象 = 子类实例;

对象向下转型: 子类 子类对象 = (子类)父类实例;

例如:

class A{

public void fun1(){

System.out.println("AA --> public void fun1(){}");

}

public void fun2(){

this.fun1();

}

}

class B extends A{

public void fun1(){ //覆写了父类的fun1()方法

System.out.println("BB --> public void fun1(){}");

}

public void fun3(){

System.out.println("BB --> public void fun3(){}");

}

}

测试类:

public class PolDemo01{

public static void main(String args[]){

B b = new B();

A a = b; //发生了向上转型关系, 子类 --> 父类

a.fun1(); //fun1()方法被覆写过!!

}

}

程序运行结果:

BB --> public void fun1(){}

上面程序运行结果可以发现,此时虽然是使用父类对象调用了fun1方法,但是实际上调用的方法是被子类覆写过的方法,也就是说,如果对象发生了向上转型后,所调用的方法一定是被子类覆写过的方法。

但是需要注意的是,此时的父类对象a是无法调用B类中的fun3()方法的。因为此方法只在子类中定义,父类中没有定义此方法。如果想要调用子类自己的方法,则肯定要使用子类实例。

向下转型

class A{

public void fun1(){

System.out.println("AA --> public void fun1(){}");

}

public void fun2(){

this.fun1();

}

}

class B extends A{

public void fun1(){ //覆写了父类的fun1()方法

System.out.println("BB --> public void fun1(){}");

}

public void fun3(){

System.out.println("BB --> public void fun3(){}");

}

}

测试类:

public class PolDemo02{

public static void main(String args[]){

A a = new B(); //发生了向上转型关系 与 B b = new B(); A a = b;等价

B b = (B)a; //此时发生了向下转型关系

b.fun1(); //调用被覆写过的方法

b.fun2(); //调用父类的方法

b.fun3(); //调用子类特有的方法

}

}

程序输出结果为:

BB --> public void fun1(){}

BB --> public void fun1(){}

BB --> public void fun3(){}

从以上的程序中可以发现,如果想要调用子类自己特有的方法,则一定只能用子类声明对象,另外,在子类中调用了父类中的fun2()方法,fun2()方法要调用fun1()方法,但此时fun1()方法已经被子类所覆写,所以此时调用的方法是被子类覆写过的方法!!

******************对象向下转型的前提: 必须首先发生对象向上转型关系,否则会出现对象转换异常************************

Animal animal = new Cat(); 可以理解成 Cat is a Animal. (Cat是Animal的子类),但是反过来就不能说Animal is a Cat!!因为Animal不仅仅只是Cat.

5. 多态性的用处:

设计一个方法,让此方法可以接受A类的任意子类对象,并调用此方法。

实现一,不适用对象多态性功能

class A{

public void fun1(){

System.out.println("AA --> public void fun1(){}");

}

public void fun2(){

this.fun1();

}

}

class B extends A{

public void fun1(){ //覆写了父类的fun1()方法

System.out.println("BB --> public void fun1(){}");

}

public void fun3(){

System.out.println("BB --> public void fun3(){}");

}

}

class C extends A{

public void fun1(){

System.out.println("CC --> public void fun1(){}");

}

public void fun5(){

System.out.println("CC --> public void fun5(){}");

}

}

测试类

public class PolDemo03{

public static void main(String args[]){

fun(new B()); //传递B类实例

fun(new C()); //传递C类实例

}

public static void fun(B b){ //接受子类B的实例

b.fun1();

}

public static void fun(C c){ //接受子类C的实例

c.fun1();

}

}

运行结果:

BB --> public void fun1(){}

CC --> public void fun1(){}

如果按照以上的方式完成程序,则当产生一个A类子类时,fun()方法就要重载一次,这样如果功能扩充,则必须要修改类本身!!

实现二: 使用对象多态性实现功能

class A{

public void fun1(){

System.out.println("AA --> public void fun1(){}");

}

public void fun2(){

this.fun1();

}

}

class B extends A{

public void fun1(){ //覆写了父类的fun1()方法

System.out.println("BB --> public void fun1(){}");

}

public void fun3(){

System.out.println("BB --> public void fun3(){}");

}

}

class C extends A{

public void fun1(){

System.out.println("CC --> public void fun1(){}");

}

public void fun5(){

System.out.println("CC --> public void fun5(){}");

}

}

测试类

public class PolDemo03{

public static void main(String args[]){

fun(new B()); //传递B类实例,此时产生了向上转型

fun(new C()); //传递C类实例,此时产生了向上转型。 而向上转型是程序自动完成的!!

}

public static void fun(A a){ //接受父类对象

a.fun1();

}

}

运行结果:

BB --> public void fun1(){}

CC --> public void fun1(){}

此时在fun()方法中使用了对象的多态性,所以可以接受任何的子类对象,他们都自动发生向上转型(由程序自动完成),这样无论子类如何增加,fun()方法都不用作任何修改。因为一旦发生对象向上转型关系后,调用的方法一定是被子类覆写过的方法。

***************向上转型,是程序自动完成的;损失了子类新扩展的属性和方法,仅剩下父类中声明过的属性和方法;所调用的方法一定是被子类覆盖过的方法********

*******因为子类是一种特殊的父类,所以JAVA允许将一个子类的实例化对象直接赋给它的父类的引用变量 ***********

引用类型直接的转换只能在具有继承关系的类型之间进行转换!!!


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: