【JavaSE】封装与继承,访问限定符的总结

前言

终于经历了漫长的前期学习的铺垫,我们终于见到了面向对象程序的三大特性:封装,继承,多态。今天我来向大家介绍其中两个特性:封装和继承。

封装

什么是封装呢?我们可以简单的理解为,把想让用户看见的东西展现给用户,把不想让用户看见的东西不让用户看见。例如我们的电脑,我们能看见的就只有开机按钮、键盘、显示器、各种接口等日常用户使用的东西,而计算机真正工作的是cpu、显卡、内存等原件,这些原件是被机箱封装起来的。向这样隐藏细节,只向用户提供使用接口的方式我们称为封装。总结一下:封装就是将数据和操作数据的方法进行有机的结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

包的封装

在Java中包其实就是一个文件夹,里面存放了很多的类,这样可以让我们方便管理类。同时包的概念也对类和接口实现了封装,比如一个包中的类不想让另一个包使用,注意:在同一个工程的不同包中,可以存在相同名称的类

如何创建包

在这里插入图片描述
如图这样我们就可以创建一个包了,在包下面我们可以创建类:
在这里插入图片描述
现在让我们来看看包是如何实现封装的:我们在com.Test.demo1这个包中创建一个test类,并且创建两个成员变量

package com.Test.demo1;

public class Test {
   public int a = 20;
   int b = 30;

}

我们在com.Test.demo2也创建了一个test2类,我们实例化了一个Test类型的对象t,通过t去访问成员变量。

package com.Test.demo2;

import com.Test.demo1.Test;

public class Test2 {

    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.a);
        System.out.println(t.b);
    }
}

我们发现我们可以访问a,但是并不能访问b,这是为什么呢?原因是我们在创建a,b两个成员变量时使用的访问限定符不一样,一个我们设置的访问修饰符是public另一个我们没有设置,这个可以我们在以后的分享中会与大家总结,现在大家大家只需要理解在不同包中,我们可以自己设置访问权限,去限定方法或者字段能否在不同包中访问,这就是包的封装。
在这里插入图片描述

导包

Java中有提供了许多已经实现的类为我们使用,但在使用时我们需要导包,如何导包呢?我们以Arrays类为例:



public class Test {

    public static void main(String[] args) {
        int[] array = new int[] {1,2,3,5,2,1};
        java.util.Arrays.sort(array);
        System.out.println(java.util.Arrays.toString(array));
    }

}

我们想对array这个数组排序并且打印,我们可以使用Arrays这个类下面的sort方法和toString方,使用java.util.Arrays.(方法);就可以导入java.util这个包中的Arrays类,但是这样太麻烦了,我们可以使用import一次性解决问题

import java.util.Arrays;

public class Test {

    public static void main(String[] args) {
        int[] array = new int[] {1,2,3,5,2,1};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
        
    }

}

private类的封装

private也是我们说的访问限定符,他是对类中的字段和方法的限定。我们来看代码:

public class Person {
    public String name;
    private int age;
    private double wight;
    
    public Person() {
        
    }
    public Person(String name,int age,double wight) {
        this.name = name;
        this.wight = wight;
        this.age = age;
    }
    
}

我们写了一个人类,我们说一般来说名字都是最先被人知道的,而自己的年龄和体重等是一些比较隐私的问题,所以我们在创建人类时将age wight 等成员变量的访问权限设为private

public class Persontest {
    public static void main(String[] args) {
        Person p = new Person("张三",18,60);
        System.out.println(p.name);
        System.out.println(p.age);
        System.out.println(p.wight);
    }
}

我们创建一个Persontest类用于测试Person类,我们实例化了一个对象,我们想去通过对象打印这个人的姓名年龄和体重。
在这里插入图片描述
我们发现我们并不可以访问,因为我们的年龄和体重都是个人隐私不能随便给陌生人人访问,陌生人能获取的信息只能是你的名字,当然我们也有家人与朋友他们可以获取到自己的近况年龄和体重等。所以我们可以提供给自己的家人一个方法去访问自己的年龄和体重。

public class Person {
    public String name;
    private int age;
    private double wight;

    public Person() {

    }
    public Person(String name,int age,double wight) {
        this.name = name;
        this.wight = wight;
        this.age = age;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

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

    public double getWight() {
        return wight;
    }

    public void setWight(double wight) {
        this.wight = wight;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", wight=" + wight +
                '}';
    }
}

我们给了一些方法,这些方法的访问限定符都是public,我们可以告诉我们的家人和朋友这些方法,这样他们就可以通过这个方法获取我的信息。

public class Persontest {
    public static void main(String[] args) {
        Person p = new Person("张三",18,60);
        System.out.println(p.name);
        System.out.println(p.getAge());
        System.out.println(p.getWight());
        System.out.println(p.toString());
    }
}

在这里插入图片描述
这就是我们面向对象的封装。

继承

继承是什么呢?继承的意义又是什么呢?我们先来看看代码:

public class Dog {
    public String name;
    public int age;
    
    public void eat() {
        System.out.println("吃饭");
    }
    
    public void wangwang() {
        System.out.println("wangwang");
    }
}
public class Cat {
    public String name;
    public int age;

    public void eat() {
        System.out.println("吃饭");
    }

    public void miaomiao() {
        System.out.println("miaomiao");
    }

}

这里我们写了两个类一个猫猫类一个狗狗类,但我们发现我们的代码中有很多重复的地方,我们想猫猫和狗狗都有自己的名字和年龄,都会吃饭,可不可以优化一下只写一次这些东西呢?当然可以,这时我们就可以使用我们的继承了。

public class Animal {
    public String name;
    public int age;

    public void eat() {
        System.out.println( name + "吃饭");
    }

}



我们写一个动物类里面有姓名和年龄,还有一个吃饭的方法,让猫猫类和狗狗类继承这个动物类就可以了。继承的语法修饰符 class (子类) extend (父类)

public class Cat extends Animal{

    public void miaomiao() {
        System.out.println("miaomiao");
    }

}
public class Dog extends Animal{
    public void wangwang() {
        System.out.println("wangwang");
    }
}

我们在测试类中测试一下我们写的代码:

public class Animaltest {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.name = "猫猫";
        c.age = 18;
        c.eat();
        c.miaomiao();

        Dog d = new Dog();
        d.name = "狗狗";
        d.age = 20;
        d.eat();
        d.wangwang();
    }
}

在这里插入图片描述

这就是我们的继承。

super

经过上面的例子,我们发现了子类可以访问父类的方法和属性,那我们就会有问题了,如果子类和父类都有相同的属性和方法会访问谁的呢?我们还是从例子中寻找答案:

class Base {


    public int b = 20;
    public int c = 30;



    public void func2() {
        System.out.println("父类的方法2");
    }

    public void func3() {
        System.out.println("父类的方法3");
    }
}

class Derived extends Base {
    public int a = 1;
    public int c = 3;

    public void func() {
        System.out.println("子类的方法1");
    }

    public void func3() {
        System.out.println("子类的方法3");
    }

    public void print() {
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }
}
public class Test2 {
    public static void main(String[] args) {
        Derived d = new Derived();
        d.func();
        d.func2();
        d.func3();
        d.print();
    }
}

我们来看看输出的结果:
在这里插入图片描述
所以我们可以总结出,在子类的方法中或者通过子类对象访问成员和方法时:

1、如果子类中有该成员变量或者方法,则调用子类中的,如果子类中没有该成员变量或者成员方法,那么就向父类中查找,如果父类中也没有就报错
2、如果有相同名字的成员变量或者成员方法,那么优先访问子类中的

有些兄弟又要问了,那我就想访问父类中的成员变量或者成员方法呢?这个时候我们的super关键字就发挥了作用。super关键字,该关键字主要作用:在子类方法中访问父类的成员

public class Test2 {
    public static void main(String[] args) {
        Derived d = new Derived();
        d.func3();
        d.print();
   }
}

class Base {

    public int c = 30;
    
    public void func3() {
        System.out.println("父类的方法3");
    }
}

class Derived extends Base {
    public int c = 3;

    public void func3() {
        System.out.println("子类的方法3");
        super.func3();
    }
    public void print() {
        System.out.println(c);
        System.out.println(super.c);
    }
}

在这里插入图片描述

子类的构造方法

关于子类中的构造方法我们只需要记住一句话就可以了:在构造子类的时候,一定要先帮助父类进行构造。因为总是现有爸爸再有孩子的嘛。
在这里插入图片描述
我们需要使用super()去调用父类的构造方法:

在这里插入图片描述
注意:我们在类与对象的时候说过,如果我们没有给任何的构造方法,那么Java会提供一个无参的构造方法,父类与子类同样适用,如果子类和父类都没有任何的构造方法,Java会在子类和父类中提供这样两个构造方法:

在这里插入图片描述
总结一下:

  1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构
    造方法
  2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的
    父类构造方法调用,否则编译失败。
  3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
  4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现,因为this也需要放在第一条语句,super也需要放在第一条语句,会冲突。

子类继承父类时的内存分配

public class Test3 {
    public static void main(String[] args) {
        Derived d = new Derived();

    }
}

class Base1 {
    public int a;
    public int b;
    public int c;

    public Base1() {

    }

    public void func3() {
        System.out.println("父类的方法3");
    }
}

class Derived1 extends Base1 {
    public int c;

    public Derived1() {
        super();
    }

    public void func3() {
        System.out.println("子类的方法3");
        super.func3();
    }
    public void print() {
        System.out.println(c);
        System.out.println(super.c);
    }
}

上面实例化的对象d是如何开辟空间的呢?我们之前说过引用指向对象d是一个局部变量,存储的是在一个指向对象的地址,而对象是我们new出来的,存储在栈上,这个对象中既有子类特有的成员变量与成员方法,也有父类中的成员方法与成员变量。方法都被放在方法区上。
在这里插入图片描述

访问限定符的总结

在我们学习类、对象和封装时我们已经提到过这个概念了,我们已经见过了private public 包访问权限还有一个访问权限protected,他的作用是什么呢?他修饰的权限可以为不同包中的子类访问,我们来看看到底是怎么回事:

package com.Test.demo1;

public class Test {
   public int a = 20;
   protected int b = 30;
}


package com.Test.demo2;

import com.Test.demo1.Test;

public class Test2 extends Test{

    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.a);
        System.out.println(t.b);
    }
}


在这里插入图片描述
我们发现这样访问会报错,我们不是说不同包中的子类可以访问嘛?但我们的访问方式不是这样的,我们可以写一个方法去打印他

package com.Test.demo2;

import com.Test.demo1.Test;

public class Test2 extends Test{

    public void func() {
        System.out.println(super.b);
    }
    

    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.a);
    }
}

好了总结一下我们的访问限定符:

限定符范围
private同一包中的同一类
default(包访问符)同一包中的同一类、同一包中的不同类
protected同一包中的同一类、同一包中的不同类、不同包中的子类
public谁都可以访问

public : 可以理解为公开的东西,例如你的长相
protected : 主要用在继承中
default : 可以理解为你家人知道的但陌生人不知道的东西。
private: 就是你自己的秘密

以上就是我对Java中继承和封装的理解,如有错误希望大家指出。

  • 31
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

悲伤猪小猪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值