一、封装性
封装性是面向对象编程的核心思想。
封装性是通过访问控制修饰符来限定应用程序内文件的访问级别的,Java语言中的访问控制级别有4种:
public: 意思为共有的、公共的。这个访问控制修饰符的访问级别最高。使用这个访问控制修饰符进行修饰的成员,被访问时不受任何限制。
protected:意思为受保护的。使用这个访问控制修饰符进行修饰的成员只能由派生类或统一程序包中的类进行访问。对其他程序包的派生类而言,效果相当于共有的(public)。对于其他程序的非派生类来说,其效果相当于私有的(private)。
default:意思为默认的。但是在作为访问修饰符时,default指的是不加任何访问控制修饰符,并不是要使用关键字default进行修饰。没有使用任一访问控制修饰符进行修饰的成员只能由同一程序包中的类进行访问,即对所在程序包中的其他类而言,其效果相当于共有的(public);对应用程序的其他程序包中的类来说,其效果相当于私有的(private)。
private:意思为私有的。这个访问控制修饰符的访问级别最低。使用关键字private所进行修饰的成员是不允许除了自身所在的类之外的其他类对其进行访问的。
大家需要注意:
1、不能使用protected(受保护的)和private(私有的)这两个访问控制修饰符去修饰类
2、default(默认的)访问控制修饰符修饰的类,即不加任何修饰符修饰的类,如果要在另一个类中使用该类,要保证这两个类在同一个程序包中
3、在应用程序设计上要遵循“尽可能保持数据的私有性”这个原则
4、面对对象编程的初学者往往采取这样的设计方式,类中的数据成员的访问级别为private,而方法成员的访问级别为public
下面看两个封装的示例:
(1)类中属性的封装
public class Car {
private String brand; //品牌
private double length; //长度
private double width; //宽度
private int seats=5; //座位数
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public int getSeats() {
return seats;
}
}
由上例可以看出,相对于brand(品牌)、length(长度)、width(宽度)这三个变量而言,seats(座位数)这个变量缺少了setSeats()这个方法,这就表示seats这个变量只能在Car类中进行修改。
(2)类中方法的封装
public class Output{
public void output(String str){
System.out.println(str);
}
}
这样就实现了对方法output()的封装,在方法的调用中,先将所需调用方法所在的类进行实例化,再通过类的实例进行方法的调用。如下例所示。
public class Test {
public static void main(String[] args) {
String str="这是封装的示例";
Output out=new Output();
out.output(str);
}
}
运行结果如图所示:
实现封装的步骤:
(1)修改属性的可见性
(2)创建公有的getter/setter方法
(3)在getter/setter方法中加入属性控制语句
二、继承性
继承反映的是两个类之间的一种关系。在面向对象的程序设计中,根据已有类派生出新类的这种现象,我们称之为类的继承机制。
被继承的类我们通常称之为父类或基类,而继承父类所有属性和方法的类为子类或派生类。
一个类可以同时派生出多个子类,而这些子类都自动的、隐含地拥有其父类中已经定义的属性和行为。
继承机制是允许并鼓励类的重用的:
派生类也可以被继承,成为父类,即派生类既具有从父类中继承下来的属性和行为,又具有自身新定义的属性和行为,当派生类又被它的子类所继承时,那么它所继承的及自身所定义的属性和行为也被下一级子类所继承下去。
Java语言中只支持单继承,即一个子类只继承自一个父类。
Java语言中可以通过接口的方式来弥补由于不支持多继承而带来的子类不能使用多个父类的属性和行为所产生的不足。
不能被子类继承的父类成员:
1、private成员 ;
2、子类与父类不在同包,使用默认访问权限的成员
3、构造方法
下面看一个继承的示例:
先创建一个A类,命名为A
public class A {
String a="我是A类";
public void showA(){
System.out.println(a);
}
}
再创建一个B类,命名为B。B继承A
public class B extends A{
String b="我是B类";
public void showB(){
System.out.println(b);
}
public static void main(String[] args){
B b=new B();
b.showA();
b.showB();
}
}
此外,可使用super关键字来访问父类的成员,但应注意:
super只能出现在子类的方法和构造方法中
super调用构造方法时,只能是第一句
super不能访问父类的private成员
三、多态性
多态指的就是在应用程序中出现的“重名”现象。
实现多态的两个要素:使用父类的类型、子类重写父类方法。
实现多态的两种形式:
1、使用父类作为方法形参实现多态
2、使用父类作为方法返回值实现多态
在Java语言中,多态性主要表现在以下几个方面:
(1)方法重载
(2)方法重写
(3)抽象类
(4)接口
(1)方法重载
public class TestPolymorphism1 {
String s="这是方法重载的示例!";
String ss="这是类TestPolymorphism1";
public void show(){
System.out.println(ss);
}
public void show(String str){
System.out.println(str);
}
public static void main(String args[]){
TestPolymorphism1 test=new TestPolymorphism1();
test.show();
test.show(test.s);
}
}
(2)方法重写
public class TestPolymorphism2 extends A{
String p="这是方法重写的示例!";
String ss="这是类TestPolymorphism1";
public void showA(){
super.showA();
System.out.println(p);
}
public void show(String str){
System.out.println(str);
}
public static void main(String args[]){
TestPolymorphism2 test=new TestPolymorphism2();
test.showA();
}
}
方法重载与方法重写的联系与区别:
(3)抽象类
抽象类和抽象方法的比较:
抽象类不能被实例化
抽象类可以有0~多个抽象方法
非抽象类在继承时必须重写父类的所有抽象方法
抽象方法没有方法体
抽象方法必须在抽象类里
抽象方法必须在子类中被实现,除非子类是抽象类
public abstract class Animal{
public abstract void getSound ();
}
(4)接口
接口的引入:
我们来看一个类
class A {
private int a;
public int getA() {
return a;
}
}
这个类的属性是私有的,外界不能访问,而外界可以通过公有方法来访问这个类。我们说一个类的公有方法就是这个类的对外接口。
一个类的属性都是私有的,方法大多是公有的。外界只能过个这些公有方法来访问类。这也是Java封装性的体现。如果一个类没有公有属性, 也没有公有方法,这个类就是无法使用的类了。所以我们需要为一个类提供对外接口。
一个Java接口是一些方法特征的集合,但没有方法的实现
public interface PCI {
public void start(); //定义了一个start()抽象方法
public void stop(); //定义了一个stop()抽象方法
}
Java接口中定义的方法在不同的地方被实现,可以具有完全不同的行为
//在SoundCard类中实现
class SoundCard implements PCI {
public void start() {
System.out.println("Du du...");
}
public void stop() {
System.out.println("Sound stop!");
}
}
//在NetworkCard类中实现
class NetworkCard implements PCI {
public void start() {
System.out.println("Send...");
}
public void stop() {
System.out.println("Network stop!");
}
}
注意:
(1)在Java中接口是一种专门的类型。用interface关键字定义接口。
(2)接口中只能定义抽象方法,故不能包含构造方法。不能有方法体,所以创建实例。
(3)接口的访问控制权限一定是public修饰的
(3)接口中可以定义变量,但实际上是static final修饰的常量。不能声明实例成员变量。
(4)接口中不能定义静态方法。 实际就是一种供外部访问的公有方法。
一个类要实现接口时,请注意以下问题:
在抽象类中实现接口时,可以不实现接口中的方法,但是在非抽象类中,必须实现接口中的所有方法。
(1)在类的声明部分,用implements关键字声明该类将要实现哪些接口。
(2)如果实现某接口的类是非abstract抽象类,则在类的定义部分必须实现所有指定接口中的所有抽象方法,即为所有抽象方法定义方法体,而且方法头部分应该与接口中的定义完全一致,即有完全相同的返回值和参数列表(注意,是方法实现,而不是方法重载)。
(3)如果实现某接口的的类是abstract的抽象类,则它可以不实现该接口所有的方法。但是对于这个抽象类任何一个非抽象的子类而言,它们父类所实现的接口中的所有抽象方法都必须有实在的方法体。这些方法体可以来自抽象的父类,也可以来自子类自身,但是不允许存在未被实现的接口方法。这主要体现了非抽象类中不能存在抽象方法的原则。
(4)接口的抽象方法的访问限制符都已制定为public,所以类在实现方法时,必须显式地使用public修饰符,否则将被系统警告为缩小了接口中定义的方法的访问控制范围。
一个类只能有一个父类,但是类可以同时实现若干个接口。这种情况下如果把接口理解成特殊的类,那么这个类利用接口实际上就获得了多个父类,即实现了多重继承。
接口是一组抽象方法,常量和内嵌类型的集合。没有具体实现,不能创建实例。
只是一种规范/声明/标准,没方法,只有被类实现后才有意义。同时,实现接口的非抽象类必须实现所有指定接口中的所有抽象方法。