> 文档中心 > Java 面向对象 day4

Java 面向对象 day4

Java 面向对象 day4

  • Java 面向对象 day4
  • 面向对象特征之二: 继承
    • 一、定义
    • 二、特征
    • 三、优点
    • 四、基本使用
  • super() 的使用
    • 一、super()的使用实例 一一 子类重写父类的方法
    • 二、super()的使用实例 一一 子类重写父类的变量
  • 方法的重写
    • 一、定义
    • 二、应用 一一 实现宠物喂养
  • 抽象类和抽象方法
    • 一、定义
    • 二、应用 一一 学生和教师
  • 面向对象特征之三: 多态
    • 一、定义
    • 二、多态的应用
      • 1.父类引用指向子类对象 一一 向上转型
      • 2.子类引用指向父类对象 一一 向下转型

Java 面向对象 day4

面向对象特征之二: 继承

一、定义

将一系列类中共有的属性和方法提取出来形成一个新的类,其他类去继承该类.新的类称之为父类(基类,超类),其他类称之为子类(派生类),在Java中一个类只能继承 一个父类,不能继承多个父类,子类继承父类,子类拥有父类所有非私有的属性和方法

为什么要有继承?
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。

二、特征

1. 只支持单继承,即一个子类只允许有一个父类。
2. 子类可以拥有父类的属性和方法
3. 子类可以拥有自己的属性和方法
4. 子类可以重写覆盖父类的方法
5. 可以声明父类,创建子类
6. 继承具有传递性
7. 父类的构造方法不能被继承

三、优点

1. 继承的出现提高了代码的复用性。
2. 父类的属性方法可以用于子类。
3. 可以轻松的定义子类。
4. 继承的出现让类与类之间产生了关系,提供了多态的前提。
5. 不要仅为了获取其他类中某个功能而去继承。

四、基本使用

Person.java

/ * 将子类中共有的属性和方法提取出来形成一个新的类 */public class Person {    private int id;    private String name;    private String sex;    private int age;    public int getId() { return id;    }    public void setId(int id) { this.id = id;    }    public String getName() { return name;    }    public void setName(String name) { this.name = name;    }    public String getSex() { return sex;    }    public void setSex(String sex) { this.sex = sex;    }    public int getAge() { return age;    }    public void setAge(int age) { this.age = age;    }    public void eat(String food) { System.out.println(name + "吃了一顿" + food);    }    public void sleep(String address) {    }}

Student .java

/ * 子类继承父类:关键字使用extends * 可以拥有父类中非私有的属性和方法 */public class Student extends Person {    private String grade;    public String getGrade() { return grade;    }    public void setGrade(String grade) { this.grade = grade;    }    //读书的方法    public void read() {    }}

Teacher .java

public class Teacher extends Person {    private String level;  //级别    public String getLevel() { return level;    }    public void setLevel(String level) { this.level = level;    }    public void teach() {    }}

TestExtends .java

public class TestExtends {    public static void main(String[] args) { Student stu = new Student(); stu.setId(1001);  //stu可以引用出父类中的方法 stu.setName("张三"); stu.setAge(20); stu.setSex("男"); stu.setGrade("大二");   //子类中特有的属性 stu.eat("大闸蟹"); Teacher t = new Teacher(); t.setId(1002); t.setName("李四"); t.setAge(19); t.setSex("男"); t.setLevel("厨师"); t.eat("霸王餐"); //小的数据类型自动转换为大的数据类型 Person per = new Student();   //当父类引用指向子类对象时,因为类型是父类,所以只能使用父类与子类共有的属性和方法 per.setId(1005);    } /*     * 运行结果:     *      张三吃了一顿大闸蟹     *      李四吃了一顿霸王餐     */     }

super() 的使用

一、super()的使用实例 一一 子类重写父类的方法

在Java中super指代父类对象(直接父类),也就是说,super相当于是一个直接new出来的父类对象,所以可以通过它来调用父类的那些非private修饰的变量、方法(对于我们普通new出来的对象来说,也就只能访问那些非private的成员变量、方法了,这里的访问是指通过“对象名.变量名或方法名”的形式)。所以,super这个对象也就是一个普通对象,同样遵循访问控制修饰符的准则
然而,对于子类来说,子类通过继承就直接拥有了父类的非private变量、方法,也就可以在子类中直接使用,再加一个super来修饰,岂不是显得有点多余了?正常情况下来说,是有点多余了(但是可以明确提示我们这是调用的父类变量或方法),但super关键字主要是用在以下两种情况中:
(1)发生了重写的情况
重写也分为两种情况,一个是重写了父类的方法;一个是重写了父类的成员变量;
重写父类方法的情况:

public class A {    String name = "lly";    protected void getName(){ System.out.println("父类getName->"+ name);    }}public class B extends A {    String nameB = "llyB";    @Override    protected void getName() { System.out.println("子类getName->"+nameB); super.getName();    }    public static void main(String[] args) { B b = new B(); b.getName();    }}

打印如下:
子类getName->llyB
父类getName->lly

在子类B中,我们重写了父类的getName方法,如果在重写的getName方法中我们去调用了父类的相同方法,必须要通过super关键字显示的指明出来
如果不明确出来,按照子类优先的原则,相当于还是再调用重写的getName()方法,此时就形成了死循环,执行后会报java.lang.StackOverflowError异常。

二、super()的使用实例 一一 子类重写父类的变量

重写父类变量的情况:
我们将B类简单改造一下:

public class B extends A {    String name = "llyB";    @Override    protected void getName() { name = super.name; System.out.println("子类getName->"+name);    }    public static void main(String[] args) { B b = new B(); b.getName();    }}

打印如下:
子类getName->lly

此时子类B中有一个和父类一样的字段(也可以说成父类字段被隐藏了),为了获得父类的这个字段我们就必须加上super,如果没有加,直接写成name = name;不会报错,只是会警告,表示此条语句没有任何意义,因为此时都是访问的子类B里面的那么字段。

我们通过super是不能访问父类private修饰的变量和方法的,因为这个只属于父类的内部成员,一个对象是不能访问它的private成员的。

(2)在子类的构造方法中
编译器会自动在子类构造函数的第一句加上 super(); 来调用父类的无参构造器;此时可以省略不写。如果想写上的话必须在子类构造函数的第一句,可以通过super来调用父类其他重载的构造方法,只要相应的把参数传过去就好。

因此,super的作用主要在下面三种情况下:
1、调用父类被子类重写的方法;
2、调用父类被子类重定义的字段(被隐藏的成员变量);
3、调用父类的构造方法;

其他情况,由于子类自动继承了父类相应属性方法,关键字super可以不显示写出来。

方法的重写

一、定义


在子类中可以根据需要对从父类中继承来的方法进行改造,也称方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。

要求:
1.重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型
2.重写方法不能使用比被重写方法更严格的访问权限。
3.重写和被重写的方法须同时为static的,或同时为非static的
4.子类方法抛出的异常不能大于父类被重写方法的异常

二、应用 一一 实现宠物喂养

Animal .java

public class Animal {    private String name = "无名氏";    private int health = 80; //健康值    private int love = 20;    public Animal() { this.health = 80;    }    public Animal(String name) { this.name = name;    }    public String getName() { return name;    }    public void setName(String name) { this.name = name;    }    public int getHealth() { return health;    }    public void setHealth(int health) { this.health = health;    }    public int getLove() { return love;    }    public void setLove(int love) { this.love = love;    }    /*     * 输出宠物信息     */    public void print() { System.out.println("宠物的自白:\n我的名字叫:" + this.name + ",我的健康值为:" + this.health + " ,我和主人的亲密度是:" + this.love + "!");    }    /*     * 喂食的方法     * 根据吃的东西不同,增加的健康值和亲密度     */    public void eat(String food) {    }}

Dog .java

public class Dog extends Animal {    private String strain; //品种    public Dog() { //super();  调用父类构造方法,用于实例化 //在构造方法中使用super  必须放在第一行 super();    }    //子类构造方法  方法形参个数为 子类参数+父类参数    public Dog(String name, String strain) { super(name);   //也可以同时调用父类带参构造函数,初始化数据 this.strain = strain;    }    public String getStrain() { return strain;    }    public void setStrain(String strain) { this.strain = strain;    }    public void show() { System.out.println("调用父类属性和方法"); super.getHealth(); super.print();    }    @Override    public void print() { super.print(); System.out.println("我是一只" + this.getStrain() + "犬..");    }    @Override    public void eat(String food) { if (getHealth() >= 100) {     System.out.println("狗仔已经很健康了,不需要喂食..."); } else {     System.out.println("狗狗吃了一顿" + food + ",健康值增加:5,亲密度增加2");     setHealth(getHealth() + 5);     setLove(getLove() + 2); }    }}

Penguin .java

public class Penguin extends Animal {    private String sex;    public Penguin() {    }    public Penguin(String name, String sex) { super(name); this.sex = sex;    }    public String getSex() { return sex;    }    public void setSex(String sex) { this.sex = sex;    }    @Override   //重写注解, 规定该方法只能是重写父类中的方法    public void print() { super.print(); System.out.println("我的性别是:" + this.getSex() + ".");    }    @Override    public void eat(String food) { if (getHealth() >= 100) {     System.out.println(getName() + "已经很健康了,不需要喂食..."); } else {     System.out.println(getName() + "吃了一顿" + food + ",健康值增加:3,亲密度增加1");     setHealth(getHealth() + 3);     setLove(getLove() + 1); }    }}

TestAnimal .java

public class TestAnimal {public static void main(String[] args) {Animal a = new Animal("保卫");a.print();Dog dog = new Dog("欧欧", "拉布拉多");dog.print();dog.eat("肉骨头");Penguin pen = new Penguin("花花", "Q妹");pen.print();pen.eat("北极熊");}}

运行结果:
宠物的自白:
我的名字叫:保卫,我的健康值为:80 ,我和主人的亲密度是:20!
宠物的自白:
我的名字叫:欧欧,我的健康值为:80 ,我和主人的亲密度是:20!
我是一只拉布拉多犬…
狗狗吃了一顿肉骨头,健康值增加:5,亲密度增加2
宠物的自白:
我的名字叫:花花,我的健康值为:80 ,我和主人的亲密度是:20!
我的性别是:Q妹.
花花吃了一顿北极熊,健康值增加:3,亲密度增加1

抽象类和抽象方法

一、定义

抽象(abstract):在程序的提取过程中,父类的概念会越来越模糊化,一般通过为父类设置 一个关键字.使父类成为一个抽象类.这就是抽象。
抽象类:使用abstract关键字修饰的类叫做抽象类。
抽象方法:使用abstract关键字修饰的方法叫做抽象方法,且该方法没有方法体。

抽象类与抽象方法的关系:
抽象方法只能存在于抽象类,但是抽象类中不一定有抽象方法。
子类继承父类时,子类必须实现父类中所有的抽象方法,除非子类也是一个抽象类,但是最终的子类也必须实现(重写)所有抽象方法。

二、应用 一一 学生和教师

抽象父类

/ * 使用abstract修饰的类叫做抽象类   一般都与父类设置抽象类 */public abstract class Person {    private int id;    private String name;    private String sex;    private int age;    public int getId() { return id;    }    public void setId(int id) { this.id = id;    }    public String getName() { return name;    }    public void setName(String name) { this.name = name;    }    public String getSex() { return sex;    }    public void setSex(String sex) { this.sex = sex;    }    public int getAge() { return age;    }    public void setAge(int age) { this.age = age;    }    public void eat(String food) { System.out.println(name + "吃了一顿" + food);    }    //所有需要重写才使用的方法,一般都设置为抽象方法    //有抽象方法的类,一定是抽象类    public abstract void sleep(String address);}

子类1-学生

/* * 子类继承父类:关键字使用extends    可以拥有父类中非私有的属性和方法 */public class Student extends Person {    private String grade;    public String getGrade() { return grade;    }    public void setGrade(String grade) { this.grade = grade;    }    @Override    public void eat(String food) { System.out.println(grade + "学生" + getName() + ",正在食堂吃" + food);    }    //读书的方法    public void read() { System.out.println("学生" + getName() + "在" + grade + "年级上课....");    }    /*     * 子类继承抽象父类,必须实现父类中所有的抽象方法     */    @Override    public void sleep(String address) { System.out.println("学生" + getName() + ",回到" + address + "进行午休.....");    }}

子类2-教师

public class Teacher extends Person {    private String level;  //级别    public String getLevel() { return level;    }    public void setLevel(String level) { this.level = level;    }    public void teach(String course) { System.out.println(level + getName() + "正在上" + course + "课...");    }    @Override    public void sleep(String address) { System.out.println(level + getName() + "正在" + address + "中睡午觉.....");    }}

测试类

public class TestPerson {    public static void main(String[] args) {/ * 抽象类不可以被实例化,只能被继承 *///Person person = new Person(); Teacher t = new Teacher(); t.setId(6001); t.setName("谭哥"); t.setLevel("高级讲师"); t.teach("java"); t.eat("澳洲龙虾"); t.sleep("办公室"); Student stu = new Student(); stu.setId(1001); stu.setName("张三"); stu.setGrade("大四"); stu.read(); stu.eat("波士顿龙虾"); stu.sleep("宿舍");    }}

运行结果:
高级讲师谭哥正在上java课…
谭哥吃了一顿澳洲龙虾
高级讲师谭哥正在办公室中睡午觉…
学生张三在大四年级上课…
大四学生张三,正在食堂吃波士顿龙虾
学生张三,回到宿舍进行午休…

面向对象特征之三: 多态

一、定义

同一指令作用于不同对象,产生不同反应或输出不同效果. 相同的指令被不同对象执行,产生不同的效果。

多态的好处:
1.提高系统的扩展性
2.降低系统的耦合性

多态的实现方式:
1.以方法的形式实现多态
2.以对象的形式实现多态

多态性,是面向对象中最重要的概念,在java中有两种体现:
1.方法的重载(overload)和重写(overwrite)。
2.对象的多态性 —— 可以直接应用在抽象类和接口上。

Java引用变量有两个类型编译时类型运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
若编译时类型和运行时类型不一致,就出现多态(Polymorphism)

对象的多态 —在Java中,子类的对象可以替代父类的对象使用

  • 一个变量只能有一种确定的数据类型
  • 一个引用类型变量可能指向(引用)多种不同类型的对象

Person p = new Student();
Object o = new Person();//Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对象
子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。

一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
Student m = new Student();
m.school = “pku”; //合法,Student类有school成员变量
Person e = new Student();
e.school = “pku”;//非法,Person类没有school成员变量
属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。

二、多态的应用

1.父类引用指向子类对象 一一 向上转型

向上转型:它表示我定义了一个Person类型的引用,指向新建的Student类型的对象。由于Student是继承自它的父类Person,所以Person类型的引用是可以指向Student类型的对象的。这就是“向上转型”。

宠物类

public class Pet {private String name = "无名氏";  private int health = 80;private int love = 20;public Pet() {this.health = 80;}public Pet(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getHealth() {return health;}public void setHealth(int health) {this.health = health;}public int getLove() {return love;}public void setLove(int love) {this.love = love;}/ * 喂食的方法 * 根据吃的东西不同,增加的健康值和亲密度 */public void eat(String food) {System.out.println("宠物吃了一顿"+food);}}

宠物主人类

import com.gec.polymorphism.Pet;public class Master {    private String name;    private int money;    public Master() {    }    public Master(String name, int money) { this.name = name; this.money = money;    }    public String getName() { return name;    }    public void setName(String name) { this.name = name;    }    public int getMoney() { return money;    }    public void setMoney(int money) { this.money = money;    }    /     * //给宠物喂食     * 未使用多态     * public void feed(Dog dog) { dog.eat("狗肉"); }     * public void feed(Penguin pen) { pen.eat("里脊肉"); }     */    //通过多态的形式,喂食    //子类对象转换为父类引用,这种方式是多态的向上转型    public void feed(Pet pet, String food) { pet.eat(food);    }}

狗类

import com.gec.polymorphism.Pet;public class Dog extends Pet {private String strain;public Dog() {super();}public Dog(String name, String strain) {super(name);this.strain = strain;}public String getStrain() {return strain;}public void setStrain(String strain) {this.strain = strain;}@Overridepublic void print() {super.print();System.out.println("我是一只"+this.getStrain()+"犬..");}@Overridepublic void eat(String food) {if(getHealth()>=100) {System.out.println("狗仔已经很健康了,不需要喂食...");}else {System.out.println("狗狗吃了一顿"+food+",健康值增加:5,亲密度增加2");setHealth(getHealth()+5);setLove(getLove()+2);}}}

测试类

import com.gec.polymorphism.Master;public class TestPet {    public static void main(String[] args) { Master m = new Master("大王", 200000); Dog dog = new Dog("欧欧", "金毛"); dog.setHealth(60); m.feed(dog, "两斤大骨头");    }}

运行结果:
狗狗吃了一顿两斤大骨头,健康值增加:5,亲密度增加2

2.子类引用指向父类对象 一一 向下转型

向下转型 :它表示在父类引用中无法调用子类中特有的属性和方法,必须将其还原为子类引用才可以使用子类中特有的属性和方法,这种转换就叫做向下转型。

宠物类

public class Pet {private String name = "无名氏";  private int health = 80;private int love = 20;public Pet() {this.health = 80;}public Pet(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getHealth() {return health;}public void setHealth(int health) {this.health = health;}public int getLove() {return love;}public void setLove(int love) {this.love = love;}}

宠物主人类

public class Master {    private String name;    private int money;    public Master() {    }    public Master(String name, int money) { this.name = name; this.money = money;    }    public String getName() { return name;    }    public void setName(String name) { this.name = name;    }    public int getMoney() { return money;    }    public void setMoney(int money) { this.money = money;    }    public void play(Pet pet) { //父类引用已经无法调用子类中特有的属性和方法,必须将对象还原为子类引用,这种转换方式为多态的向下转型 //父类引用中的对象只有1个不能同时转换为两种对象 //使用instanceof  判断具体对象是否属于某个类型  如果属于返回true if (pet instanceof Dog) {     Dog dog = (Dog) pet;     dog.jieUFO(); } else if (pet instanceof Penguin) {     Penguin pen = (Penguin) pet;     pen.swimming(); }    }}

狗类

public class Dog extends Pet {private String strain;public Dog() {super();}public Dog(String name, String strain) {super(name);this.strain = strain;}public String getStrain() {return strain;}public void setStrain(String strain) {this.strain = strain;}public void jieUFO() {if(getHealth()>=20) {System.out.println(getName()+"与主人一起玩飞碟,健康值减10,亲密度加15");setHealth(getHealth()-10);setLove(getLove()+15);}else {System.out.println(getName()+"已经饿得不行了,不能陪主人接飞碟了...");}}}

企鹅类

public class Penguin extends Pet {    private String sex;    public Penguin() {    }    public Penguin(String name, String sex) { super(name); this.sex = sex;    }    public String getSex() { return sex;    }    public void setSex(String sex) { this.sex = sex;    }    public void swimming() { if (getHealth() >= 20) {     System.out.println(getName() + getSex() + "与主人一起游泳,健康值减5,亲密度增加10");     setHealth(getHealth() - 5);     setLove(getLove() + 10); } else {     System.out.println(getName() + getSex() + "已经饿得不行了,不能陪主人游泳了...."); }    }}

测试类类

public class TestPet {    public static void main(String[] args) { Master m = new Master("大王", 200000); Dog dog = new Dog("欧欧", "金毛"); m.play(dog); Penguin penguin = new Penguin("花花","Q妹"); m.play(penguin);    }}

运行结果:
欧欧的狗狗与主人一起玩飞碟,健康值减10,亲密度加15
花花Q妹与主人一起游泳,健康值减5,亲密度增加10