Java 面向对象 day4
Java 面向对象 day4
- Java 面向对象 day4
- 面向对象特征之二: 继承
-
- 一、定义
- 二、特征
- 三、优点
- 四、基本使用
- 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