继承--为什么有?[Demo117.java]
//功能:说明继承的重要性
x
package com.abc;//包名
public class Demo117 {
public static void main(String[] args) {
Pupil p1=new Pupil();
p1.printName();
}
}
//将学生的共有属性提取,做一个父类
class Stu{
//定义成员属性
protected int age;
public String name;
public float fee;
private String job;//私有将不被继承
//编程中,如果你不希望子类继承某个属性或方法
//则将其声明为private即可
public void printName(){
System.out.println("名字"+this.name);
}
}
//小学生类
class Pupil extends Stu{
//交学费
public void pay(float fee){
this.fee=fee;
}
}
//幼儿
class Pre extends Pupil{
//交学费
public void pay(float fee){
this.fee=fee*1.5f;
}
}
//中学生类
class MiddleStu extends Stu{
//交学费
public void pay(float fee){
this.fee=fee*0.8f;
}
}
//大学生类
class ColStu extends Stu{
//交学费
public void pay(float fee){
this.fee=fee*0.1f;
}
}
继承--解决之道
继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(比如刚才的Student),在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends语句来声明继承父类:
语法:class 子类 extends 父类
这样,子类就会自动拥有父类定义的某些属性和方法。
继承--深入讨论
1、父类的哪些属性(变量)、方法被子类继承了?并不是父类的所有属性、方法都可以被子类继承
父类 子类
public 属性; public 属性;
protected 属性; 继承 protected 属性;
private 属性; → 属性;
属性;
public 方法; public 方法;
protected 方法; protected 方法;
private 方法; 方法;
方法;
2、结论
从图可以看出,父类的public修饰符的属性和方法;protected修饰符的属性和方法;默认修饰符属性和方法被子类继承了,父类的private修饰符的属性和方法不能被子类继承。
继承--注意事项
1、子类最多只能继承一个父类(指直接继承)
2、java所有类都是Object类的子类 (所有的子类都可以逐级继承,例:爷->父->子->孙)
3、JDK6中有202个包3777个类、接口、异常、枚举、注释和错误
4、在做开发的时候,强烈建议大家多查jdk帮助文档
5、在使用类时,实在不知道怎么办,多使用搜索引擎
定义类的改进
在提出包后,我们类的定义就更加完善了:
class 类名{ class 类名{ class类名{ package包名;
成员变量; → 成员变量; → 成员变量; → class 类名{
} 成员方法; 构造方法; 成员变量;
} 成员方法; 构造方法;
} 成员方法;
} ↓
↓←←←←←←←←←←←←←←←←←←←←←←←←←
package 包名;
class 类名 extends 父类{ 待定
成员变量; → ....
构造方法;
成员方法;
}
-------------------------------------------------------------------------------
java面向对象编程(2)--方法重载(overload)
方法重载(overload)
按顺序,我们应该讲解多态,但是在讲解多态前,我们必须讲解方法重载和方法覆盖(override)。
请编写一个类(Abc),编写方法可以接收两个整数,返回两个数中较大的数[Demo119.java]
x
//方法重载(overload)getMax
public class Demo119{
public static void main(String []args){
Abc2 abc1=new Abc2();
System.out.println(abc1.getMax(12,14));
System.out.println(abc1.getMax(24f,20f));
}
}
class Abc2{
//返回较大的整数
public int getMax(int i,int j){
if(i>j){
return i;
}else{
return j;
}
}
public float getMax(float a,float b){
if(a>b){
return a;
}else{
return b;
}
}
//如果只是返回类型不一样,能否构成重载?不能够构成重载
/* public double getMax(float d,double c){
if(c>d){
return c;
}else{
return d;
}
}
//如果只是控制访问修饰符不同,能否构成重载?不能够构成重载
protected float getMax(float c,float d){
if(c>d){
return c;
}else{
return d;
}
}*/
}
方法重载(overload)概念
简单的说:方法重载就是在类的同一种功能的多种实现方式,到底采用哪种方式,取决于调用者给出的参数。
注意事项:
1、方法名相同
2、方法的参数类型,个数,顺序至少有一项不同
3、方法返回类型可以不同(只是返回类型不一样,不能构成重载)
4、方法的修饰符可以不同(只是控制访问修饰符不同,不能构成重载)
方法覆盖(override)
既然子类可以继承父类的属性和方法,这样可以提高代码的复用性,这个很好,可是问题来了,假设现在我要求大家写三个类猫猫,狗狗,猪猪。我们知道这三个东东都是动物,动物必然存在相同的特点。根据类的抽象特征,我们可以把它们的相同点提取出来,形成一个父类,然后继承。
x
//子类方法覆盖父类方法[Demo120.java]
public class Demo120{
public static void main(String []args){
//创建一只猫
Cat cat1=new Cat();
cat1.cry();
Dog dog1=new Dog();
dog1.cry();
}
}
//动物类
class Animal{
int age;
String name;
//都会叫
public void cry(){
System.out.println("我是动物,不知道怎么叫");
}
}
//猫猫类
class Cat extends Animal{
//覆盖父类方法
public void cry(){
System.out.println("猫猫叫!");
}
}
//狗狗类
class Dog extends Animal{
//覆盖父类方法
public void cry(){
System.out.println("汪汪叫!");
}
}
方法覆盖(override)概念
简单的说:方法覆盖就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法。比如上个案例的Cat类中的cry方法就覆盖了Animal类的cry方法。
注意事项:
方法覆盖有很多条件,有些书上说的比较细,总的讲有两点一定注意:
1、子类的方法的返回类型,参数,方法名称,要和父类的返回类型,参数,方法名称完全一样,否则编译出错。
2、子类方法不能缩小父类方法的访问权限。
===============================================================================
作业:上机实习题目
1、Josephu问题(丢手帕问题)
Josephu问题为:设编号为1,2,...n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
提示:用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点的人从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
//Josephu问题(丢手帕问题)
//使用单向链表
public class Demo121 {
public static void main(String[] args) {
CycLink cyclink=new CycLink();
cyclink.setLen(5);//链表长度
cyclink.createLink();
cyclink.setK(2);//从第几个人开始数
cyclink.setM(2);//数几下
cyclink.show();
cyclink.play();
}
}
class Child{
int no;
Child nextChild=null;
public Child(int no){
//给一个编号
this.no=no;
}
}
//单向环形链表
class CycLink{
//先定义一个指向链表第一个小孩的引用
//指向第一个小孩的引用,不能动
Child firstChild=null;
Child temp=null;
int len=0;//表示共有多少个小孩
int k=0;
int m=0;
//设置m数几下
public void setM(int m){
this.m=m;
}
//设置环形链表大小
public void setLen(int len){
this.len=len;
}
//设置从第几个人开始数数
public void setK(int k){
this.k=k;
}
//开始play
public void play(){
Child temp=this.firstChild;
//1.先找到开始数数的人
for(int i=1;i<k;i++){
temp=temp.nextChild;
}
while(this.len!=1){
//2.数m下
for(int j=1;j<m;j++){
temp=temp.nextChild;
}
//找到要出圈的前一个小孩
Child temp2=temp;
while(temp2.nextChild!=temp){
temp2=temp2.nextChild;
}
//3.将数到m的小孩,退出圈
temp2.nextChild=temp.nextChild;
//让temp指向下一个数数的小孩
temp=temp.nextChild;
this.len--;
}
//最后一个小孩
System.out.println("最后出圈的小孩:"+temp.no);
}
//初始化单向环形链表
public void createLink(){
for(int i=1;i<=len;i++){
if(i==1){
//创建第一个小孩
Child ch=new Child(i);
this.firstChild=ch;
this.temp=ch;
}else{
//创建最后一个小孩
if(i==len){
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
temp.nextChild=this.firstChild;
}else{
//继续创建小孩
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
}
}
}
}
//打印该环形链表
public void show(){
//定义一个跑龙套
Child temp=this.firstChild;
do{
System.out.print(temp.no+" ");
temp=temp.nextChild;
}while(temp!=this.firstChild);
}
}