面向对象(2)

1.面向对象的三大特性:封装、继承、多态。
一、封装
1.封装的学习就是学习类成员的访问权限的控制。是设计类的时候需要考虑的问题。
概念:通过对类中的成员的访问权限的控制,实现对外部类的访问的可见和隐藏的控制的过程。
2.类成员的访问权限的控制,通过访问权限修饰符来控制。可以在类成员的前面添加访问权限修饰符来实现对类成员访问权限的控制。
3.类成员的访问权限一共有四种:

  • public :本类、本包其他类、跨包其他类。被访问的权限最大的,工程级别的。
  • protected:本类、本包其他类,跨包的子类。
  • 默认的 default:本类、本包其他类。 包私有权限。
  • private:只能本类访问
    4.设计类的时候需要遵守的一些基本规范:
  • 所有的类成员的访问权限越小越好。
  • 所有的类的成员变量全部私有化。如果还希望其他的类来访问属性,那么对外提供修改器和访问器。getter and setter。
  • 如果一个类中包含了final static 修饰的,因为只有访问权,没有修改权,通常可以是public 修饰的。
  • 对于工具类来说,构造方法私有化,可以避免创建工具类的对象。
    5.关于类的访问权限修饰符只有两个:
  • public 该类可以被本工程的所有的其他的类访问。
  • 默认的,什么都不写。只能本包的其他的类访问。
    二、继承
    1.继承的语法相关的概念
    被继承的类:父类、基类、超类 比如 Person类
    继承的类:子类、派生类、衍生类。
    继承的概念:可以在子类中直接访问使用父类的成员的过程。
    继承的语法: class 子类类名 extends 父类类名{ 子类 类体 }
    说明:被子类继承的父类的成员,可以看做是子类的成员一样,可以直接使用。
    2.父类中的哪些成员可以被子类继承?
  • private 修饰的 不能被子类继承。
  • 默认的权限的成员 如果子类父类在同一个包下,那么可以被继承。跨包不可以。
  • Protected 修饰的。肯定可以被子类继承的。
  • Public 修饰的 ,可以被子类继承。
  • 构造方法不能被子类继承。
  • 静态成员 如果访问权限够,就可以被子类继承。
    3.创建子类对象的过程:
  • 类加载:按照当前类的继承体系,从上到下依次加载,先加载最上层的父类,依次向下。每加载一个类,就要对类中的静态成员分配内存初始化,执行静态代码块。
  • 按照类的继承体系,从上到下,先对最上层的父类的实例成员变量分配内存,初始化,执行构造块,执行构造方法。
  • 上述给实例成员变量的内存的分配,有几个继承的环节,那么就从上到下执行几次。先给最上层的分配,执行,然后是它的子类,以此类推,直到给最底层的子类分配,执行构造方法。
  • 当最底层的子类的构造方法执行完毕之后,子类对象才真正的创建完毕。
    4.结论:子类对象中包含了所有的直接的或者间接的父类的实例成员变量的内存空间,包含父类私有的属性。父类私有的属性不能被子类继承,但是被子类对象拥有。
/**
 *测试继承
 */
public class TestFatherAndSon {
    public static void main(String[] args) {
        Son son=new Son();
        System.out.println();
        Son son1=new Son();
    }
}
class GrandFather{
    static{
        System.out.println("static GrandFather");
    }
    {
        System.out.println("constructor block GrandFather");
    }
    GrandFather(){
        System.out.println("constructor GrandFather");
    }
}
class Father extends GrandFather{
    static{
        System.out.println("static Father");
    }
    {
        System.out.println("constructor block Father");
    }
    Father(){
        System.out.println("constructor Father");
    }
}
class Son extends Father{
    static{
        System.out.println("static son");
    }
    {
        System.out.println("constructor block son");
    }
    Son(){
        System.out.println("constructor son");
    }
}

执行结果:
static GrandFather
static Father
static son
constructor block GrandFather
constructor GrandFather
constructor block Father
constructor Father
constructor block son
constructor son

constructor block GrandFather
constructor GrandFather
constructor block Father
constructor Father
constructor block son
constructor son

Process finished with exit code 0

5.方法重写(override):当子类觉得父类中的方法不能满足自身的需求的时候,在子类中对父类的方法重新定义的过程。就称为重写(覆盖)。重写并没有真的把父类中的原有的方法覆盖掉,而是在子类中多了一个同名的方法。
6.重写的前提条件:必须有继承,是发生在子类父类之间的。
7.重写需要注意的问题:

  • 方法的权限:子类中重写的方法的权限必须大于等于父类中被重写的方法的权限。
  • 方法的返回类型:如果返回类型是基本数据类型,那么必须一致。如果是引用数据类型,那么子类中重写的方法返回的类型可以是父类中的方法返回类型的子类型。
  • 方法名字:必须一致。
  • 方法的参数:必须相同,不同就是重载。
  • 方法可能抛出的异常的类型:子类重写的方法抛出的异常的类型必须小于等于父类的。
  • 方法体:不相等。
/**
 * 重写toString()方法和equals()方法
 */
public class TestEquals {
    public static void main(String[] args) {
        Student student1=new Student("学生1",10,90);
        Student student3=student1;
        Student student2=new Student("学生2",10,90);
        Student student4=new Student("学生3",10,90);
        System.out.println(student1==student3);
        System.out.println(student1.equals(student2));
        System.out.println(student1.equals(student4));
        System.out.println(student1.equals(null));
        System.out.println(student1.equals("123"));
    }
}
class Student{
    private String name;
    private int age;
    private int score;
    //构造方法
    public Student(String name,int age,int score){
        this.name=name;
        this.age=age;
        this.score=score;
    }
    //访问器和修改器
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //访问器和修改器
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    //访问器和修改器
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
    //重写toString()方法
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
    //重写equals()方法
    public boolean equals(Object o){
        //o和当前对象是同一个对象
        if(o==this) return true;
        //o是null
        if(o==null) return false;
        //o不是student
        if(!(o instanceof Student)) return false;
        //一般情况进行判断
        //把o转换为Student类型才能访问
        Student s=(Student)o;
        if(this.age!=s.age) return false;
        if(this.score!=s.score) return false;
        if(!name.equals(s.name)) return false;
        return true;
    }
}

8.super 的用法:

  • 在子类的任意的构造方法内的第一句都必须显式的或者隐式的调用父类的构造方法。使用super 调用父类的构造方法。子类构造方法的第一句如果是隐式调用,那么只能调用父类中默认无参的构造方法。如果父类中不存在默认无参的构造方法,那么必须在子类的构造方法中显式的使用super 调用父类的构造方法。
  • 可以在子类中使用super 访问父类中定义的被子类隐藏的成员。
/**
 *测试super
 * super的两种用法:1.在子类的任意构造方法内打一句必须隐式或者显式的调用父类的构造方法
 * 2.在子类中,可以通过super方法调用父类中定义的被子类隐藏的成员
 */
public class TestSuper {
    public static void main(String[] args) {
        Doctor doctor=new Doctor();
        doctor.show();
    }
}
//创建people类
class People{
    private String name;
    private int age;
    /*
    public People(){
        System.out.println("constructor people");
    }
    */
    public People(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("constructor people"+name);//不需要用对象调用就执行了,再给对象进行初始化的时候执行
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    void work(){
        System.out.println("人们都需要工作来满足生活");
    }
}
//创建doctor类
class Doctor extends People{
    private int age;
    public Doctor(){
        this("医生2",100);

    }
    public Doctor(String name,int age){
        super(name,age);
        System.out.println("constructor Doctor");
    }
    void work(){
        System.out.println("白衣天使救死扶伤");
    }
    void show(){
        //打印子类的年龄
        System.out.println(age);
        //打印父类的年龄
        System.out.println(super.getAge());
        //获取父类的年龄,并赋值给age
        int age=getAge();
        //将age 的值进行运算
        age+=5;
        //设置父类的年龄
        super.setAge(age);
        //验证设置的父类的年龄值对子类有没有影响
        System.out.println(age);
        //验证设置的父类的年龄值对父类的年龄有没有影响
        System.out.println(super.getAge());
        //调用子类的额Work方法
        work();
        //利用super调用父类的Work方法
        super.work();

    }
}

三.多态
1.概念:多态是一种能力,是一种父类引用可以指向子类对象,并且在运行期对象根据自身的实际类型调用实际类型的方法的能力。
2.多态的三个必要条件:继承、父类引用指向子类对象、子类重写父类方法

/**
 * 人演奏乐器:大鼓、钢琴、小号
 */
public class TestInstruments {
    public static void main(String[] args) {
        /*
        Instruments piano=new Piano("钢琴");
        piano.sound();
        Instruments Bigdrum=new Bigdrum("大鼓");
        Bigdrum.sound();
        Instruments trumpet=new Trumpet("小号");
        trumpet.sound();
        */
        Person person=new Person();
        person.play(new Piano("钢琴"));
        person.play(new Bigdrum("大鼓"));
        //用类名直接访问静态方法
        person.play(MyFactory.creatInstruments("Piano"));

    }
}
//创建乐器类
class Instruments{
    private String name;
    Instruments(){}
    Instruments(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
    public void setName(){
        this.name=name;
    }
    void sound(){
        System.out.println("音乐");
    }
}
//创建钢琴类
class Piano extends Instruments{
    Piano(String name){
        super(name);
    }
    void sound(){
        System.out.println("弹奏钢琴的声音很美");
    }
}
//创建大鼓类
class Bigdrum extends Instruments{
    Bigdrum(String name){
        super(name);
    }
    void sound(){
        System.out.println("敲大鼓的声音当当当");
    }
}
//创建小号类
class Trumpet extends Instruments{
    Trumpet(String name){
        super(name);
    }
    void sound(){
        System.out.println("小号的声音嗡嗡嗡");
    }
}
//创建演奏的人类
class Person{
    void play(Instruments instruments){
        instruments.sound();
    }
}
//简单工厂模式
class MyFactory{
    //定义一个方法用于创建不同乐器的对象
    //根据传入不同类的名字,创建不同类的对象
    //父类类型作为方法的返回类型,返回的还具体的子类对象
    public static Instruments creatInstruments(String className){
        Instruments instruments=null;
        switch(className){
            case "Piano":
               instruments=new Piano("钢琴2");
               break;
            case "Bigdrum":
               instruments=new Bigdrum("大鼓2");
               break;
            case "Trumpet":
                instruments=new Trumpet("小号2");
                break;
        }
        return instruments;
    }
}

3.多态的转型

  • 父类引用指向子类对象:自动向上类型转换,子类对象当做父类类型来使用,小类型的对象当做大类型来使用。父类中包含的功能子类一定也包含,子类对象的功能要大于等于父类的。
  • 强制向下类型转换:需要使用子类特有的功能的时候,才有必要将父类引用转换为子类对象。如果想保证向下强制转换成功,那么被转换的对象的实际类型必须是要转换的类型才可以。不然会报下面的错误。类型转换异常。
/**
 * 测试类型转换
 */
public class TestClassCast {
    public static void main(String[] args) {
        Animal animal=new Animal();
        animal.sound();
        Dog dog=new Dog();
        dog.sound();
        //自动类型转换
        Animal dog2=new Dog();
        dog2.sound();
        //强制类型转换
        Dog dog3=(Dog)dog2;
        dog3.seeDoor();
        ((Dog)dog2).seeDoor();
    }
}
//
class Animal{
    public void sound(){
        System.out.println("所有的动物都会叫");
    }
}
class Dog extends Animal{
    public void sound(){
        System.out.println("汪汪汪~~~");
    }
    public void seeDoor(){
        System.out.println("狗狗会看门");
    }
}
class Cat extends Animal{
    public void sound(){
        System.out.println("喵喵喵~~~");
    }
}

四.抽象类和抽象方法
1.抽象类的概念:被abstract关键字修饰的类就是抽象类。
2.抽象类出现的意义:

  • 如果一个类不希望被实例化,比希望创建该类的对象,就可以声明成抽象的。抽象类是不允许实例化的。
  • 如果设计类的时候,希望该类只能作为父类出现,那么声明成抽象类,抽象类不能被实例化,如果使用抽象类,只能作为继承体系的上层类使用。
    3.抽象类的特点:不能被实例化,只能作为父类使用别子类继承。
    4.抽象方法的概念:被abstract修饰的方法 称为抽象方法。
    5.抽象方法出现的意义:如果一个方法不希望被对象使用,只作为被实现(重写)的父类中的方法,为了实现多态而存在的,那么就需要声明成抽象的。
    6.抽象方法的特点:没有方法体,不能被调用,只能被子类实现。
/**
 *测试abstract
 */
public class TestAbstract {
    public static void main(String[] args) {
        Animal dog=new Dog();
        dog.eat();
        dog.sleep();
        Animal cat=new Cat();
        cat.eat();
    }
}
abstract class Animal{
    abstract void eat();
    //父类中有一个静态方法,可以被继承,但是不能重写
    static void sleep(){
        System.out.println("啥动物都得睡觉");
    }
}
//创建Dog类
class Dog extends Animal{
    void eat(){
        System.out.println("狗狗爱吃骨头");
    }
}
class Cat extends Animal{
    void eat(){
        System.out.println("猫咪爱吃鱼");
    }
}

今日练习:

使用面向对象的思想实现:
玩家和电脑游戏比赛,比赛内容。石头剪刀布的比赛。三局两胜。输出整个比赛的每个回合的过程,并输出最后的结果。要求有接口的使用。(参考答案见本博客项目)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值