12.Java对象的封装、继承、多态

一.封装(Encapsulation)

1.1概念

如字面意思,将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。

我们对程序的追求:高内聚,低耦合
高内聚:类的内部数据操作自己完成,不允许外部干扰
低耦合:仅暴露少量的方法给外部使用,减少类(模块)之间的相互依赖

1.2封装的优点

  1. 良好的封装能够减少耦合。

  2. 类内部的结构可以自由修改。

  3. 可以对成员变量进行更精确的控制。

  4. 隐藏信息,实现细节。

1.3实现方法

首先记住这样一句话:属性私有,get/set(大多数对属性私有)

记住这样的两个基本的成员变量修饰符:(关于其他修饰符,会另起一章介绍)
(1)public:公共访问控制符,指定该变量为公共的,他可以被任何对象的方法访问。
(2)private:私有访问控制符,指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。

  1. 修改属性修饰符:private
  2. 创建get/set(用于属性的读写,也就是访问方法)
  3. 在get/set方法中加入属性控制语句
public class Person {

    //属性私有
    private String name;
    private int age;
    private char gender;

    //创建get/set方法
    //获得这个数据
    public String getName(){
        return this.name;
    }
    //设计数据值
    public void setName(String name){
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        //防止数据不合法
        if (age<120 && age>0){
            this.age = age;
        }else
        {this.age = 0;}
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}
public class Application {
    public static void main(String[] args) {

        //实例化 类 对象名 = new 类名();
        Person zhangsan = new Person();
        zhangsan.setName("张三");
        zhangsan.setAge(200);
        zhangsan.setGender('男');
        System.out.println(zhangsan.getName());
        System.out.println(zhangsan.getAge());
        System.out.println(zhangsan.getGender());
    }
}

这样写的好处:

  1. 提高代码安全性,保护数据
  2. 隐藏代码实现细节(例如案例中的年龄合法性设置)
  3. 统一接口
  4. 提高系统维护性

二.继承

2.1概念

继承是类与类的一种关系。比如“男人,女人”继承“人”,这里人类是男人,女人类的父类或者基类,男人,女人类类是人类的子类或者派生类。如下图所示:
继承

在Java中继承是单继承,没有多继承
简单理解,父亲可以有多个儿子,而儿子只能有一个父亲

需要注意的是,继承是类与类之间的关系之一,除此还有依赖,组合,聚合等

2.2实现方法

extends意为扩展,延伸

class 子类 extends 父类

class Men extends Person

2.3继承好处

子类拥有父类的所有属性和方法(除了private修饰的属性不能拥有)从而实现了实现代码的复用;

私有的可以继承,但是无法访问

例如:

//父类
public class Person {

    private int money = 1000;
    public void say(){
        System.out.println("说了一句话");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}

//子类
public class Men extends Person{

}

//主方法
public class Application {
    public static void main(String[] args) {

        Men men = new Men();
        men.say();
        System.out.println(men.getMoney());


    }
}

2.3 Object类

我们Men方法界面按下Ctrl + H,可以弹出层次结构。
层次结构
可以清晰地看到类之间的关系。这里我们发现有一个没有写的Object类,我们切换其他类界面调出结构图,发现都有这个Object类。那么这是个什么呢?
在java中,所有的类,都直接或者间接继承于这个类

2.4 super关键字

在对象的内部使用,可以代表父类对象。

//父类
public class Person {

    public String name = "张三";

    public void print(){
        System.out.println("我是父类");
    }
    }

//子类
public class Men extends Person {
    private String name = "李四";

    public void test() {
        System.out.println(this.name);   //李四
        System.out.println(super.name);  //张三
    }

    public void print() {
        System.out.println("我是子类");
    }
    public void test1(){
        this.print(); //我是子类
        super.print();  //我是父类
    }
}

public class Application {
    public static void main(String[] args) {

        Men men = new Men();
        men.test();
        men.test1();
    }
}

在涉及到构造器时

//父类
public class Person {

    public Person() {
        System.out.println("父类无参执行啦");
    }
}

//子类
public class Men extends Person {

    public Men() {
        System.out.println("子类无参执行啦");
    }
}

public class Application {
    public static void main(String[] args) {

        Men men = new Men();
    }
}

我们对比结果会发现默认先执行了父类的构造器,然后子类的。相当于在子类的无参构造器的第一行有super();

如果自己用super关键字在子类里调用父类的构造方法,则必须在子类的构造方法中的第一行
注意:如果在父类中没有显式定义无参构造,定义了有参构造。这时,子类只能显式调用有参构造

2.5 方法重写

2.5.1什么方法重写?什么时候进行重写?

子类如果对继承的父类的方法不适合,可以自己编写继承的方法,这种方式就称为方法重写。当调用方法时会优先调用子类的方法。

2.5.2方法重写特征

子类重写的方法与父类方法:

  1. 方法名称相同
  2. 参数类型,个数相同
  3. 返回值类型相同
//父类
public class Person {
    public void test(){
        System.out.println("父类测试");
    }
}

//子类
public class Men extends Person {
    @Override  //注解:有功能的注释
    public void test() {
        System.out.println("子类测试");;
    }
}

public class Application {
    public static void main(String[] args) {
        Men a = new Men();
        a.test();
        //父类的引用(b)指向了子类
        Person b = new Men();  //子类重写了父类的方法
        b.test();
    }
}

idea中可按快捷键Alt +insert 重写方法,override意为重写

注意点:

  • 重写方法后,执行的是子类的方法
  • 只有非静态方法可以重写
  • 修饰符:范围可以扩大,但是不能缩小(public>Protexted>Default>provate)
  • 抛出的异常:范围可以缩小,但是不能扩大

三.多态

3.1概念

即同一方法可以根据发送对象(引用类型)的不同采用多种不同的行为方式
多态的三个前提:

  1. 继承
  2. 重写
  3. 父类引用指向子类对象

3.2实例

//父类
public class Person {
    public void test(){
        System.out.println("父类测试");
    }
}
//子类
public class Men extends Person {
    @Override  //注解:有功能的注释
    public void test() {
        System.out.println("子类测试");
    }
    public void run(){
        System.out.println("run");
    }
}
public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的(等号右侧),但是可以指向的引用类型不确定(等号左侧)
        Men a = new Men();     //父类的引用可以指向本类
        Person b = new Men(); //父类的引用可以指向子类
        Object c = new Men(); //父类的引用可以指向子类
        //对象执行的方法,取决于对象左边的引用类型
        a.test();
        a.run();    //子类可以调用自己的,和继承自父类的
        b.test();
        ((Men) b).run();   //父类只能调用自己的,不能调用子类的,否则会出现强制转换
    }
}

当父类的引用指向子类的对象时,该对象将只是看成一种特殊的父类(里面有重写的方法和属性)

不存在子类的引用属性指向父类,就好比“狗是一种动物”,但是不能说“动物是一种狗”

3.3多态的注意事项

  • 继承是多态的基础
  • 多态是方法的多态 属性不存在

3.4 instanceof

instanceof是Java的一个二元操作符,和==,>,<是同一类。也是Java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据.

public class Application {
    public static void main(String[] args) {

        Object object = new Student();

        System.out.println(object instanceof Student);
        System.out.println(object instanceof Person);
        System.out.println(object instanceof Object);
        System.out.println(object instanceof Teacher);
        System.out.println(object instanceof String);
    }
}

返回结果
true
true
true
false
false
public class Application {
    public static void main(String[] args) {

        Student student = new Student();

        System.out.println(student instanceof Student);
        System.out.println(student instanceof Person);
        System.out.println(student instanceof Object);
        //System.out.println(student instanceof Teacher);//编译报错
        //System.out.println(student instanceof String);//编译报错
    }
}
返回结果
true
true
true

关系如下图
关系图但是instanceof在Java的编译状态和运行状态是有区别的:

在编译状态中,右侧可以是左侧的父类,自身类,子类。在这三种情况下Java编译时不会报错。

在运行转态中,右侧可以是左侧对象的父类,自身类,子类。在前两种情况下的结果为true,最后一种为false。

3.5类型转换

public class Application {
    public static void main(String[] args) {

        //类型之间的转换(高转低强制转换)

        Person a = new Student();
        //此时a对象无法使用go方法
        //转换为Student类型
        //高 ==================> 低
        Student a1 = (Student) a;
        a1.go();
        //上面两句写为一句
        ((Student) a).go();


        //类型之间的转换(低转高)子类转换为父类可能会丢失自己本来的方法
        Student b = new Student();
        b.go();
        Person b1 = b;  //此时b1无法调用go方法
    }
}

  • 父转子(高转低;向下转型):父子都有相同的成分,但是子类还有自己本身的方法.所以父转子时就需要在开辟空间,所以是强制转换.有风险,易发生数据溢出
  • 子转父(低转高;向上转型):由于已经继承父类所有,并且还有自己本身的方法.所以转换为父类就要删去自身的方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不一样的鑫仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值