Java基础课程-面向对象

来源:互联网 发布:极致软件官网 编辑:程序博客网 时间:2024/05/21 02:50

1.上章回顾与预习检查

1.1 上章回顾

  1. 什么是类、对象及之间的关系?
  2. 谈谈你对构造函数的理解 ?
  3. 静态初始化块与初始化块的区别?
  4. 成员方法与静态方法的区别?
 

1.2 预习检查

  1. 什么是抽象类?
  2. 什么是方法的重写?

2. 本章任务

  1. 写出一个使用super关键字调用父类的方法的完成案例
  2. 写出一个成员变量的隐藏的案例
  3. 完成一个多态性的案例
  4. 写代码测试当父类是抽象类,实例化子类时父类及子类中静态方法及构造方法的执行顺序是怎样的
  5. 写出一个静态块、语句块、构造函数在继承中执行顺序是怎样的案例

3. 本章内容

  1. package
  2. import
  3. 类的继承
  4. 抽象类
  5. 静态块、初始化块、构造函数在继承关系中的使用

3.1 package

3.1.1 package概述

为便于管理大型软件系统中数目众多的类,解决类的命名冲突问题,Java引入包(package)机制,提供类的多重类命名空间。

下面借由一张图来解释说明
这里写图片描述

package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。它的格式为:

package pkg1[.pkg2[.pkg3…]];

3.1.2 代码示例1

    package student.biggirl;    public class Beauty {      public void display(){         System.out.println("I’ve big eyes ");       }    }

备注:
Java编译器把包对应于文件系统的目录管理,package语句中,用”.”来指明包(目录)的层次;

3.2 import

3.2.1 import概述

为使用定义在不同包中的Java类,需用import语句来引入所需要的类。

语法格式:

import package1[.package2…]. (classname |*);

3.2.2 代码示例1

  1. 定义Beauty类

     package student.biggirl.Beauty;  /**  * @author chj  */  public class Beauty {  /**   * show方法  */  public void show(){     System.out.println("show!!");  }}
  2. 在不同的包中测试Beauty中的show方法:

    package student.biggirl.Beauty.test;import student.biggirl.Beauty.Beauty;public class BeautyTest {/** * 入口方法 * @param args */public static void main(String[] args) {    //创建对象    Beauty b = new Beauty();    //调用方法    b.show(); }}

备注说明:

  • Java中默认导入java.lang.*所有类.
  • 对于Java中其它包中的类可以采用import导入。例如导入:import java.util.Arrays;

3.2.3 扩展classapth

  • 对于 import java.util.Arrays; 将按照路径: CLASSPATH \java\util\Arrays 来查找所需的外部类。
  • 环境变量CLASSPATH是用来指示Java程序所引用的外部类所在的一系列相对路径.

3.3 类的继承

3.3.1 继承的定义

继承一般值得是指晚辈从父辈那里继承财产,也可以说是子女拥有父母所给予他们的东西。在面向对象程序设计中,继承的含义与此类似,所不同的是,这里继承的实体是类而非人。也就是说继承是子类拥有父类非私有的成员。
继承是面向对象三大特征之一,也是实现软件复用的重要手段

继承需要满足 is-a的关系
这里写图片描述

现实生活中的例子:
这里写图片描述
备注:引入网络图片.

3.3.2 继承的分类

继承分为单继承和多重继承。单继承是指一个子类最多只能有一个父类。多继承是一个子类可以有二个以上的父类。由于多继承会带来二义性,在实际应用中应尽量使用单继承。Java语言中的类只支持单继承,而接口支持多继承。Java中多继承的功能是通过接口(interface)来间接实现的[1]。

  1. 单继承———子类只能有一个直接父类
    这里写图片描述
    备注:学生只继承Person类
  2. 多重继承——子类可以有多个直接父类
    这里写图片描述
    备注:博士生:既是人,又是学生,还有可能是讲师呀!

3.3.3继承的实现

在java语言中,继承通过extends关键字来实现。也就是用extends指明当前类子类,并指明从哪个类继承而来的。即在子类的声明中,通过使用extends关键字来显式的指明其父类。

其基本的声明格式如下:

        [修饰符]class 子类名 extends 父类名 [implements 接口名]{            //类体        }
  • 修饰符:可选参数,用于指定类的访问权限,可选值为public、abstract和final。
  • 子类名:必选参数,用于指定子类的名称,类名必须是合法的Java标识符。一般情况下,要求首字符大写。
  • extends 父类名:必选参数,用于指定要定义的子类继承与哪个父类。
  • implements 接口名:可选参数,用时实现某个接口

3.3.4 代码示例1

//父类Animal类public class Animal{    public String address = "动物园"}//子类Dog类public class Dog extends Animal{    public static void main(String[] args) {        Dog dog = new Dog();        System.out.println("狗属于动物,在"+dog.address+"里");    }}/*可以看到,Dog类中没有address成员变量,  但是继承了父类Animal,所以当动物在动物园时,狗也在动物园*/

注意:

  • 子类不能继承父类的私有成员(变量、方法)
  • 在Java中,所有的类都是通过直接或间接继承类java.lang.Object而得到的。
  • 也就是说Animal这个类继承了Object

3.3.5 类继承应用

  1. 为描述和处理个人信息,定义类Person
    这里写图片描述
    代码如下:

            public class Person {          public String name;          public int age;          public Date birth;          public String getInfo() {...}        }
  2. 为描述和处理学生信息,定义类Student

代码如下:

            public class Student {              public String name;              public int age;              public Date birth;              public String school;              public String getInfo() {...}            }
  1. 通过继承,简化Student类的定义:
    这里写图片描述
    代码如下:

            public class Student extends Person{          public String school;        }

3.3.6 多态性

多态机制是面向对象程序设计的最重要特征.
动态绑定是指”在执行过程中(而非编译期间)”,判断所引用的实际对象类型.
多态的特点是采用同名的方式,根据调用方法时传递的参数的多少以及传递参数类型的不同,调用不同的方法,这样对于类的编制而言,可以采用同样的方法获得不同的行为特征.
多态性
1. 编译时多态
表现为方法名相同,而参数列表不同。
典型:System.out.println(参数);它的参数有很多种.
2. 运行时多态
程序运行的时候判断到底是哪个类(父类还是子类的),进而确定实际调用的方法.
对象的多态性(子类对象和父类对象的相互转换关系)

  • 向上转型 父类 父类对象 = new 子类对象的实例 自动完成.
  • 向下转型 子类 子类对象 = 父类对象(但实际是子类对象的实例类型) 强制类型转换

如何实现多态
1. 要有继承
2. 要有重写
3. 父类的引用指向子类的对象
更具体的说明如下:

  • 子类继承父类
  • 子类重写父类的方法
  • 编写方法是,使用父类作为形参类型
  • 将子类的对象作为实参传递给该方法
  • 运行时,根据实际的对象类型动态决定使用那个子类的方法

现实中的示例
这里写图片描述
备注:引入网路的图片
根据现实中的示例完成的代码示例1如下:

/*打印机*/public class Printer {    public void print() {        System.out.println("普通打印!");    }    /**    * 根据不同的打印机 进行不同的打印    *     * @param printer    */    public static void print(Printer printer) {        //可以讲解一下instanceof的使用        printer.print();    }    public static void main(String[] args) {        // 普通打印        print(new Printer());        // 彩色打印        print(new ColorPrinter());        // 黑白打印        print(new BwPrinter());    }}/*** 彩色打印机* @author change**/public class ColorPrinter extends Printer{    @Override    public void print() {        System.out.println("彩色打印!!!!!!");    }}/*** 黑白打印机* @author change**/public class BwPrinter extends Printer{    @Override    public void print() {        System.out.println("黑白打印!!!!!!");    }}

运行结果如下

    普通打印!    彩色打印!!!!!!    黑白打印!!!!!!

多态禁忌

  • 千万不要出现以下操作:就是将父类对象转换成子类对象类型

    Person p = new Person(); //Person是父类   Student是子类Student stu = (Student) p;//出现如下bug /*Exception in thread "main" java.lang.ClassCastException:  day01.Person cannot be cast to day01.Student at day01.Student.main(Student.java:10)*/  

注意:正确操作:我们能转换的是父类的引用指向类自己的子类对象时,该引用可以被提升也可以被强制转换.

3.3.7 super关键字

在Java中,super关键字有两个主要用途;

  • 第一种用途是:在子类的构造方法中,super关键字可以显式地调用父类的构造方法,用于将参数传递给它;
    其一般语法是:

        super(实际参数);

需要注意的是:该语句必须是子类构造方法的第一条语句

如果父类的构造方法中包括参数,则参数列表为必选项,用于指定父类构造方法的入口参数。

  • 第二种用途是:调用父类的成员变量及其成员属性;
    其一般语法是:

        super.成员名;       super.方法名([参数列表]); 

前提条件是:父类中的该成员不是private的。

3.3.8 案例1

//父类Person类class Person {    private String name;    public Person() {        System.out.println("构造器---person---");    }    public Person(String name) {        System.out.println("构造器---person---"+name);    }}//子类Student类class Student extends Person{    public Student(String name) {                    super(name);        System.out.println("构造器---student--"+name);    }}//测试类public class Test{    public static void main(String[] args) {        Student stu = new Student("王三");    }}

3.3.9 成员变量的隐藏

父类Parent中有成员变量A,子类Child定义了与A同名的成员变量B,子类对象ChildObj调用的是自己的成员变量B。
如果把子类对象ChildObj转换为超类对象ParentObj,ParentObj调用的是父类的成员变量A!
注:
1. 隐藏成员变量时,只要同名即可,可以更改变量类型(无论基本类型还是隐藏类型)
2. 不能隐藏超类中的private成员变量,换句话说,只能隐藏可以访问的成员变量。
3. 隐藏超类成员变量A时,可以降低或提高子类成员变量B的访问权限,只要A不是private
4. 隐藏成员变量与是否静态无关!静态变量可以隐藏实例变量,实例变量也可以隐藏静态变量。
5. 可以隐藏超类中的final成员变量。

3.3.10 案例2

class Animal {    char hairColor='B';    int legNumber=2;    static boolean isHuman=true;    public static void testClassMethod() {        System.out.println("The class" + " method in Animal.");    }    public void testInstanceMethod() {        System.out.println("The instance " + " method in Animal.");    }}public class Cat extends Animal {    static int hairColor=1;    char legNumber='A';    double isHuman=3.1415926E5;     public static void testClassMethod() {        System.out.println("The class method" + " in Cat.");    }    public void testInstanceMethod() {        System.out.println("The instance method" + " in Cat.");    }    public static void main(String[] args) {        System.out.println("========child class=========");        Cat myCat = new Cat();        System.out.println("myCat.hairColor="+myCat.hairColor);        System.out.println("myCat.legNumber="+myCat.legNumber);        System.out.println("myCat.isHuman="+myCat.isHuman);        myCat.testClassMethod();        myCat.testInstanceMethod();        System.out.println("========child class ---> parent class=========");        Animal myAnimal = myCat;        System.out.println("========parent class=========");        System.out.println("myAnimal.hairColor="+myAnimal.hairColor);        System.out.println("myAnimal.legNumber="+myAnimal.legNumber);        System.out.println("myAnimal.isHuman="+myAnimal.isHuman);               myAnimal.testClassMethod();        myAnimal.testInstanceMethod();    }}

输出结果:

========child class=========myCat.hairColor=1myCat.legNumber=AmyCat.isHuman=314159.26The class method in Cat.The instance method in Cat.========child class ---> parent class=================parent class=========myAnimal.hairColor=BmyAnimal.legNumber=2myAnimal.isHuman=trueThe class method in Animal.The instance method in Cat.

备注:引入网络案例.

3.3.11 继承中的构造方法

父类中的构造方法不能被子类继承,即便它是public的;
父类的构造方法负责初始化属于它的成员变量,而子类的构造方法则只需考虑属于自己的成员变量,不必去关注父类的情况。

代码示例 1

class Person {    public Person() {        System.out.println("构造器---person---");    }}class Student extends Person{    public Student() {        System.out.println("构造器---student--");    }}public class Test{    public static void main(String[] args) {        Student stu = new Student();    }}

输出结果:

构造器---person---构造器---student--

代码示例 2

public class Person {    public Person(String str) {        System.out.println("构造器---person---"+str);    }}public class Student extends Person{    public Student() {        super("super");//如果父类中没有默认的构造函数,那么在子类的构造函数中 必须采用 super来进行处理        System.out.println("构造器---student--");    }    public static void main(String[] args) {        Student stu = new Student();    }}

输出结果:

构造器---person---super构造器---student--

构造器方法执行顺序:

  • 当实例化子类的对象时,必须先执行父类的构造方法,然后再执行子类的构造方法;
  • 如果父类还有更上级的父类,就会先调用最高父类的构造方法,再逐个依次地将所有继承关系的父类构造方法全部执行;
  • 如果父类的构造方法执行失败,那么子类的对象也将无法实例化。

继承的应用:

代码示例 3

public class Point {    protected float mx, my;    public Point(float mx, float my) {        this.mx = mx;        this.my = my;    }    public static void main(String[] args) {        Cycle cycle = new Cycle(2.5f);    }}class Cycle extends Point {    protected float mx;    public Cycle(float mx) {        this.mx = mx;    }}

继承应用分析:

在实例化Circle类对象时,虚拟机一定会先调用其父类(Point类)的构造方法;
Point类的构造方法需要两个参数来初始化其成员,但此时并没有获得这两个参数,造成Point类的构造方法无法执行;
父类的构造方法执行失败从而导致子类(Circle类)的对象也无法创建;
问题的关键是:在实例化子类对象时,如何将参数传递给父类的构造方法?这就要使用到super关键字。

所以,代码可以修改为:

3.3.12 案例3

public class Point {    protected float mx, my;    public Point(float mx, float my) {        this.mx = mx;        this.my = my;        System.out.println("父类带参的构造方法");        System.out.println(mx+"   "+my);    }    public Point(){        System.out.println("父类不带参的构造方法");    }    public Point(float mx){        System.out.println("父类带一个参 的构造函数");        System.out.println(mx);    }    public static void main(String[] args) {        Cycle cycle = new Cycle(2.5f);    }}class Cycle extends Point {    protected float mx;    public Cycle(float mx) {        super(mx);    }}

3.3.13 方法的重写

方法重写时要遵循的规则:

  • 即方法名相同,形参列表相同和相同或相容的返回值类型;
  • 指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;
  • 指的子类方法的访问权限应比父类方法更大或相等;
  • 覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法。

注意
静态方法不能重写

//一  User类class User {    public int test() {        return 0;    }}class Employee extends User {    public byte test() {        return 0;    }}//二  Bird类class Bird {    public Object fly() {        return 0;    }}class Ostrich extends Bird {    public Byte fly() {        return 0;    }}//三  Bird类class Bird {    public static  int fly() {        return 0;    }}class Ostrich extends Bird {    public  int  fly() {        return 0;    }}观察三个例子,看是否是方法的重写

提示:
Byte是包装类型,byte是基本类型,两个可以互相转换。包装类型默认是null,而基本类型可能不是

//四  bird类class Bird {    public int fly() {        return 1;    }  }class Ostrich extends Bird {    public int fly() {        return 2;    } }//五  bird类class Bird {    public static int fly() {        return 1;    }}class Ostrich extends Bird {    public static int fly() {        return 2;    }}//测试代码public class OverTest {    public static void main(String[] args) {        Ostrich ostrich = new Ostrich();        System.out.println(ostrich.fly());        Bird bird = new Ostrich();        System.out.println(bird.fly());    }}

问题1:通过代码测试,以上四和以上五重写了么?
扩展问题:方法重写与方法重载的区别?

3.4 抽象类

3.4.1 抽象类概述

用abstract关键字来修饰一个类时,这个类叫做抽象类

3.4.2 抽象类语法格式

定义抽象类,语法格式如下:

abstact class 类名{    //类体}

3.4.3 代码示例1

abstact class Animal{    public String type;      public Animal(){        tupe = "猫"    }}

3.4.4 抽象方法

用abstract来修饰一个方法时,该方法叫做抽象方法

抽象方法只有方法的声明,而没有方法的实现,用abstract关键字进行修饰。声明一个抽象方法的基本格式如下:

abstract <方法返回值类型> 方法名(参数列表);
  • 方法返回值类型:必选参数,用于指定方法的返回值类型,如果该方法没有返回值,可以使用关键字void进行标识。方法返回值的类型可以是任何java数据类型
  • 方法名:必选参数,用于指定抽象方法的名称,方法名必须是合法的java标识符。
  • 参数列表:可选参数,用于指定方法中所需的参数。当存在多个参数时,各参数之间应使用逗号分隔。方法的参数可以是任何java数据类型。
  • 含有抽象方法的类必须被声明为抽象类
  • 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
  • 不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法。

3.4.5 代码示例1

public abstract void Animal();  

注意:抽象方法不能使用private 或 static 关键字进行修饰。

包含一个或多个抽象方法的类必须被声明为抽象类。因为抽象方法没有定义方法的实现部分,如果不声明为抽象类,这个类将可以生成对象,这时当用户调用抽象方法时,程序就不知道如何处理了

3.4.6 案例4

//使用abstract关键创建抽象类Animal,在该类中定义相应的变量和方法。abstract class Animal {    public String type;     //定义种类成员变量    //定义构造方法    public Animal(){        type="猫";   //对变量type进行初始化    }    //定义抽象方法    public abstract void zoo();  //把动物放动物园的方法。}//创建Animal的子类Cat类   ,并实现zoo()方法public class Cat extends Animal {    @Override    public void zoo(){        System.out.println("猫进了动物园");    }    static {        System.out.println("加载Cat");    }    {        System.out.println("实例化Cat");    }}//创建Animal的子类Dog()类,并实现zoo()方法public class Dog extends Animal{    @Override    public void zoo(){        System.out.println("把狗放进了动物园");    }    static {        System.out.println("加载Dog类");    }    {        System.out.println("实例化Dog类");    }}//创建一个包含main()方法的公共类Result,在该类中创建子类Cat和Dog实例。public class Result {    public static void main(String[] args) {        System.out.println("调用Cat类的zoo()方法的结果是");        Cat cat =  new Cat();        cat.zoo();        System.out.println("调用Dog类的zoo()方法的结果是");        Dog dog = new Dog();        dog.zoo();    }}

输出结果:

调用Cat类的zoo()方法的结果是加载Animal类加载Cat类实例化Animal实例化Cat类猫进了动物园调用Dog类的zoo()方法的结果是加载Dog类实例化Animal实例化Dog类把狗放进了动物园

或者我们可以试试修改Reault类

public class Result {    public static void main(String[] args) {        //匿名类对象        new Animal() {            @Override            public void zoo() {                // TODO Auto-generated method stub            }        };        new Cat();        new Dog();        new Dog();    }}

输出结果是:

加载Animal类实例化Animal加载Cat类实例化Animal实例化Cat类加载Dog类实例化Animal实例化Dog类实例化Animal实例化Dog类

思考:
问题1:为什么抽象类不可以使用final关键字声明?
问题2:一个抽象类中可以定义构造器吗?

3.6 静态块、语句块、构造函数在继承关系的使用

3.6.1 静态块、语句块、构造函数执行顺序的说明

3.6.2 案例5

class Parent{        static String name = "hello";        {            System.out.println("3 parent  block");        }        static {            System.out.println("1 parent static block");        }            public Parent(){            System.out.println("4 parent constructor");        }    }    class Child extends Parent{        static String childName = "hello";        {            System.out.println("5 child  block");        }        static {            System.out.println("2 child static block");        }            public Child(){            System.out.println("6 child constructor");        }    }    public class StaticIniBlockOrderTest {        public static void main(String[] args) {        new Child();//语句(*)        }    } 输入结果:1 parent static block2 child static block3 parent  block4 parent constructor5 child  block6 child constructor

5 总结

本章主要讲解了类的继承及其应用;抽象类的应用;静态块、初始化块、构造函数在继承关系中的使用。其中更扩展延伸出了super关键字,继承中的构造方法等知识点。


6 预习任务

  • 1.接口(接口的概念,接口的定义,接口的继承,使用接口)
  • 2.内部类
  • 3.匿名类
  • 4.静态内部类

以上都是个人整理资料部分,有问题欢迎大家留言!如需转载,请注明出处!

2 0
原创粉丝点击