面向对象编程

一级目录

二级目录

三级目录

封装

使用private将属性进行封装(这个属性只在当前类的内部可见,对外部隐藏)。
使用public作用在方法上,提供调用的入口。

封装有两大特性:保护性和易用性

保护性

创建一个Person类,假设他的money属性是public(公共的),那么所有的人类对象都可以调用,也就是说你的钱任何人都可以花,这合理吗?

public class Person {
    public String name;
    public double money ;
}
class person {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "xiaoming";
        person.money = 100;
        System.out.println("购买一瓶可乐");
        person.money -= 3;
        System.out.println(person.money);
    }
}

为了避免属性被外部随意修改和访问,需要使用private将属性进行封装。若需访问和修改成员属性需要使用内部的getter和setter方法进行访问和修改。

易用性

通过程序对外界提供的方法来操控属性,可以更加灵活和安全。
比如:

public class Person {
    public String name;
    private double money;

    public double setMoney(double money){
        return this.money = money;
    }
    public double getMoney(){
       return this.money;
    }
}
public class xiaoMing {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "xiaoming";
        person.setMoney(100);
        person.setMoney(person.getMoney() - 3);
        System.out.println("购买一瓶可乐还剩下" + person.getMoney());
    }
}

继承

面向对象编程最大的一个特点就是方法复用,假如有这样一组代码。

public class Animal {
    public String name;

    public void eat(String food){
        System.out.println(this.name + "正在吃" +food);
    }
}
public class Cat {
    public String name;

    public void eat(String food){
        System.out.println(this.name +"正在吃" +name);
    }
}
public class Dog {
    public String name;

    public void eat(String food){
        System.out.println(this.name +"正在吃" +food);
    }
}

这三个类代码完全一样

按道理来讲:
狗狗 是 动物
Dog is an Animal
猫 是 动物
Cat is an Animal
当类和类之间满足: 一个类 is a 另一个类 一定存在继承关系

当一个类继承了另一个类,另一个类中所有的属性和方法(包括静态属性和方法)子类就天然具备了

Java中使用extends表示类的继承

public class Dog extends Animal{
}
public class Cat extends Animal{
}

Dog(子类/派生类) extends Animal(父类/基类)

继承规则:
1.要能使用继承,必须满足is a关系
2.一个子类只能使用extends继承一个父类(单继承)
3.子类会继承父类的所有属性和方法,显示继承(public实行和方法可以直接使用),隐式继承(private属性和方法,子类其实也继承了这个方法但是无法直接使用)

protected访问权限

protected:当前类和其子类(不同包具有继承关系)内部可见

假设Animal是父类,其中的name属性是protected权限,person是Animal的子类,这时在test类(和Animal类没有继承关系)中创建一个person对象(Person per = new Person(); ),此时per这个对象无法使用那么这个属性,其原因就是per.name发生在test这个类中,protected权限只能在当前类和其子类中可见。

protected权限在同包中没有继承关系也可见

private < default < protected < public
既然default权限(包权限)小于protected权限,包权限可见的范围,protected一定包含。
所以protected权限:同包(不包含子包)下没有继承关系的类以及不同包下有继承关系的类之间都可见。

在这里插入图片描述
在这里插入图片描述
这里test和Anlmal在同一个包中

this关键字

表示当前对象的引用
修饰属性:表示直接从当前类中找同名属性
修饰方法:修饰构造方法、修饰普通方法,从当前类中 寻找
表示当前对象的引用

    protected String name;
    private int age;//隐式继承,子类没法直接使用该属性,必须通过父类提供的方法来操作

    public Animal(){}//Animal的无参构造
    public Animal(String name){
        this();//this关键字调用无参构造
        this.name = name;//this关键字调用类中同名属性
    }
    public Animal(String name,int age){
        this(name);//this关键字调用有参构造
        this.age = age;//this关键字调用类中同名属性
    }

super关键字

修饰属性:表示直接从父类寻找同名属性
修饰方法:表示直接从父类寻找方法

1.super修饰属性
当有继承关系时,访问成员变量默认为使用this关键字

public class China extends Person{
    public String name = "china";
    public void fun(){
        System.out.println(name);//默认为使用this
    }
}

在这里插入图片描述

要想访问父类属性得加上super

public class China extends Person{
    public String name = "china";
    public void fun(){
        System.out.println(super.name);
    }
}

在这里插入图片描述

super先从直接父类中寻找同名属性,若不存在再向上寻找
不能使用super直接调用父类private权限的属性
this直接从当前类中找同名属性,若不存在再向上搜索

2.修饰构造方法
当产生子类对象时,默认先产生父类对象,若父类对象还有继承,继续向上先产生父类对象。

super修饰构造方法:
1.super(父类构造方法的参数);
2.super();//直接父类的无参构造,可写可不写
3.若父类中不存在无参构造,则子类构造方法的首行必须显式使用suoer(有参构造)
4.在一个构造方法中无法显示使用this()和super()同时出现

3.super修饰普通方法
1.和修饰属性一样直接从父类寻找同名方法
在这里插入图片描述
2.super不能指代当前父类对象的引用
在这里插入图片描述

final关键字

修饰属性表示属性值不能变–常量
修饰类,表示这个类无法被继承
final class Person
------Person无法被继承

组合关系

类和类除了继承关系之外还有组合关系,如果说还有就是毫无关系。

组合关系: School这个类有学生、老师,但老师和学生与学校不是继承关系。
School has student
School has teacher
这就是组合关系

多态

多态:一个引用可以表现出多种行为/特性 =>多态性

向上转型

Dog dog = new Dog();//最常见的
类名称 类引用 = new 该对象();
Animal animal = new Dog();
父类对象 父类引用 = new 子类对象();
总结:向上转型发生在有继承关系的类之间

假设现在没有向上转型:

class test1{
    public static void main(String[] args) {
        fun(new Animal());
        fun(new Duck());
        fun(new Bird());
    }
    //假设没有向上转型,有多少个子类就得重载多少次fun方法
    public static void fun(Animal animal){}
    public static void fun(Duck duck){}
    public static void fun(Bird bird){}
}

有向上转型之后,最顶端的父类引用就可以指代所有的子类对象:
在这里插入图片描述
同一个引用(变量名称),同一个方法名称根据对象的不同表现出不同的行为—多态
在这里插入图片描述

fun中animal局部变量的引用调用eat方法时,当传入不同的对象时,表现出来了不同的eat方法行为,这就是多态性。

方法重写(override)

发生在有继承关系的类之间,子类定义了若干个和父类权限不同,其他完全相同的方法,这样的一组方法称之为方法重写。

比如:
在这里插入图片描述
在这里插入图片描述

方法重写:
看当前通过哪个类new的对象,若该类重写了相关方法,则调用的一定是重写后的方法。
若子类没有重写这个方法则调用父类的同名方法
当时发生重写时,子类权限必须大于等于父类权限(private < default < protected < public),但是不能是private权限。
方法重写只发生在普通方法中,静态方法也不行

在这里插入图片描述
假设Dog类中有一个扩展方法play(),这个方法Animal类不具备
在这里插入图片描述

类名称 引用名称 = new 类实例();
引用名称.方法名称();
能通过"."访问二点方法类名称说了算,能访问的这些方法必须都在类中定义过,编译器会先在类中查找是否包含指定方法。
至于这个方法到底表现出哪个类的样子,实例所在的方法说了算

向下转型

还是那个例子:假设Dog类中有一个扩展方法play(),这个方法Animal类不具备,但是此刻就像调用子类拓展的方法就必须还原为子类引用-----向下转型。

向下转型格式:
子类名称 子类引用 = (子类名称)父类引用;
Dog dog = (Dog)animal;
将父类引用强制转换为子类引用时:
子类 is a 父类 -----Dog is an animal
父类 is a 子类(不一定) — Animal is a Dog?
要发生向下转型,首先要发生向上转型。

在这里插入图片描述
当发生向下转型时会有风险----类型转换异常,可以使用instanceof关键字
引用名称 instanceof 类 ----返回布尔值,表示该引用指向的本质是不是该类的对象
在这里插入图片描述

小结:当方法接受一个类和当前类的子类,参数指定为相应的父类引用,发生的就是向上转型;当某个特殊的情况下,需要使用子类拓展方法,才需要将原本向上转型的引用向下转型还原为子类引用。

抽象类

若需要子类强制覆写方法,需要用到抽象类。
现实生活中有很多抽象类,这些类都是概念化的,没办法具体到某个实例来描述这一类对象共同的属性和行为。
比如说:人类–抽象类,因为没办法对应到具体某个或者某一类人

1.抽象类是普通类的“超集”,只比普通类多了一些抽象方法而已----普通类有的抽象类全有。
2.抽象方法所在的类必须是抽象类,子类(普通类)若继承了抽象类,必须覆写所有抽象方法。
3.Java中定义抽象类或者抽象方法使用abstract关键字。

1.抽象方法所在的类必须使用abstract声明为抽象类。

1.抽象方法指的是使用abstract关键字声明,只有函数声明,没有函数实现的方法,称为抽象方法。
2.Java中除了抽象方法没有方法体本地方法(不是抽象方法)也没有方法体。

public abstract class sharp {
    public abstract void print();//只有方法声明,没有具体实现--延迟到子类实现
}

2.若一个类使用abstract声明为抽象类,无法直接通过该类实例化对象,哪怕该类中一个抽象方法都没有
当一个类是抽象类,不管他有没有抽象方法,这个类本身就是一个抽象的概念,没办法具体到某个特定的实例。(只能通过子类向上转型变为父类的引用)
Person per = new Person();//error
Person per = new China();//ok

3.子类继承了抽象类,就必须强制子类覆写抽象类中的所有抽象方法(子类是普通类),也满足单继承局限,一个子类只能extends一个抽象类。
在这里插入图片描述
4.抽象类是普通类的超集(普通类有的内容,抽象类都有),只比普通类多了一些抽象方法而已,抽象类虽然没法直接实例化对象,但也是可以存在构造方法(子类在实例化时,仍然遵从继承的规则,先调用父类(抽象类)的构造方法,而后调用子类构造方法)

接口

1.接口中只有全局常量和抽象方法
2.接口使用关键字interface声明,子类使用implement实现接口

一般来说,接口的使用表示两种场景:

1.接口表示具备某种能力/行为,子类实现接口时不是is a,而是具备这种能力或行为
比如说:游泳(能力)----Person(满足游泳接口)
2.接口表示一种规范或者标准
比如:“USB接口”

使用interface声明USB接口

public interface USB {
    //插入
    public abstract void PlugIn();
    //工作
    public abstract void Work();
}

子类KeyBoard使用implements实现接口,必须覆写所有抽象方法

public class KeyBoard implements USB{

    @Override
    public void PlugIn() {
        System.out.println("安装驱动中");
    }

    @Override
    public void Work() {
        System.out.println("鼠标正常工作");
    }
}

对于电脑这个类来说,它是USB规范的使用者,不关心到底哪个具体设备插入到我的电脑上,这要这个设备满足了USB接口,都能被电脑识别。

public class computer {
    public static void main(String[] args) {
        computer computer = new computer();
        KeyBoard keyBoard = new KeyBoard();
        computer.fun(keyBoard);
    }
    public void fun(USB usb){
        usb.PlugIn();
        usb.Work();
    }
}

接口允许多实现,一个类可能具备多个能力,同时实现多个父类接口,若实现多个父接口,子类普通类,需要覆写所有的抽象方法
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值