一:消息
1.消息的概念:
对象之间的联系是通过消息传递来实现的。把发消息的对象称为发送者,把接受消息的对象称为接收者。消息就是向对象发出服务请求,是对数据成员和成员方法的引用。消息性质:
(1)同一对象可接收不同形式的多个消息,产生不同的响应。
(2)相同形式的消息可以发送给不同的对象,各对象所作出的响应可以是截然不同的。
(3)消息的发送可以不考虑具体的接收者,对象可以相应消息,也可以对消息不予理会,对消息的响应并不是必须的。
2.公有消息和私有消息
在面向对象系统中,消息分为两类:公有消息和私有消息。当有一批消息同属于一个对象时,由外界对象直接发送给这个对象的消息称为共有消息;对象发送给自己的消息称为私有消息。私有消息对外不开放。
特定于对象的消息可分为以下三种类型:
(1)可以返回对象内部状态的消息。
(2)可以改变对象内部状态的消息。
(3)可以做一些特定操作,改变系统状态的消息。
二:访问控制
当一个类被声明为 public 时,其他包中的public程序可使用 import 语句可以引用这个 public 类。
访问控制规则见下表:
数据成员与方法\类 | public | 缺省 |
---|---|---|
public | 所有类 | 包中类(含当前类) |
protected | 包中类(含当前类),所有子类 | 包中类(含当前类) |
缺省(friendly) | 包中类(含当前类) | 包中类(含当前类) |
private | 当前类本身 | 当前类本身 |
三:多态机制
多态是面向对象系统中的又一重要特性,它描述的是同名方法可以根据发送消息的对象传送参数的不同,采取不同的行为方式的特性。
1.概念
多态是指一个程序中具有相同名字而内容不同的方法共存的情况。
java中提供了两种多态机制。:重载和覆盖。
重载:
在同一类中定义了多个同名而不同内容的成员方法时,我们称这些方法是重载(override)的方法。
重载的方法主要通过形式参数列表中参数的个数、参数的数据类型和参数的顺序(java特有)等方面的不同来区分。
覆盖:
继承机制中,java允许子类对父类的方法重新定义,即在子类中可以定义与父类中已定义的方法同名而内容不同的方法。这种多态被称为覆盖(overload)。
在方法引用时指明引用的是父类的方法还是子类的方法来区分。
2.继承
java用extends指明继承关系。子类可以从父类那里继承所有非private的属性和方法。
在定义一个类而不给出 extends 关键字及父类名时,默认这个类是系统类object的子类。
(1)数据成员的继承
子类可以继承父类的所有非私有数据成员。
数据成员的隐藏:
在子类中重新定义一个与父类中已定义的数据成员名完全相同的数据成员。
即子类拥有了两个相同名字的数据成员,一个来自父类,一个是自己定义的。当子类引用这个数据成员时默认引用它自己定义的数据成员,把父类的“隐藏”起来。
当子类要引用继承自父类的同名数据成员时,可使用关键字 super 引导。
(2)成员方法的继承
子类可以继承父类的所有非私有数据成员。
成员方法的覆盖
方法的覆盖与数据成员的隐藏不同之处在于:父类同名的数据成员在子类对象中仍占有自己独立的内存空间;子类方法对父类同名方法的覆盖将清除父类方法占用的内存,使父类方法在子类对象中不复存在。
注意:
子类在重新定义父类已有的方法时,应保持与父类完全相同的方法名、返回值类型和参数列表,否则就不是方法的覆盖,而是子类定义的特有方法,与父类方法无关。
(3) this 和 super
this 使用场合:
(1)用来访问当前对象的数据成员,使用形式:this.数据成员
(2)用来访问当前对象的成员方法,使用形式:this.成员方法(参数)
(3)当有重载的构造方法时,用来引用同类的其他构造方法,使用形式:this(参数)
//构造方法的重载
class Address{
public int x=0,y=0,z=0;
//以下是同名不同参的构造方法
Address(int x){//可重载的构造方法1
this.x=x;
}
Address(int x,int y){//可重载的构造方法2
this(x);//当前构造方法调用可重载的构造方法1
this.y=y;
}
Address(int x,int y,int z){//可重载的构造方法3
this(x,y);//当前构造方法调用可重载的构造方法2
this.z=z;
}
public int add(){
return x+y+z;
}
}
public class C5_14{
public static void main(String arg[]){
Address p1=new Address(2,3,5);
Address p2=new Address(10,20);
Address p3=new Address(1);
System.out.println(p1.add());
System.out.println(p2.add());
System.out.println(p3.add());
}
}
super 使用方法:
(1)用来访问直接父类隐藏的数据成员,使用形式:super.数据成员
(2)用来调用直接父类中被覆盖的成员方法,使用形式:super.成员方法(参数)
(3)用来调用直接父类的构造方法,使用形式:super(参数)
//P119构造方法的继承
class Address{
public int x=0,y=0,z=0;
//以下是同名不同参的构造方法
Address(int x){//可重载的构造方法1
this.x=x;
}
Address(int x,int y){//可重载的构造方法2
this(x);//当前构造方法调用可重载的构造方法1
this.y=y;
}
Address(int x,int y,int z){//可重载的构造方法3
this(x,y);//当前构造方法调用可重载的构造方法2
this.z=z;
}
public int add(){
return x+y+z;
}
}
public class C5_15 extends Address{
int a=0,b=0,c=0;
C5_15(int x){
super(x);
a=x+7;
}
C5_15(int x,int y){
super(x,y);
a=x+5;
b=y+5;
}
C5_15(int x,int y,int z){
super(x,y,z);
a=x+4;
b=y+4;
c=z+4;
}
public int add(){
System.out.println("super:x+y+z="+super.add());
return a+b+c;
}
public static void main(String arg[]){
C5_15 p1=new C5_15(2,3,5);
C5_15 p2=new C5_15(10,20);
C5_15 p3=new C5_15(1);
System.out.println(p1.add());
System.out.println(p2.add());
System.out.println(p3.add());
}
}
3.向方法传递对象
传递方法的参数如果是变量,只能由实参传递给形参,而不能由形参带回,即单向值传递,在方法的引用过程中,对于形参变量值的修改并不影响实参变量值。
传递方法的参数如果是对象,则实参与形参的对象的引用指向同一个对象,成员方法中对对象的数据成员的修改,会使实参对象的数据成员值也发生同样的变化。这种参数的传递方式被称为“双向地址传递”。
class Student{
public String Name;
public int age=16;
public int score=0;
public void ShowStudent(){
System.out.println("Name:"+Name);
System.out.println("age:"+age);
System.out.println("score:"+score);
}
public void A(Student s,String Name,int age,int score){
s.Name=Name;
s.age=age;
s.score=score;
}
}
public class C5_16 extends Student{
public static void main(String arg[]){
Student st1=new Student();
Student st2=new Student();
st1.A(st1,"Zhang",23,81);
st2.A(st2,"Li",24,90);
st1.ShowStudent();
st2.ShowStudent();
}
}
4.继承与封装的关系
继承机制的引入丝毫没有影响对象的封装性。
封装性主要指的是对象的封装性,即将属于某一类的一个具体的对象封装起来,使其数据和操作称为一个整体。继承是一种静态共享代码的手段,通过派生类对象的创建,可以接受某一消息,启动其基类所定义的代码段,从而使基类和派生类共享这一段代码。封装机制所提供的是一种动态共享代码的手段,通过封装,我们可以将一段代码定义在一个类中,在另一个类所定义的操作中,可以通过创建该类的实例,并向它发送消息而启动这一段代码,达到共享的目的。
四:抽象类、接口与包
抽象类体现数据抽象的思想,是实现程序多态性的一种手段。接口是java中实现多重继承的唯一途径。
1.抽象类
抽象类是它的所有子类公共属性的集合。
抽象类与抽象方法的限制如下:
(1)凡是用 abstract 修饰符修饰的类被称为抽象类。凡是用 abstract 修饰符修饰的成员方法被称为抽象方法。
(2)抽象类中可以有零个或多个抽象方法,也可以包含非抽象的方法。
(3)抽象类中可以没有抽象方法,但是有抽象方法的类必须是抽象类。
(4)对于抽象方法来说,在抽象类中只指定其方法名及其类型,而不书写其实现代码。
(5)抽象类可以派生子类,在抽象类派生的子类中,必须实现抽象类中定义的所有抽象类方法。
(6)抽象类不能创建对象,只能由抽象类派生的子类创建对象。
(7)如果父类中已有同名的 abstract 方法,则子类中就不能再有同名的抽象方法。
(8)abstract 不能与 final 并列修饰同一个类。
(9)abstract 不能与private、static、final、或 native 并列修饰同一个方法。
2.接口
声明接口:
[修饰符] interface 接口名 [extends 父接口名列表]{
常量数据成员声明
抽象方法声明
}
说明;
(1)interface 是声明接口的关键字,可以把它看成一个特殊类。
(2)接口名要符合 java 标识符规定。
(3)修饰符有 public 和默认。
public 修饰的接口:公共接口,可被所有的类和接口使用;
默认:只能被同一个包中的其他类和接口使用。
(4)接口也具有继承性,用 extends 声明,与类的继承不同的是,一个接口可以有一个以上的父接口,它们之间用逗号分隔。
(5)常量数据成员声明:常量数据成员前有没有修饰符都可以。修饰符是 public static 和 final static ;注意接口中的数据成员都是用 final 修饰的常量,写法如下:
修饰符 数据成员类型 数据成员名=常量值
或
数据成员名=常量值
(6)抽象方法声明。接口中的方法都是用abstract 修饰的抽象方法,默认为 public abstract 方法。所以接口的本质是抽象类。
定义接口注意事项:
接口没有自身的构造方法,所有成员方法都是抽象方法。
类实现接口的注意事项:
接口定义仅仅是实现某一特定功能的对外接口和规范,而不能真正实现这个功能,真正的实现是在“继承”这个接口的各个类完成的。所以在 java 中,把对接口功能的继承称为“实现”。
(1)在类中,用 implements 关键字就可以调用接口。一个类若要调用多个接口,可在 implements 后用逗号隔开多个接口的名字。
(2)如果实现某接口的类不是 abstract 的抽象类,则在类的定义部分必须实现指定接口的所有抽象方法,并且方法头部分应该与接口中的定义完全一致。
(3)如果实现某接口的类是 abstract 的抽象类,则它可以不实现指定接口的所有抽象方法。但是对于这个抽象类的任何一个非抽象的子类而言,它们父类所实现的接口中的抽象方法都必须有实现的方法体,这些方法可以来自抽象的父类,也可以来自子类自身,但是不允许存在未被实现的接口方法,这主要体现了非抽象类中不能存在抽象方法的原则。
(4)接口的抽象方法的访问限制符都已被指定为 public ,所以类在实现方法时,必须显示的使用 public 修饰符,否则缩小了接口中定义的方法的访问控制范围。