一、使用继承的原因和作用:
1、 原因:父类拥有的是所有子类所共有的属性和方法,而子类除了继承了父类所有的属性和方法,还有一些特有的属性和方法,这些属性和方法是父类不能拥有的。父类和子类的关系就像一般与特殊的关系。
Eg:
| 类名 | 属性 | 方法 |
父类 | Student | Name,age | Study() |
子类 | UNStudent | Name,age | Study(),work() |
如上例,子类UNStudent(大学生)类除了可以拥有study()方法,还可有work()方法。
2、 作用:
1) 提高代码的重用性。
子类中不需要重新定义父类中的属性和方法,子类的对象也可以引用父类中的属性和方法。
2) 提高程序的扩展性。
根据继承的原因可知,子类可以拥有自己特有的属性的方法,这样,不同的子类就可以拥有不同的属性和方法,也就提高了程序的扩展性。
二、JAVA继承的语法格式:
子类继承的关键字是:extends
父类(基类)子类(超类)
格式:
public class 子类名 extends 父类名{
}
三、子类继承到父类的哪些属性和方法
1、 子类可以继承到父类所有的属性和方法,除了构造方法。
Eg:
//父类Student类
public class Student {
private String name;
//父类的构造参数
public Student(String name) {
this.name = name;
}
}
//子类UNStudent类
public class UNStudent extends Student{
//子类的构造函数
public UNStudent(String name) {
super(name);
}
}
如上例,子类并没有继承父类的构造函数,在子类里需要自己定义子类的构造函数。
2、访问修饰符(private,protected,默认的,public)决定了子类是否能使用父类中的属性和方法。
1) 子类和父类在同一个包下
只有父类中private属性和private方法不能被子类或子类的对象调用。
父类中protected,默认的,public方法都可以被子类或子类的对象调用。
2) 子类和父类不在同一个包下
父类中默认的和private属性和方法不能被子类或子类的对象调用。
父类中protected属性和方法能被子类调用,但不能被子类的对象调用。
父类中public属性和方法都可以被子类或子类的对象调用。
Eg:父类和子类在不同包内
package zr.study.test1;
public class Test {
public static void main(String[] args) {
UNStudent un=new UNStudent();
//un.name="张三";//name在父类中是私有的,不能被子类的对象调用
un.work();
//un.study();//父类和子类在不同的包,子类的对象不能调用父类中默认的方法
}
}
package zr.study.test2;
//父类Student类
public class Student {
private String name;
protected String getName() {//getName()方法是受保护的,父类和子类在不同的包,getName()只能被子类调用
return name;
}
protected void setName(String name) {//setName()方法是受保护的,父类和子类在不同的包,setName()只能被子类调用
this.name = name;
}
void study(){//study()方法为默认的,父类和子类在不同的包,study()不能被子类和子类的对象调用
name="张三";
System.out.println("名字为:"+name);//name属性为私有的,只能在该类(父类)中被使用
}
}
package zr.study.test1;
import zr.study.test2.Student;
//子类UNStudent类
public class UNStudent extends Student{
//子类的构造函数
public void work(){
//name="张三";//name在父类中是私有的属性,不能被子类调用
setName("张三");//可以通过可以访问的方法去给属性赋值
System.out.println("名字:"+getName());
//System.out.println("在子类中调用study()方法,结果为:");
//study();//父类和子类在不同的包,study()方法在父类中是默认的,不能被子类调用
}
}
四、 方法重写
1、 为什么要方法重写?
生活中的例子:
老师是一个类,都拥有教书的行为,但是不同专业的老师所教的课程是不一样的。这样就需要方法重写了
2、 方法重写的条件:
重写后的方法的方法名、返回值、参数类型、参数个数、参数顺序必须和父类的方法一致。
3、 子类方法重写的访问修饰符必须小于或等于父类方法的访问修饰符。
如果父类中的方法的访问修饰符为protected的,在子类进行方法重写时,访问修饰符可以是protected或public。
4、 如果实现了方法重写,那么子类的对象优先调用的是子类中的方法。
5、 子类可以定义自己的属性和方法。
Eg:
//定义了一个老师类Teacher
public class Teacher {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected void teach(){
name="张三";
System.out.println(name+"老师在上课!");
}
//定义一个子类英语老师类,EnglishTeacher
public class EnglishTeacher extends Teacher{
public void teach(){//重写了父类中的teach()方法
setName("张三");
System.out.println(getName()+"在上英语课!");
}
}
五、 对象的自动转型
1、实现对象的自动转型的条件:存在继承关系。
2、格式:
父类名对象名 = new 子类构造方法();
3、自动转型存在的问题,对象不能引用子类自己定义的方法。
Eg:
public class Test {
public static void main(String[] args) {
Teacher teacher = new EnglishTeacher();//自动转型
teacher.teach();
//teacher.speakTeach();//自动转型后,对象不能调用子类自己定义的方法
}
}
//定义了一个老师类Teacher
public class Teacher {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected void teach(){
name="张三";
System.out.println(name+"老师在上课!");
}
}
//定义一个子类英语老师类,EnglishTeacher
public class EnglishTeacher extends Teacher{
public void teach(){//重写了父类中的teach()方法
setName("张三");
System.out.println(getName()+"老师在上英语课!");
}
//子类中自己定义的一个方法
public void speakTeach(){
setName("李四");
System.out.println(getName()+"老师在上英语口语课!");
}
}
结果:张三老师在上英语课!
4、为什么自动转型后,对象不能调用子类定义的方法呢?
这个问题是JAVA的编译机制引起的问题。
自动转型后,teacher变量时一个Teacher类型的,teacher这个对象只能从Teacher类中去找它要调用的方法,因为speakTeacher()方法是在子类EnglishTeacehr中被定义的,teacher在Teacher类中找不到,所以对象不能调用子类定义的方法。
如果在子类中重写了父类中的方法,由于方法名和父类中的方法名一样,所以teacher对象可以在父类中找到这个方法名,又自动转型的对象根据是由EnglishTeacher类自动转型的,就可以自动在子类中找到重写的这个方法,所以根据优先原则,teacher对象调用的是子类中重写的方法。
5、自动转型的作用:提高代码的重用性。
通过自动转型,可以示例化不同子类的对象,自动转型后,这些对象都是父类类型的,这样,就可以把父类类型的一个变量作为参数,把不同子类的对象传给一个方法,从而避免了写多个不同参数类型(不同子类类型)的方法,提高了代码的重用性。
Eg:
例1:
//定义一个评价老师的方法
Public void evaluate(Teacher teacher){
System.out.println(teacher.getName()+”的分数为:”+teacher.getScore());
}
如果我们进行了自动转型:
Teacher teacher1=new EnglishTeacher();//实例化了一个英语老师类
Teacher teacher2=new ComlishTeacher();//实例化了一个计算机老师类
那么我们在调用evaluate()方法的时候可以这样传参:
evaluate(teacher1);//传入一个英语老师对象作为参数
或
evaluate(teacher2);//传入一个计算机老师对象作为参数
例二:
//定义一个评价英语老师的方法
Public void evaluate(EnglishTeacher engTeacher){
System.out.println(engTeacher.getName()+”的分数为:”+ engTeacher.getScore());
}
//定义一个评价计算机老师的方法
Public void evaluate(ComTeacher comTeacher){
System.out.println(comTeacher.getName()+”的分数为:”+ comTeacher.getScore());
}
如果有100种专业类型的老师,那就得写100个evaluate()方法(每个方法的参数类型不同)。
比较例一和例二,当然例一更节省代码!
六、 多态
多态是JAVA的方法重载、继承、方法重写、自动转型等技术的组合。多态方法调用允许一种类型表现出与其他相似类型之间的区别,只要它们都是从同一父类导出来的。
Eg:
**战士和**Boss进行Pk,直到一方的血量为0时结束战斗,输出谁胜利了!
要求战士要可以和Boss或者其他的战士对象进行战斗。
要求Boss要可以和战士或者其他的Boss对象进行战斗。
public class Par {
private String name;
private int blood;
protected Skill [] array;
private int sum;
// public Par(){
//
// }
//
public Par(String name, int blood,Skill [] array) {
//super();
this.name = name;
this.blood = blood;
this.array=array;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getBlood() {
return blood;
}
public void setBlood(int blood) {
this.blood = blood;
}
public Skill[] getArray() {
return array;
}
public void setArray(Skill[] array) {
this.array = array;
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
}
public void fight(Par p){
}
}
public class Soldier extends Par {
public Soldier(String name, int blood, Skill[] array) {
super(name, blood, array);
// TODO Auto-generated constructor stub
}
public void fight(Par p){
Random rand=new Random();
Skill skill=array[rand.nextInt(array.length)];
p.setBlood(p.getBlood()-skill.getAgressivity());//与Boss类的不同之处
p.setSum(p.getSum()+skill.getScore());
System.out.println(getName()+"攻打"+p.getName()+","+p.getName()+"剩余血量为:"+p.getBlood()+"。"+getName()+"使用技能为:"+skill.getName()+","+getName()+"获得的分数为:"+skill.getScore());
}
}
public class Boss extends Par{
public Boss(String name, int blood, Skill[] array) {
super(name, blood, array);
// TODO Auto-generated constructor stub
}
public void fight(Par p){
Random rand=new Random();
Skill skill=array[rand.nextInt(array.length)];
p.setBlood(p.getBlood()-2); //与Soldier类的不同之处
p.setSum(p.getSum()+skill.getScore());
System.out.println(getName()+"攻打"+p.getName()+","+p.getName()+"剩余血量为:"+p.getBlood()+"。"+getName()+"使用技能为:"+skill.getName()+","+getName()+"获得的分数为:"+skill.getScore());
}
}
public class Skill {
private String name;
private int agressivity;
private int score;
public Skill(String name, int agressivity, int score) {
super();
this.name = name;
this.agressivity = agressivity;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAgressivity() {
return agressivity;
}
public void setAgressivity(int agressivity) {
this.agressivity = agressivity;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
public class Test {
public static void main(String[] args) {
Test t=new Test();
Skill [] skillArray={new Skill("X战火",5,50),new Skill("X战枪",10,100),new Skill("X战剑",8,80)};
Random rand=new Random();
Skill skill=skillArray[rand.nextInt(skillArray.length)];
Par [] array={new Boss("大魔王",6,skillArray),new Soldier("A战士",8,skillArray),new Boss("小怪兽",8,skillArray),new Soldier("B战士",10,skillArray)};
Par par1=array[rand.nextInt(array.length)];
Par par2=array[rand.nextInt(array.length)];
//System.out.println(!par1.equals(par2));
int value=rand.nextInt(2);
t.choose(value,par1,par2);
}
private void choose(int value,Par par1,Par par2) {
switch(value){
case 0:
if(!par1.equals(par2)){
while(par1.getBlood()>0&&par2.getBlood()>0){
par1.fight(par2);
if(par2.getBlood()<=0){
System.out.println(par1.getName()+"胜利!"+par1.getName()+"获得的总分数为:"+par1.getSum());
break;
}
par2.fight(par1);
if(par1.getBlood()<=0){
System.out.println(par2.getName()+"胜利!"+par2.getName()+"获得的总分数为:"+par2.getSum());
break;
}
}
}else{
System.out.println(par1.getName()+"不能和"+par2.getName()+"一起战斗!");
}
break;
case 1:
if(!par1.equals(par2)){
while(par1.getBlood()>0&&par2.getBlood()>0){
par2.fight(par1);
if(par1.getBlood()<=0){
System.out.println(par2.getName()+"胜利!"+par2.getName()+"获得的总分数为:"+par2.getSum());
break;
}
par1.fight(par2);
if(par2.getBlood()<=0){
System.out.println(par1.getName()+"胜利!"+par1.getName()+"获得的总分数为:"+par1.getSum());
break;
}
}
}else{
System.out.println(par2.getName()+"不能和"+par1.getName()+"一起战斗!");
}
break;
}
}
}