Java 面向对象 day4

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;
	}

	@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);
		}
	}
}

测试类

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值