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

Java学习笔记:封装、继承、多态

  • 一、访问修饰符
  • 二、封装
  • 三、继承
  • 四、super关键字
  • 五、方法重写
  • 六、多态
  • 七、绑定机制
  • 八、Object类
    • equals方法
    • hashCode方法
    • toString方法
    • finalize方法

一、访问修饰符

  • 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;
    }
}

三、继承

继承用于解决代码复用,在父类中定义属性和方法所有的子类只需要通过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");
    }
}
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());//可以通过父类的方法来调用私有属性
    }
}

子类必须调用父类的构造器,完成父类的初始化。如果父类没有提供无参构造器,必须在子类的构造器中使用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()
  • 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

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");
    }
}

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

七、绑定机制

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

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

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

八、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;
}

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

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

你可能感兴趣的:(JAVA,java,学习,jvm)