1.为什么使用继承
将重复抽取到父类中,代码使用继承优化设计
2.使用继承优化
方便修改代码、减少代码量
子类与父类是is-a关系
3.如何使用继承
首先编写父类
class Pet {
//公共的属性和方法
}
然后编写子类,继承父类
class Dog extends Pet {
//子类特有的属性和方法
}
class Penguin extends Pet {
}
一个子类只能继承一个父类
继承关键字:extends
举例:访问父类的构造结构
public abstract class Pet {
/*宠物类*/
private String name;
private int love;
private int health;
/*
* get.set
*
* */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
/*
*
* 带参数的方法
*
* */
public Pet(String name, int love, int health) {
super();
this.name = name;
this.love = love;
this.health = health;
System.out.println("父类有参的构造方法");
}
/*
*
*
* 不带参数的方法
*
* */
public Pet() {
super();
System.out.println("父类无参的构造方法");
// TODO Auto-generated constructor stub
}
/*
*
* 打印print
*
* */
public void print(){
System.out.println("name="+name+"love"+love+"health"+health);
}
}
public class Dog extends Pet{
private String strain;
/*
* get.set
*
* */
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/*
*
* 带参数的方法
*
* */
public Dog(String name, int love, int health, String strain) {
super(name, love, health);
this.strain = strain;
System.out.println("子类有参构造方法");
}
/*
*
* 不带参数的方法
*
* */
public Dog() {
super();
System.out.println("子类无参构造方法");
// TODO Auto-generated constructor stub
}
}
public class Penguin extends Pet{
private String gender;
/*
* get.set
*
* */
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
/*
*
* 带参数的方法
*
* */
public Penguin(String name, int love, int health, String gender) {
super(name, love, health);
this.gender = gender;
}
/*
*
* 不带参数的方法
*
* */
public Penguin() {
super();
// TODO Auto-generated constructor stub
}
}
public class Test {
public static void main(String[] args) {
//初始化一个子类对象
//首先初始化父类对象
Dog d=new Dog("小黑", 99, 99, "动漫人物");
}
}
心得:
super()表示代表父类的名字,只是把自己的属性初始化了,但是父类的属性还是由父类来初始化
使用了继承,必然会初始化父类对象
举例:访问父类的方法、属性
public abstract class Pet {
/*宠物类*/
private String name;
private int love;
private int health;
/*
* get.set
*
* */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
/*
*
* 带参数的方法
*
* */
public Pet(String name, int love, int health) {
super();
this.name = name;
this.love = love;
this.health = health;
System.out.println("父类有参的构造方法");
}
/*
*
*
* 不带参数的方法
*
* */
public Pet() {
super();
System.out.println("父类无参的构造方法");
// TODO Auto-generated constructor stub
}
/*
*
* 打印print
*
* */
/*public void print(){
System.out.println("name="+name+"love"+love+"health"+health);
}*/
}
public class Dog extends Pet{
private String strain;
/*
* get.set
*
* */
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/*
*
* 带参数的方法
*
* */
public Dog(String name, int love, int health, String strain) {
/*访问父类的带参数的构造方法*/
super(name, love, health);
this.strain = strain;
System.out.println("子类有参构造方法");
}
/*
*
* 不带参数的方法
*
* */
public Dog() {
super();
System.out.println("子类无参构造方法");
// TODO Auto-generated constructor stub
}
//重写
@Override
public void print() {
//访问父类的方法
super.print();
//访问父类属性
System.out.println("name="+super.getName()+"love="+super.getLove()+"health="+super.getHealth());
}
}
public class Test {
public static void main(String[] args) {
//有参数
Dog dog===new Dog("小黑", 99, 99, "动漫人物");
dog.print();
}
}
心得:
访问父类私有属性name时,super.name报错,不能被访问,如果还想访问的话,可以使用get方法实现,如super.getName()
4.子类可以继承父类的所有些资源吗?
不能被继承的父类成员:private成员不能、子类与父类不在同包,使用默认访问权限的成员、构造方法
举例:
public abstract class Pet {
/*宠物类*/
private String name;
private int love;
private int health;
//默认访问权限
int num;
/*
* get.set
*
* */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
/*
*
* 带参数的方法
*
* */
public Pet(String name, int love, int health) {
super();
this.name = name;
this.love = love;
this.health = health;
System.out.println("父类有参的构造方法");
}
/*
*
*
* 不带参数的方法
*
* */
public Pet() {
super();
System.out.println("父类无参的构造方法");
// TODO Auto-generated constructor stub
}
/*
*
* 打印print
*
* */
public void print(){
System.out.println("name="+name+"love"+love+"health"+health);
}
}
public class Dog extends Pet{
private String strain;
/*
* get.set
*
* */
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/*
*
* 带参数的方法
*
* */
public Dog(String name, int love, int health, String strain) {
/*访问父类的带参数的构造方法*/
super(name, love, health);
this.strain = strain;
System.out.println("子类有参构造方法");
}
/*
*
* 不带参数的方法
*
* */
public Dog() {
super();
System.out.println(super.num); //默认访问权限
System.out.println("子类无参构造方法");
// TODO Auto-generated constructor stub
}
//重写
@Override
public void print() {
super.print();
Sysotem.out.println(super.num)在同一个包下使用默认权限可访问
}
}
package demo2;
public class Cat extends Pet{
private String eyeColor;
public String getEyeColor() {
return eyeColor;
}
public void setEyeColor(String eyeColor) {
this.eyeColor = eyeColor;
}
public Cat() {
super();
// TODO Auto-generated constructor stub
}
public Cat(String eyeColor) {
super();
this.eyeColor = eyeColor;
}
/*不同包不可使用*/
private void print() {
System.out.println(num);
}
}
5.访问修饰符总结
记住有几个
6.多重继承关系的初始化顺序是怎样的
Animal--pet--dog 假设它们都是继承类,new一个Dog的无参方法,调用无参方法之前先必须调用pet()构造方法,调用pet方法有发现需要先调用animal方法
7.何时使用继承
继承与真实世界类似,符合is-a关系的设计使用继承
继承是代码重用的一种方式、将子类共有的属性和行为放到父类中
8.使用继承后效果
调用父类的print()方法,不能显示Dog的strain信息
举例:
public abstract class Pet {
/*宠物类*/
private String name;
private int love;
private int health;
/*
* get.set
*
* */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
/*
*
* 带参数的方法
*
* */
public Pet(String name, int love, int health) {
super();
this.name = name;
this.love = love;
this.health = health;
}
/*
*
*
* 不带参数的方法
*
* */
public Pet() {
super();
// TODO Auto-generated constructor stub
}
/*
*
* 打印print
*
* */
public void print(){
System.out.println("name="+name+"love"+love+"health"+health);
}
}
public class Dog extends Pet{
private String strain;
/*
* get.set
*
* */
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/*
*
* 带参数的方法
*
* */
public Dog(String name, int love, int health, String strain) {
/*访问父类的带参数的构造方法*/
super(name, love, health);
this.strain = strain;
}
/*
*
* 不带参数的方法
*
* */
public Dog() {
super();
System.out.println(super.num); //默认访问权限
// TODO Auto-generated constructor stub
}
//重写
@Override
public void print() {
print();*/
}
}
public class Test {
public static void main(String[] args) {
//有参数
Dog d===new Dog("小黑", 99, 99, "动漫人物");
d.print();
}
}
9.方法重写
子类重写父类方法,方法名不能变,返回值父类值的子类对象
10.方法重写的规则
n方法名相同
n参数列表相同
n返回值类型相同或者是其子类;
n访问权限不能严于父类
举例:
public abstract class Pet {
/*宠物类*/
private String name;
private int love;
private int health;
//默认访问权限
int num;
/*
* get.set
*
* */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
/*
*
* 带参数的方法
*
* */
public Pet(String name, int love, int health) {
super();
this.name = name;
this.love = love;
this.health = health;
}
/*
*
*
* 不带参数的方法
*
* */
public Pet() {
super();
// TODO Auto-generated constructor stub
}
/*
*
* 打印print
*
* */
public void print(){
System.out.println("name="+name+"love"+love+"health"+health);
}
}
public class Dog extends Pet{
private String strain;
/*
* get.set
*
* */
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/*
*
* 带参数的方法
*
* */
public Dog(String name, int love, int health, String strain) {
super(name, love, health);
this.strain = strain;
}
/*
*
* 不带参数的方法
*
* */
public Dog() {
super();
// TODO Auto-generated constructor stub
}
//重写
@Override
public void print() { System.out.println("name="+super.getName()+"love="+super.getLove()+"health="+super.getHealth()+"strain="+strain);
}
}
public class Test {
public static void main(String[] args) {
//有参数
Dog d===new Dog("小黑", 99, 99, "动漫人物");
d.print();
}
}
11.super关键字来访问父类的成员
super只能出现在子类的方法和构造方法中
super调用构造方法时,只能是第一句
super不能访问父类的private成员
练习:车辆的运行
package lx;
public class Motor {
private String pl;
private String qgs;
private String xh;
public String getPl() {
return pl;
}
public void setPl(String pl) {
this.pl = pl;
}
public String getQgs() {
return qgs;
}
public void setQgs(String qgs) {
this.qgs = qgs;
}
public String getXh() {
return xh;
}
public void setXh(String xh) {
this.xh = xh;
}
public Motor(String pl, String qgs, String xh) {
super();
this.pl = pl;
this.qgs = qgs;
this.xh = xh;
}
public Motor() {
super();
// TODO Auto-generated constructor stub
}
//自己的方法
public void work(){
System.out.println("发动机开始工作");
}
//
}
package lx;
public class Car extends Motor {
private String fdj;
private String cp;
private String cx;
public String getFdj() {
return fdj;
}
public void setFdj(String fdj) {
this.fdj = fdj;
}
public String getCp() {
return cp;
}
public void setCp(String cp) {
this.cp = cp;
}
public String getCx() {
return cx;
}
public void setCx(String cx) {
this.cx = cx;
}
public Car(String pl, String qgs, String xh, String fdj, String cp,
String cx) {
super(pl, qgs, xh);
this.fdj = fdj;
this.cp = cp;
this.cx = cx;
}
public Car() {
super();
// TODO Auto-generated constructor stub
}
//
public void run(){
System.out.println("车牌为:"+cp+"的"+cx+"启动....");
super.work();
System.out.println("型号:"+super.getXh());
System.out.println("排量:"+super.getPl());
System.out.println("汽缸数:"+super.getQgs());
}
}
package lx;
public class CarTest {
public static void main(String[] args) {
Car car=new Car("3000", "12", "奔馳330", "奔馳330", "金A123456", "寶馬");
car.run();
}
}
12.抽象类
实例化Pet没有意义
Pet pet = new Pet ("贝贝",20,40);
pet.print();
13.如何避免/限制实例化(关键字abstract)
abstract也可用于抽象类
举例
public abstract class Pet {
}
abstract作用限制一个类的实例化,这个类的存在是为了帮助其他类,实例化这个类无意义,让这个类无法做对象了
abstract也可用于-抽象方法
举例:
public abstract class Pet {
public void print() {
//…
}
}
抽象方法没有方法体
抽象方法必须在抽象类里(类是抽象的,方法可以是抽象的可以不是,一旦方法是抽象的,类必须是抽象的)
抽象方法必须在子类中被实现,除非子类是抽象类
举例:
public abstract class Pet {
/*宠物类*/
private String name;
private int love;
private int health;
/*
* get.set
*
* */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
/*
*
* 带参数的方法
*
* */
public Pet(String name, int love, int health) {
super();
this.name = name;
this.love = love;
this.health = health;
System.out.println("父类有参的构造方法");
}
/*
*
*
* 不带参数的方法
*
* */
public Pet() {
super();
System.out.println("父类无参的构造方法");
// TODO Auto-generated constructor stub
}
/*抽象方法*/
public abstract void print();
}
public class Dog extends Pet{
private String strain;
/*
* get.set
*
* */
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
/*
*
* 带参数的方法
*
* */
public Dog(String name, int love, int health, String strain) {
super(name, love, health);
this.strain = strain;
}
/*
*
* 不带参数的方法
*
* */
public Dog() {
super();
// TODO Auto-generated constructor stub
}
//必须重写
@Override
public void print() { System.out.println("name="+super.getName()+"love="+super.getLove()+"health="+super.getHealth()+"strain="+strain);
}
}
14.final用法
1-某个类不希望被继承前面加final
最终版的类
public final class Penguin extends Pet {
//…
}
2-方法不希望被重写
最终版的方法
public final void print () {
//…
}
3-属性值不希望被修改
最终版的属性值
public class Penguin {
final String home ="南极";// 居住地
public void setHome(String name){
this.home=home; //错误,不可再赋值
}
}
举例1:修饰类
package Final;
public final class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(String name) {
super();
this.name = name;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public final void Person() {
System.out.println("你好");
}
}
package Final;
public class Test extends Person {
/*
* 出现错误:修饰类
* The type Test cannot subclass the final class Person*/
}
举例2:修饰方法
package Final;
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(String name) {
super();
this.name = name;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public final void Person() {
System.out.println("你好");
}
}
package Final;
public class Test1 extends Person {
/*
*
* 错误:修饰方法
* 父类的f方法是final类型,不可重写!
*
* */
public void print(){
}
}
举例3:修饰属性
package Final;
public class Person {
private String name;
public final int num=10;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(String name) {
super();
this.name = name;
}
public void print() {
System.out.println("你好");
}
}
package Final;
public class Test2 extends Person {
/*
*
* 错误:属性值不希望被修改
*
*
* */
private void print1() {
// TODO Auto-generated method stub
System.out.println(num);
num=20;
}
}
补充:同时使用static和final关键字
static final用来修饰成员变量和成员方法,可简单理解为“全局常量”,
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
对于方法,表示不可覆盖,并且可以通过类名直接访问。
15.常见错误
使用变量final修饰引用型变量,不可以再指向另外的对象
final Dog dog = new Dog("欧欧");
dog = new Dog("亚亚");
练习
package lx2;
public abstract class MotorVehicle {
private String no;
private String brand;
private String color;
private String mileage;
public MotorVehicle(String no, String brand, String color, String mileage) {
super();
this.no = no;
this.brand = brand;
this.color = color;
this.mileage = mileage;
}
public MotorVehicle() {
super();
// TODO Auto-generated constructor stub
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getMileage() {
return mileage;
}
public void setMileage(String mileage) {
this.mileage = mileage;
}
/*
* 計算租賃價格、
* */
public abstract double calcRent(int days);
}
package lx2;
/*
* 小轿车
* final不可以被继承
*
* */
public final class Car extends MotorVehicle{
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Car(String no, String brand, String color, String mileage,
String type) {
super(no, brand, color, mileage);
this.type = type;
}
public Car() {
super();
// TODO Auto-generated constructor stub
}
/*
* 小轎車租賃方法
* */
@Override
public double calcRent(int days) {
double rent=0;
String type=this.type;
if(type.equals("550i")) {
rent=500*days;
}else if(type.equals("別克商務艙GL8")) {
rent=600*days;
}else if(type.equals("別克林蔭大道")) {
rent=300*days;
}
return rent;
}
}
package lx2;
public final class Bus extends MotorVehicle{
private int seatCount;
public int getSeatCount() {
return seatCount;
}
public void setSeatCount(int seatCount) {
this.seatCount = seatCount;
}
public Bus(String no, String brand, String color, String mileage,
int seatCount) {
super(no, brand, color, mileage);
this.seatCount = seatCount;
}
public Bus() {
super();
// TODO Auto-generated constructor stub
}
/*
*
* 客车租赁价格
*
*
* */
@Override
public double calcRent(int days) {
double rent=0;
int seat=this.seatCount;
if(seat<16) {
rent=800*days;
}else {
rent=1500*days;
}
return rent;
}
}
package lx2;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int days=0;
int choice=0;
Car car=null;
Bus bus=null;
double rent=0;
System.out.println("*************");
System.out.println("欢迎");
System.out.println("请输入您要租的天数");
days=input.nextInt();
System.out.println("请选择租车类型:1-轿车;2-客车");
choice=input.nextInt();
switch (choice) {
case 1:
//轎車
System.out.println("请输入轿车的品牌:1-宝马;2-别克");
String brand=null;
String type=null;
String no="赣A123456";
String color="红色";
String mileage="2万公里";
choice=input.nextInt();
if (choice==1) {
brand="宝马";
System.out.println("请选择您的型号;1-550i");
choice=input.nextInt();
if (choice==1) {
type="550i";
}
}else if(choice==2){
brand="别克";
System.out.println("请选择您的型号:1-別克商務艙GL8;2-別克林蔭大道");
choice=input.nextInt();
if(choice==1) {
type="別克商务仓GL8";
}else if(choice==2) {
type="別克林阴大道";
}
}
//初始化小轎車
car=new Car(no, brand, color, mileage, type);
rent=car.calcRent(days);
System.out.println("分配給您的車牌號是"+no);
break;
case 2:
//客車
String brand2=null;//轎車品牌
int seatCount=0;//轎車的座位數
String no2="贛A123456";
String color2="紅色";
String mileage2="5萬公里";
System.out.print("請選擇客車的品牌;1-金杯;2-金龍");
choice=input.nextInt();
if(choice==1) {
brand="金杯";
}else if(choice==2) {
brand="金龍";
}
System.out.print("請輸入座位數目");
seatCount=input.nextInt();
bus=new Bus(no2, brand2, color2, mileage2, seatCount);
rent=bus.calcRent(days);
System.out.println("分配給您的車牌號是"+no2);
break;
default:
System.out.println("對不起,輸入錯誤");
break;
}
//結算 判斷租賃的車輛是轎車還是客車
System.out.println("租金為:"+rent);
}
}