JAVA初等基础__(面向对象三个特征, 封装,继承,多态)


练习:设计一个CBox类,具有length、width和height三个属性,对每个属性都提供相应的get和set方法,提供构造函数,完成CBox信息的初始化,增加volume()方法,用来计算CBox对象的体积,定义surfaceArea()方法用来计算CBox的表面积。
面向对象的三个特征:
(1)封装:封装就是把对象的属性(状态)和方法(行为)结合在一起,并尽可能隐蔽对象的内部细节,成为一个不可分割的独立单位(即对象),对外形成一个边界,只保留有限的对外接口使之与外部发生联系。
封装的原则:使对象以外的部分不能随意存取对象的内部数据,从而有效的避免了外部错误对它的“交叉感染”。数据隐藏特性提升了系统安全性,使软件错误能够局部化,减少查错和排错的难度。如:微波炉,将线路板(属性)封装在微波炉内部,使用者无法接触到,而通过面板按钮(方法)简单的操控线路板工作。     
(2)继承:继承是软件重用的一种形式,它通过重用现有类的属性和方法,并增加新功能或修改现有功能来构建新的类。如:“人”这个类抽象了这个群体的一般特性,“学生”和“老师”都具备“人”所定义的一般性,但其各自又有各自的特殊性,在保持了一般性和特殊性的情况下,作为一个新类而存在。
(3)多态:多态是指在父类中定义的属性或方法被子类继承之后,可以具有不同的表现行为。这使得同一个属性或方法在父类及其各个子类中具有不同的语义。如:动物会“叫”,“猫”和“鸟”都是动物的子类,但其“叫”声是不同的
新授内容:
1、继承:
表现的是一种共性和特性的关系,一个类可以继承另一个类,并在此基础上添加自己特有功能,这称为继承。在java中使用extends关键字表现继承关系。
格式:
[访问符][修饰符] class <子类名> extends <父类名>{
  [属性]  //成员变量
  [方法]  //成员
}
public tiger extends animal{
}
2、继承的特性
(1)Java是单继承的,即一个子类只能继承一个父类,被继承的类叫做父类(超类),继承的类叫做子类(派生类)。
(2)在继承过程中,子类拥有父类定义的所有属性和方法,但父类可以通过封装思想隐藏某些数据,然后提供子类可以访问的属性和方法。
(3)当生成子类对象时,Java默认首先调用父类的不带参数的构造方法,然后执行该构造方法,生成父类的对象,再去调用子类的构造方法,生成子类的对象。要想生成子类的对象,首先生成父类的对象,没有父类对象就没有子类对象。
(4)如果一个类没有指明任何父类,则缺省的自动继承java.lang.Object类。Object类是所有类的*父类,在java中,所有类都是直接或间接的继承了Object类。
(5)super关键字:super关键字代表父类对象,主要有两个用途:
1)调用父类的构造方法
与super()所对应的就super表示对父类对象的引用。如果子类使用super()显示调用父类的某个构造方法,那么在执行的时候前面不会寻找构造方法而不再去寻找父类的不带参数的构造方法。super必须作为构造方法的第一条语句能有其他的,可执行语句。
2)访问父类的属性和方法。
当子类的属性或方法与父类的属性或方法重名时,可用super.属性名或super.方法名(参数列表)的方式访问父类的属性或方法。
3、多态
当子类继承父类时,可以在子类中直接使用父类的属性和方法。如果父类的方法无法满足子类的需求,则可以在子类中对父类的方法进行改造,这称为方法的重写,重写是java多态性的一种体现。
(1)、方法重写:又叫做覆写,子类与父类的方法返回值类型一样,方法名称一样,参数一样,这样我们说子类与父类的方法构成了重写关系。
public class Test2 {
public static void main(String[] args) {
Dog dog=new Dog();
dog.run();
}
}
class Animal{
public void run(){
System.out.println("Animal is running!");
}
}
class Dog extends Animal{
public void run(){
System.out.println("Dog is running!");
}
}
 
若给子类的run方法添加一个参数,则不叫重写。分别调用带参数的run和不带参数的run来执行一下。
(2)、方法重写与方法重载之间的关系:重载发生在同一个类内部的两个或多个方法。重写发生在父类与子类之间。
(3)、方法重写需要遵循以下几点:
重写的方法的签名必须要和被重写的方法的签名完全匹配;
重写的方法的返回值必须和被重写的方法的返回一致或者是其子类;
重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
私有方法不能被重写
子类重写父类方法的过程中,可访问性只能一样或变的更公开。
(4)、多态
我们说子类就是父类(玫瑰是花,男人是人),因此多态的意思是:父类型的引用可以指向子类的对象。
1)多态:父类型的引用可以指向子类型的对象。
public class Test3 {
public static void main(String[] args) {
Flower flower=new Rose();//多态
flower.sing();
}
}
class Flower{
public void sing(){
System.out.println("Flower is sing.");
}
}
class Rose extends Flower{
}
花是花,玫瑰是玫瑰,玫瑰是花,但花是玫瑰是错误的,花是玫瑰,那么康乃馨呢是花吗?对不对呀。
Rose rose=new Flower();
rose.sing();
2)、Flower flower=new Rose();当使用多态方式调用方法时,首先检查父类中是否有Sing方法,如果有,则去调用子类的sing方法(不管是继承的还是重写的)。有这个sing方法,则无法如果没有则编译错误。因为flower是一个Flower类型的变量,如果Flower类型没调用。
 Java实现多态有三个必要条件:继承、重写、向上转型。
         继承:在多态中必须存在有继承关系的子类和父类。
         重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
         向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
      只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
      对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
所以基于继承实现的多态可以总结如下:对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。
public class A {
    public String show(D obj) {
        return ("A and D");
    }
 
    public String show(A obj) {
        return ("A and A");
    }
 
}
 
public class B extends A{
    public String show(B obj){
        return ("B and B");
    }
    
    public String show(A obj){
        return ("B and A");
    }
}
 
public class C extends B{
 
}
 
public class D extends B{
 
}
 
public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));      
    }
}
 
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
 
在这里看结果1、2、3还好理解,从4开始就开始糊涂了,对于4来说为什么输出不是“B and B”呢?
      首先我们先看一句话:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
      分析:
      从上面的程序中我们可以看出A、B、C、D存在如下关系。


      首先我们分析5,a2.show(c),a2是A类型的引用变量,所以this就代表了A,a2.show(c),它在A类中找发现没有找到,于是到A的超类中找(super),由于A没有超类(Object除外),所以跳到第三级,也就是this.show((super)O),C的超类有B、A,所以(super)O为B、A,this同样是A,这里在A中找到了show(A obj),同时由于a2是B类的一个引用且B类重写了show(A obj),因此最终会调用子类B类的show(A obj)方法,结果也就是B and A。
      按照同样的方法我也可以确认其他的答案。
      方法已经找到了但是我们这里还是存在一点疑问,我们还是来看这句话:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。这我们用一个例子来说明这句话所代表的含义:a2.show(b);
      这里a2是引用变量,为A类型,它引用的是B对象,因此按照上面那句话的意思是说有B来决定调用谁的方法,所以a2.show(b)应该要调用B中的show(B obj),产生的结果应该是“B and B”,但是为什么会与前面的运行结果产生差异呢?这里我们忽略了后面那句话“但是这儿被调用的方法必须是在超类中定义过的”,那么show(B obj)在A类中存在吗?根本就不存在!所以这句话在这里不适用?那么难道是这句话错误了?非也!其实这句话还隐含这这句话:它仍然要按照继承链中调用方法的优先级来确认。所以它才会在A类中找到show(A obj),同时由于B重写了该方法所以才会调用B类中的方法,否则就会调用A类中的方法。
      所以多态机制遵循的原则概括为:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。JAVA初等基础__(面向对象三个特征, 封装,继承,多态)