• Java学习笔记(二):封装、继承、多态


    一、访问修饰符

    • public: 在任何类的函数或定义初始值中可以使用,使用指的是调用、访问、或定义变量。

    • protected: 受保护的,对子类和同一个包中的类公开。

    • 默认级别: 向同一个包的类公开。

    • private: 只有这个类内部可以访问。类内部指类的成员函数和初始化对象。(这个限制是对类的而不是对对象的)

    • 在同一个包下,不能访问private,在不同包下只能访问public

    编译单元: 一个.java文件,一个编译单元里可以有很多个类,但是只有一个类可以是public。

    修饰符用于修饰类中的属性,成员方法和类,只有默认级别和public才能修饰类。

    二、封装

    把抽象出来的属性跟方法封装在一起,数据被保存在内部,程序其他部分只有通过被授权的方法才能进行操作。

    可以隐藏实现细节,对数据进行验证,保证安全合理。

    1. 将属性进行私有化private(不能直接修改属性)

    2. 提供一个公共的set方法,用于对属性判断并赋值。

    3. 提供一个公共的get方法,用于获取属性的值。

    4. 可以将构造器和set方法结合,这样就不会通过构造器绕过set方法对属性的限制。

    class Encap{
        public int 1;
        private int j;//私有化
        private String name;//私有化
        
        public Encap(int i,int j,String name){
            this.i = i;
            setJ(j);//在构造器中使用set方法
            setName(name);
        }
    
        public int getJ() {
            return j;
        }
    
        public void setJ(int j) {
            //可加入判断条件
            this.j = j;
        }
    
        public String getName() {
            //可加入判断条件
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    三、继承

    继承用于解决代码复用,在父类中定义属性和方法所有的子类只需要通过extends来声明继承父类即可。

    class 子类 extends 父类{}

    • 子类会自动拥有父类定义的属性和方法,父类又叫超类,基类,子类称为派生类。

    • 如果子类中有父类中有过的完全相同的名字的,父类的被隐藏。

    • 子类定义了子类型,子类的对象可以被当作父类的对象来使用,赋值给父类的变量,传递给需要父类对象的函数,放进存放父类对象的容器。

    • 父类中是private的东西只有父类可用,子类虽然继承但是不能直接用,但是可以通过父类的函数去使用。

    package Extends;
    
    public class extends01 {
        public int n1 = 100;
        protected int n2 = 200;
        int n3 = 300;
        private int n4 = 400;
        
        //父类提供了一个public方法,返回n4
        public int getN4(){
            return n4;
        }
    
        public extends01(){
            System.out.println("extends01()");
        }
    
        public void test100(){
            System.out.println("test100");
        }
    
        protected void test200(){
            System.out.println("test200");
        }
    
        void test300(){
            System.out.println();
        }
    
        private void test400(){
            System.out.println("test400");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    package Extends;
    
    public class extends02 extends extends01{
        public extends02(){
            System.out.println("extends02()");
        }
        public void sayOK(){
            System.out.println(n1+n2+n3);
            System.out.println(getN4());//可以通过父类的方法来调用私有属性
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    子类必须调用父类的构造器,完成父类的初始化。如果父类没有提供无参构造器,必须在子类的构造器中使用super去指定使用父类的构造器完成对父类的初始化,否则编译不通过。

    package Extends;
    
    public class extends02 extends extends01{
        public static void main(String[] args) {
            extends02 extends02 = new extends02();
        }
        public extends02(){
            super();//默认调用父类的无参构造器,系统默认加上。
            System.out.println("extends02()");
        }
    }
    
    extends01()
    extends02()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • Java所有类都是Object类的子类,父类构造器的调用不限于直接父类,可一直追溯到Object类(顶级父类)

    • 子类最多只能继承一个父类(直接继承),单继承机制。可以让父类继承其他父类从而使子类继承多个类。

    • 子类和父类之间必须满足is-a的逻辑关系(包含关系)

    • 子类通过查找关系来返回信息,首先看子类是否有该属性,再看父类,再继续找上级父类直到Object类。

    四、super关键字

    super代表父类的引用,用于访问父类的属性、方法、构造器。

    • super在使用时,需要放在构造器第一行,因此和this()不能共存在一个构造器中。

    • super在访问父类的属性和方法时不可以访问private属性和private方法。

    • super的访问不限于直接父类,上级父类和本类中有同名的成员,也可以使用super去访问成员,多个父类中都有同名的成员,super遵循就近原则

    • 当子类中有和父类的属性和方法重名时,为了访问父类的成员,必须使用super。 如果没有重名,使用super、this、直接访问都可。

    package Extends;
    
    public class A {
        public static void main(String[] args) {
            C c = new C();
            c.say();
        }
    }
    
    class B{
        public void say(){
            System.out.println("B");
        }
    }
    
    
    class C extends B{
        public void say(){
            System.out.println("C");
            super.say();
    //        this.say();
    //        say();
        }
    }
    
    C
    B
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    this表示当前对象,super表示子类中访问父类对象。

    this访问和调用都是先从本类开始,super直接访问父类中的属性和方法。

    五、方法重写

    子类的方法和父类的方法的名称、返回类型、参数一样,称为子类的方法覆盖了父类的方法。(构成覆盖关系)

    ● 子类方法的名称、参数要和父类方法的名称、参数完全一致。

    ● 子类方法的返类型和父类方法的返回类型一致,或者是父类返回类型的子类。

    ● 子类方法不能缩小父类方法的访问权限(public>protected>默认>private)

    六、多态

    多态:使用一个变量去调用函数,前提是两个类(对象)存在继承关系。

    package Extends;
    
    public class A {
        public static void main(String[] args) {
            C c = new C();
            System.out.println(c.sum(10,20));
            System.out.println(c.sum(10,20,30));
            
            B b = new B();
            b.say();
            c.say();
        }
    }
    
    class B{
        public void say(){
            System.out.println("B");
        }
    }
    
    class C extends B{
        public int sum(int n1,int n2){
            return n1 + n2;
        }
        public int sum(int n1,int n2,int n3){
            return n1 + n2 + n3;
        }
        public void say(){
            System.out.println("C");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    java的对象变量是多态的,能保存不止一种类型的对象(声明类型的对象或者声明类型的子类的对象)。

    一个对象的编译类型和运行类型可以不一致,编译类型在定义对象时确定(无法改变),运行类型可以改变。(编译类型看 = 左边,运行类型看 = 右边)

    向上转型: 把子类的对象当作父类的对象,向上转型是默认的,不需要运算符,总是安全的。

    父类类型 应用名 = new 子类类型();

    可以调用父类中的所有成员(遵守访问权限),不能调用子类中的特有成员。

    向下造型:子类类型 引用名 = (子类类型) 父类引用;

    只能强转父类的引用,不能强转父类的对象,父类的引用必须指向的是当前目标类型的对象。向下造型后,可以调用子类类型中的所有成员。

    属性的值看编译类型(instanceof比较操作符,判断对象的运行类型是否为XX类型或者其子类型)

    package Extends;
    
    public class Extends {
        public static void main(String[] args) {
            Base base = new Base();
            Sub sub = new Sub();
            Object object = null;
            System.out.println(sub instanceof Sub);
            System.out.println(object instanceof Base);
            
            Base base = new Sub();
            System.out.println(base instanceof Base);
            System.out.println(base instanceof Sub);
        }
    }
    
    class Base{
        int count = 10;
    }
    
    class Sub extends Base{
        int count = 20;
    }
    
    true
    false
    true
    true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    七、绑定机制

    当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定;调用对象属性时,没有动态绑定机制,哪里声明哪里调用。

    函数调用的绑定: 通过对象变量调用函数,调用哪个函数的这件事叫做绑定。

    静态绑定: 变量的声明类型决定
    动态绑定: 变量的动态类型决定(默认使用)

    八、Object类

    Object类:所有的类都是继承自Object类。

    equals方法

    ==:判断基本类型和引用类型,基本类型判断值是否相等,引用类型判断地址是否相等。

    equals:只能判断引用类型,在Object类的子类中往往重写该方法用于判断内容是否相等(Integer、String)

    public boolean equals(Object obj) {
        return (this == obj);
    }
    static final boolean COMPACT_STRINGS;
    
    private final byte coder;
    
    private final byte[] value;
    
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        return (anObject instanceof String aString)
            && (!COMPACT_STRINGS || this.coder == aString.coder)
            && StringLatin1.equals(value, aString.value);
    }
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            for (int i = 0; i < value.length; i++) {
                if (value[i] != other[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    hashCode方法

    提高具有哈希结构的容器的效率,两个引用如果指向的是同一个对象,哈希值是一样的,哈希值主要是根据地址号来但不能完全等价。如果有需要也可以对hashCode进行重写。

    toString方法

    返回全类名@哈希值的十六进制,子类会重写方法用于返回对象的属性信息,当直接输出一个对象时,会被默认调用。

    public final native Class<?> getClass();
    
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    private transient String name;
    private native String initClassName();
    
    public String getName() {
        String name = this.name;
        return name != null ? name : initClassName();
    }
    public class Extends {
        public static void main(String[] args) {
            Base base = new Sub();
    
            System.out.println(base);
            System.out.println(base.toString());
        }
    }
    
    Extends.Sub@7ef20235
    Extends.Sub@7ef20235
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    finalize方法

    • 当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法做一些释放资源的操作。

    • 当一个对象没有任何引用时,就会使用垃圾回收机制来销毁该对象,在销毁前先调用finalize方法。

    • 垃圾回收机制的调用是由系统决定,可以通过System.gc()主动触发

    package Extends;
    
    public class Extends {
        public static void main(String[] args) {
    
            Base base = new Base(20);
            base = null;
            System.gc();
        }
    }
    
    class Base{
        int count = 10;
    
        public Base(int count) {
            this.count = count;
        }
    
        @Override
        protected void finalize() throws Throwable {
            System.out.println("finalize");
        }
    }
    
    finalize
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    Bug系列路径规划算法原理介绍(二)——BUG1 BUG2算法
    QT C++实战:实现用户登录页面及多个界面跳转
    磁珠元器件:微小却强大的科技奇迹 | 百能云芯
    Spring DI(依赖注入)的实现方式:属性注入和构造注入
    GEE ——绘制二元分类的特征 (ROC) 曲线、计算曲线下面积 (AUC)
    JAVA每日小知识(关于excel下载时插入和stream流遍历优化)
    权限框架SpringSecurity(一)——自定义登录
    react-demo项目:支持使用scss(不使用create-react-app脚手架)
    爬虫兽问题解答1-抖音评论区爬虫采集拓客系统
    Canny算子与霍夫变换检测圆与直线
  • 原文地址:https://blog.csdn.net/qq_45902224/article/details/127863265