JAVA学习——Java中面向对象的三大特征

 

目录

一、封装性

二、继承性

2.1 继承中的注意事项

2.2 继承设计原则

2.3 继承使用详解

2.3.1 子类访问成员变量和方法

2.3.2 super关键字

2.3.3 this关键字

2.3.4 方法重写

三、多态性

3.1 接口

3.1.2  常量

3.1.2 抽象方法

3.1.3 默认方法

3.1.4 静态方法

3.1.5 私有方法

3.1.6 接口实现步骤

3.1.7 类和接口之间关系:

3.2 多态性

3.2.1 多态的优点:

3.2.2 多态存在的三个必要条件

3.2.3. Java中多态实现

3.2.4 多态的使用规则

3.2.5 向上转型和向下转型:


一、封装性

封装性在Java当中的体现:
1. 方法就是一种封装
2. 关键字private也是一种封装(私有化,类似于)

使用private方法的时候,被封装后的成员变量不能直接访问,需要定义一对Getter/Setter方法,(必须叫setXxx或者getXxx命名规则)。代码如下:

public class Person {
    String name;
    private int age;

    public void show() {
        System.out.println("姓名:" + name + "年龄:" + age);
    }

    // 这个成员方法,专门用于向age设置数据
    public void setAge(int num){
        if (num < 150 && num>0){
            age = num;
        }else {
            System.out.println("格式输入不对!");
        }
    }

    // 这个成员方法,专门用于获取age的数据
    public int getAge() {
        return age;
    }
}

当然,在本类中通过this关键字可以访问到本类私有化的成员变量,格式为this.成员变量(类似python中的self),当需要调用成员变量的时候,都推荐使用this.成员变量,可以将成员变量和方法变量区分开来。面向对象的思想包括高内聚低耦合,良好的封装能够减少程序的耦合度,保证属性的操作安全性。

二、继承性

继承的概念:多个类中存在相同的属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只需要继承那个类即可。

这个单独的类被称为父类,也可以叫做超类,基类等。从这个类继承的类可以称为子类。子类拥有父类的所有属性与方法,无需重新定义。并且可以直接使用非私有的父类成员,同时子类还可以定义自己的属性和方法。在继承中,可以有多个继承关系,“子类就是一个父类”。也就是说,子类可以被当作父类看待,子类有父类的特征。

在java中通过extends关键字让类与类之间产生继承关系。定义一个继承关系的类为:

首先创建父类:

定义父类的格式:(一个普通的类定义)

public class 父类名称{
    //...
}

然后创建子类继承父类:

定义子类的格式:

public class 子类名称 extends 父类名称{
    //...
}

2.1 继承中的注意事项

  1. Java只支持单继承,不支持多继承。即只能有一个父类。
  2. 子类可以被当作父类看待,子类有父类的特征
  3. 所有类均有父类,只有Object类没有父类。Object为最高类

2.2 继承设计原则

对于已经投入使用的类,尽量不要进行修改。推荐定义一个新的类,来重复利用其中共性内容,并且添加改动新内容。

2.3 继承使用详解

2.3.1 子类访问成员变量和方法

局部变量:直接写成员变量名
本类的成员变量:this.成员变量名
父类的成员变量名:super.成员变量名

父类:

public class Fu(){

    Stirng name;

    int age;


    public void printFu(){

        System.ou.println(“父类方法”)

    }

}

子类:

public class Zi extends Fu(){

    Stirng sex;

    int id;


    public void printZi(int num){ // num为局部变量

        this.id += num; // 调用本类的成员变量

        System.ou.println(this.id)

        System.ou.println(super.name) //调用父类的成员变量

    }

}

2.3.2 super关键字

继承关系中,父子类构造方法的调用特点:
1. 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
2. 子类构造可以通过super关键字来调用父类重载构造。
3. super的父类构造调用,必须是子类构造方法的第一个语句,不能一个子类构造调用多次super构造
总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。

父类:

public class Fu {
    private int num = 10;
    private String sex;

    public Fu() {
        System.out.println ("父类无参构造方法");
    }

    public Fu(String sex) {
        this.sex = sex; // 把局部变量赋值给成员变量
        System.out.println ("我是" + sex);
    }

}

子类:

public class Zi extends Fu{
    int num = 20;

    public Zi(){
        super(); // 调用父类的无参构造方法
        System.out.println ("子类构造方法");
    }

    public Zi(String sex){
        super(sex); // 调用父类的有参构造方法

    }

2.3.3 this关键字

super 关键字用来访问父类内容,而this关键字用来访问本类内容。用法也有三种;
1. 在本类的成员方法中,访问本类的成员变量。
2. 在本类的成员方法中,访问本类的另一个成员方法。
3. 在本类的构造方法中,访问另一个构造方法(访问的本类独有的构造方法)。
在第3种用法当中要注意:
this(...)调用也必须是构造方法的第一个语句。

public class Zi extends Fu{
    int num = 20;

    public Zi(){
        super();
    }

    public Zi(int num){
        this();
    }

    public Zi(int num, int num2){
        this(1000);
    }
}

2.3.4 方法重写

1. 重写(override)
概念:发生在继承关系当中,方法的名称一样,参数列表也一样。
2. 重写和重载的区别
重写(override):方法的名称一样,参数列表也一样。
重载(overload):方法的名称一样,参数列表不一样。
3. 方法的覆盖重写特点:创建的是子类对象,则优先使用子类方法。

4. 方法覆盖重写的注意事项:
 1) 必须保证父子类之间方法的名称相同,参数列表也相同。
@override:写在方法前面,用来检测是不是有效的正确覆盖重写。
这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。

2) 子类方法的返回值必须【小于等于】父类方法的返回值范围
小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。

3) 子类方法的权限必须【大于等于】父类方法的权限修饰符/
小扩展提示:public > protected > (default) > private
备注:(default)不是关键字default,而是什么都不写,留空

三、多态性

3.1 接口

在学习多态性之前,需要先了解什么是接口。

接口就是一种公共的规范标准,只要符合规范标准,就可以通用。接口是一种引用数据类型,最重要的内容就是其中的:抽象方法。

如何定义一个接口的格式:

public interface 接口名称 {
    // 接口名称
}

备注:换成了关键字interface之后,编译生成的字节码文件仍然是:.java --> .class

如果是java 7,那么接口中可以包含的内容有:

3.1.2  常量

 成员变量其实是常量,格式:

public static final 数据类型 常量名称 = 数据值;

注意:

  1. 常量必须进行赋值,而且一旦复制不能改变,因为使用了final关键字
  2. 常量名称完全大写,用下划线进行分隔。
  3. 接口当中的常量,可以省略public static final,注意:不写也照样是这样。
  4. 接口当中的常量,必须进行赋值,不能不赋值。
  5. 接口当中的常量的名称,使用完全大写的字母,用下划线进行分割

示例代码:

public interface MyInterfaceConstant {

    public static final int NUM_OF_MY_CLASS = 77;

}

3.1.2 抽象方法

示例代码:

public interface MyInterfaceAbstract {

    // 这是一个抽象方法
    public abstract void methodAbs1();

    // 这是一个抽象方法
    public  void methodAbs2();

}

如果是java 8,可以额外包含有:

3.1.3 默认方法

1. 格式:

public default 返回值类型 方法名称(参数列表) {
    方法体
}

2. 备注:接口当中的默认方法,可以解决接口升级的问题。

示例代码:

public interface MyInterfaceDefault {

    // 抽象方法
    public abstract void methodAbs1();

    // 添加一个默认方法
    public default void methodDefault(){
        System.out.println ("新添加的默认方法");
    }
}

实现类可以重写默认方法,也可以不重写,都可以调用默认方法

3.1.4 静态方法

1. 格式:

public static 返回值类型 方法名称(参数列表){
    方法体
}

3. 提示:就是将abstract或者default换成static即可,带上方法体

4. 注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。

5. 正确用法:通过接口名称,直接调用其中的静态方法。

格式:接口名称.静态方法名(参数)

示例代码:

public interface MyInterfaceStatic {
    public static void methodStatic(){
        System.out.println ("接口静态方法!");
    }
}

如果是java 9,还可以额外包含有:

3.1.5 私有方法

1. 普通私有方法,解决多个默认方法之间重复代码问题

格式:

private 返回值类型 方法名称(参数列表){
    方法体
}

示例代码:

public interface MyInterfacePrivateDefault {

    public default void methodDefault1(){
        System.out.println ("默认方法1");
        methodCommon ();
    }

    public default void methodDefault2(){
        System.out.println ("默认方法2");
        methodCommon ();
    }

    private void methodCommon(){
        System.out.println ("AAA");
        System.out.println ("BBB");
        System.out.println ("CCC");
    }
}

2. 静态私有方法,解决多个静态方法之间重复代码问题

格式:

private static 返回值类型 方法名称(参数列表){
    方法体
}

示例代码:

public interface MyInterfacePrivateStatic {

    public static void methodStatic1(){
        System.out.println ("静态方法1");
        methodStaticCommon ();
    }

    public static void methodStatic2(){
        System.out.println ("静态方法2");
        methodStaticCommon ();
    }

    private static void methodStaticCommon(){
        System.out.println ("AAA");
        System.out.println ("BBB");
        System.out.println ("CCC");
    }
}

3.1.6 接口实现步骤

1. 接口不能直接使用,必须有一个“实现类”,来“实现”接口

格式:

public class 实现类名称 implements 接口名称 {
    // ...
}

2. 接口的实现类必须覆盖重写(实现接口中所有的抽象方法)。

实现:去掉abstract关键字,加上方法体大括号

3.创建实现类的对象,进行使用

注意事项:

如果实现类没有覆盖重写接口中的所有抽象方法,那么这个实现类自己就必须是抽象类

4. 使用接口的时候需要注意:

  • 接口是没有静态代码块和构造方法的;
  • 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。

格式:

public class MyInterfaceImpl implements MyInterfaceA,MyInterfaceB {
    // 覆盖重写所有抽象方法
}
  • 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
  • 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
  • 如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
  • 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先使用父类当中的方法。
  •  

3.1.7 类和接口之间关系:

1. 类与类之间是单继承的,直接父类只有一个。

2. 类与接口是多实现的,一个类可以实现多个接口。

3. 接口与接口之间是多继承的。

 

注意事项:

1. 多个父接口当中的抽象方法如果重复,没有关系。

2. 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,【而且带着default关键字】

 

3.2 多态性

多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:

 

3.2.1 多态的优点:

1. 消除类型之间的耦合关系

2. 可替换性

3. 可扩充性

4. 接口性

5. 灵活性

6. 简化性

3.2.2 多态存在的三个必要条件

1. 继承

2. 重写

3. 父类引用指向子类对象

 

java中实现多态性:

extends和implements就是多态性的前提。

3.2.3. Java中多态实现

代码当中实现多态性,其实就是一句话:父类引用指向子类对象。

格式:

父类名称 对象名 = new 子类名称();

或者:

接口名称 对象名 = new 实现类名称();

已图中为例,示例代码如下:

首先定义一个电脑接口:

public interface Computer {

    void playGame(); // 定义玩游戏的抽象方法,public abstract可以省略不写
}

然后定义一个笔记本电脑的实现类:

public class Laptop implements Computer {
    @Override
    public void playGame() {
        System.out.println ("笔记本玩游戏方便");
    }

    public void myLaptop() {
        System.out.println ("笔记本携带方便");
    }
}

台式电脑的抽象方法:

public class Desktop implements Computer{

    @Override
    public void playGame() {
        System.out.println ("台式电脑玩游戏舒服");
    }

    public void myDesktop(){
        System.out.println ("台式携带太麻烦啦");
    }
}

3.2.4 多态的使用规则

在多态的代码当中,成员方法的访问规则是:

看new的是谁,就优先用谁,没有则向上找。

成员变量:编译看左边,运行还看左边

成员方法:编译看左边,运行看右边,在调用方法的时候,如果子类重写了父类的成员方法,

那么会优先使用子类重写的方法,但是不能直接调用子类中特有的方法。

总结:不能直接访问子类(实现类)里接口没有的成员变量或者方法。

3.2.5 向上转型和向下转型:

1. 对象的向上转型,其实就是多态写法:

    格式:

        父类名称 对象名 = new 子类名称();

    含义:

        右侧创建一个子类对象,把它当作父类来看待使用。

    注意事项:

        向上转型一定是安全的,没有问题的,正确的,但是也有一个弊端:

        对象一旦向上转型父类,那么就无法调用子类特有的内容。

 

2. 对象的向下转型,其实就是一个【还原的动作】

    格式:

        子类名称 对象名 = (子类名称)父类对象;

        含义:将父类对象,【还原】成为本来的子类对象

    注意事项:

        * 必须保证对象本来创建的时候,就是猫,才能向下转型成为猫

        * 如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错。

如何才知道一个父类引用的对象本来是什么子类?

格式:

对象名 instanceof 类名称

这将会得到一个boolean值结果,也就是判断前面的对象能不能当作后面类型的实例。

代码示例:

public class DemoMain {

    public static void main(String[] args) {
        // // 对象的向上转型,就是:父类引用指向子类对象
        Computer computer1 = new Laptop (); 
        computer1.playGame (); // 父子都有的方法,那么就会优先有子类重写过后的方法
        //computer1.myLaptop(); // 错误写法

        // 如果希望调用子类特有的方法,需要向下转型,进行“还原”
        // 判断以下父类引用Computer本来是不是Laptop
        if (computer1 instanceof Laptop) {
            Laptop laptop = (Laptop) computer1;
            laptop.myLaptop ();
        }

        givemeAComputer (computer1);
    }

    // 最好创建一个方法来判断,因为子类可能不止有一个
    public static void givemeAComputer(Computer computer) {
        if (computer instanceof Laptop) {
            Laptop laptop = (Laptop) computer;
            laptop.myLaptop ();
        }else if (computer instanceof Desktop) {
            Desktop desktop = (Desktop) computer;
            desktop.myDesktop();
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值