Java的四种特性
封装
封装的概念
在面向对象程序设计方法中,封装是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程序更容易理解和维护,也加强了程序代码的安全性。
封装的优点
- 良好的封装能减少耦合;
- 类内部的结构可以自由修改;
- 可以i对成员变量进行更精确的控制;
- 隐藏信息,实现细节。
继承
继承的概念
继承是Java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承符合的关系是:is-a,父类更通用,子类更具体。子类会具有父类的一般特性也会具有自身的特性。
类的继承格式
在Java中通过extends关键字可以申明一个类是从另一个类继承而来的,一般形式为:
class 父类 {
}
class 子类 extends 父类 {
}
为什么要继承?
在编程中可以将多个类的代码重复部分提取出来组成一个父类,其它类作为子类继承父类后,就具有了父类当中的属性和方法,子类就不会存在重复的代码,维护性也提高,代码也更简洁,提高代码的复用性。
继承类型
注意:Java不支持多继承,但支持多重继承。
继承的特性
- 子类拥有父类非私有的属性、方法;
- 子类可拥有自己的属性和方法,即子类可以对父类进行扩展;
- 子类可以用自己的方式实现父类的方法;
- Java的继承是单继承,但可以实现多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如B类继承A类,C类继承B类,所以按照关系就是B类是C类的父类,A类是B类的父类,这是Java继承区别于C++继承的一个特性;
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字
继承可以使用extends和implements这两个关键字来实现继承,而且所有的类都是继承与java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在java.lang包中,所以不需要import)祖先类。
extends关键字
在Java中,类的继承是单一继承,一个子类只能继承一个父类,所以extends只能继承一个类。
implements关键字
使用implements关键字可以变相的使Java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口和接口之间采用逗号分隔)。
super和this关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
输出结果:
animal : eat
dog : eat
animal : eat
final关键字
final关键字声明类可以把类定义为不能继承的,即最终类;或者修饰方法,该方法不能被子类重写。
注:实例变量也可以被定义为final,被定义为final的变量不能被修改。被声明为final类的方法自动地声明为final,但实例变量并不是final。
构造器
子类是不继承父类的构造器(构造方法或构造函数)的,它只是调用(显式或隐式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过super关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用super关键字调用父类构造器,系统会自动调用父类的无参构造器。如:
class SuperClass {
private int n;
SuperClass(){
System.out.println("SuperClass()");
}
SuperClass(int n) {
System.out.println("SuperClass(int n)");
this.n = n;
}
}
// SubClass 类继承
class SubClass extends SuperClass{
private int n;
SubClass(){ // 自动调用父类的无参数构造器
System.out.println("SubClass");
}
public SubClass(int n){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass(int n):"+n);
this.n = n;
}
}
// SubClass2 类继承
class SubClass2 extends SuperClass{
private int n;
SubClass2(){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass2");
}
public SubClass2(int n){ // 自动调用父类的无参数构造器
System.out.println("SubClass2(int n):"+n);
this.n = n;
}
}
public class TestSuperSub{
public static void main (String args[]){
System.out.println("------SubClass 类继承------");
SubClass sc1 = new SubClass();
SubClass sc2 = new SubClass(100);
System.out.println("------SubClass2 类继承------");
SubClass2 sc3 = new SubClass2();
SubClass2 sc4 = new SubClass2(200);
}
}
输出:
------SubClass 类继承------
SuperClass()
SubClass
SuperClass(int n)
SubClass(int n):100
------SubClass2 类继承------
SuperClass(int n)
SubClass2
SuperClass()
SubClass2(int n):200
多态:
多态的基本概念
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作。
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
11>如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
22>如果当前在 Word 下弹出的就是 Word 帮助;
33>在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:parent p = new Child();
class Shape {
void draw() {}
}
class Circle extends Shape {
void draw() {
System.out.println("Circle.draw()");
}
}
class Square extends Shape {
void draw() {
System.out.println("Square.draw()");
}
}
class Triangle extends Shape {
void draw() {
System.out.println("Triangle.draw()");
}
}
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有则编译错误;有则再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
实例演示:
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
执行结果:
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠
虚函数
虚函数的存在是为了多态。
Java中其实没有虚函数的概念,它的普通函数就相当于C++的虚函数,动态绑定是Java的默认行为。如果Java中不希望某个函数具有虚函数特性,可以加上final关键字变成非虚函数。
重写
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。
要想调用父类中被重写的方法,则必须使用关键字 super。
多态的实现方式
方式一:重写
方式二:接口
方式三:抽象类和抽象方法
抽象:
在面向对象的概念中,所有的对象都是通过类来描绘的,但反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其他功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承才能使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但由于父类本身是抽象的,所以不能使用这些方法。
在Java中抽象类表示是一种继承关系,,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
抽象类
在Java语言中使用abstract class来定义抽象类。
继承抽象类
尽管我们不能实例化一个抽象类的对象,但如果我们实例化一个它的子类对象,该对象将从抽象类继承抽象类的成员方法,且可以通过该方法设置或获取成员变量。
抽象方法
如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由他的子类确定,那么你可以在父类中声明该方法为抽象方法。
Abstract关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
声明抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类;
- 任何子类必须重写父类的抽象方法,或声明自身是抽象类。
继承抽象方法的子类必须重写该方法。否则,该类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。
抽象类总结
- 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类才可以创建对象;
- 抽象类中不一定包含抽象方法,但包含抽象方法的类必定是抽象类;
- 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能;
- 构造方法,类方法(用static修饰的方法)不能声明为抽象方法;
- 抽象方法的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。