Java基础(十四)面向对象编程 OOP

Java面向对象基础知识笔记(三)


1. 继承(Inheritance)

继承是面向对象编程中的一种重要概念,它允许创建一个新类,从已存在的类中继承属性和方法。在 Java 中,使用关键字 extends 来实现类之间的继承关系。

1.1 如何继承

class Animal {
    protected String name;

    public void eat() {
        System.out.println(name + " is eating.");
    }
}

class Dog extends Animal {
    public void bark() {
        System.out.println(name + " is barking.");
    }
}

在上述示例中,Dog 类继承自 Animal 类。子类 Dog 继承了父类 Animal 的属性 name 和方法 eat(),并新增了自己的方法 bark()

1.2 类中可以继承哪些内容?哪些不能继承?

可以继承的内容包括:

  • 公共(public)和受保护(protected)的成员变量和成员方法。

不能继承的内容包括:

  • 私有(private)的成员变量和成员方法。
  • 构造方法(constructor)。
  • 静态初始化块(static initializer)和实例初始化块(instance initializer)。

1.3 实例化顺序

在创建一个类的实例时,Java 会按照以下顺序执行:

  1. 执行父类的静态初始化块(如果有)。
  2. 执行子类的静态初始化块(如果有)。
  3. 执行父类的实例初始化块(如果有)。
  4. 执行父类的构造方法。
  5. 执行子类的实例初始化块(如果有)。
  6. 执行子类的构造方法。

2. super 和 this

super 关键字用于访问父类的成员或调用父类的构造方法。this 关键字用于访问当前类的成员或调用当前类的构造方法。

class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    String breed;

    Dog(String name, String breed) {
        super(name);
        this.breed = breed;
    }
}

在上述示例中,Dog 类继承自 Animal 类。子类 Dog 的构造方法使用 super 关键字调用了父类 Animal 的构造方法,并使用 this 关键字给子类的成员变量赋值。

3. 重写(Override)

重写是指子类使用与父类相同名称、相同参数列表和相同返回类型的方法来覆盖父类的方法。子类可以通过重写方法来提供特定于子类的实现逻辑。

class Animal {
    public void makeSound() {
        System.out.println("The animal makes a sound.");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("The dog barks.");
    }

	// Object 是所有类的父类
	public String toString() {
		return "重写 Object 类的 toString() 方法";
	}
}

在上述示例中,Dog 类重写了父类 Animal 的方法 makeSound(),以提供狗狗叫的实现逻辑。

4. 隐藏(Hiding)

隐藏是指子类使用与父类相同名称的静态方法来隐藏父类中的同名静态方法。当通过子类调用该方法时,会隐藏父类中的同名静态方法。
在Java中,实例变量和静态变量之间可以发生隐藏关系。四种可能的情况:

4.1 实例变量隐藏实例变量(instance-field hiding instance-field):

class Parent {
    public int num = 10;
}

class Child extends Parent {
    public int num = 20;

    public void printNum() {
        System.out.println(num); // 输出子类的num,即20
    }
}

在这个例子中,子类 Child 定义了一个与父类 Parent 相同名称的实例变量 num。当在子类中访问 num 时,子类的实例变量会隐藏父类的实例变量。

4.2 实例变量隐藏静态变量(instance-field hiding static-field):

class Parent {
    public static int num = 10;
}

class Child extends Parent {
    public int num = 20;

    public void printNum() {
        System.out.println(num); // 输出子类的num,即20
    }
}

在这个例子中,子类 Child 定义了一个与父类 Parent 相同名称的实例变量 num,而父类 Parentnum 是一个静态变量。当在子类中访问 num 时,子类的实例变量会隐藏父类的静态变量。

4.3 静态变量隐藏实例变量(static-field hiding instance-field):

class Parent {
    public int num = 10;
}

class Child extends Parent {
    public static int num = 20;

    public void printNum() {
        System.out.println(num); // 输出子类的num,即20
    }
}

在这个例子中,子类 Child 定义了一个与父类 Parent 相同名称的静态变量 num,而父类 Parentnum 是一个实例变量。当在子类中访问 num 时,子类的静态变量会隐藏父类的实例变量。

4.4 静态变量隐藏静态变量(static-field hiding static-field):

class Parent {
    public static int num = 10;
}

class Child extends Parent {
    public static int num = 20;

    public void printNum() {
        System.out.println(num); // 输出子类的num,即20
    }
}

在这个例子中,子类 Child 定义了一个与父类 Parent 相同名称的静态变量 num。当在子类中访问 num 时,子类的静态变量会隐藏父类的静态变量。

需要注意的是,当一个变量隐藏另一个变量时,隐藏的是同名的变量,而不是覆盖或重写。隐藏是在编译时决定的,而覆盖和重写是在运行时决定的。隐藏是针对具体的类及其子类,而不会影响其他类。

5. final

final 关键字可以应用于类、方法和变量。它具有以下作用:

  • 当应用于类时,表示该类不能被继承。
  • 当应用于方法时,表示该方法不能被子类重写。可以重载、可以继承。
  • 当应用于变量时,表示该变量是一个常量,只能被赋值一次。
final class MyClass {
    // 类定义
}

class Parent {
    final void myMethod() {
        // 方法定义
    }

    final int num = 10;
}

class Child extends Parent {
    // 编译错误!无法重写 final 方法

    // 编译错误!无法修改 final 变量的值
}

在上述示例中,MyClass 类被声明为 finalParent 类的 myMethod() 方法和 num 变量都被声明为 final

6. Object 类

Object 是 Java 中所有类的根类,它定义了一些常用的方法供其他类继承和使用。以下是一些常用的 Object 方法:

  • toString():返回对象的字符串表示形式。可以根据需要进行重写。
  • finalize()(JDK 9 开始已弃用):在对象被垃圾回收之前调用。不建议在代码中使用该方法。
  • getClass():返回对象的运行时类。
  • hashCode():返回对象的哈希码。
  • equals(Object obj):比较对象是否相等。通常需要与 hashCode() 方法一起重写。
  • clone():创建并返回对象的浅拷贝副本。需要实现 Cloneable 接口。
package kfm.bases.ObjectOriented;

public class CloneDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        // throws CloneNotSupportedException:throws 关键字用于声明方法可能抛出的异常。
        // 在这里,它表示 main 方法可能会抛出 CloneNotSupportedException 异常。
        // 这个异常通常与对象的克隆操作相关。
        Dog1 dog1 = new Dog1("欧弟", "咖啡色");
        // 克隆
        Object dog2 = dog1.clone();

        System.out.println(dog1);
        System.out.println(dog2);

        // 获取哈希码值,看克隆后的对象和克隆前的对象是否为同一个。
        System.out.println(dog1.hashCode());
        System.out.println(System.identityHashCode(dog2));
        // 两种获取哈希码值的方式,结果不同,所以两个对象不是同一个
    }
}

class Dog1 implements Cloneable {
    /*
    implements Cloneable:这是一个接口实现的声明。
    通过实现Cloneable接口,表示该类具有克隆能力,可以使用Object类中定义的clone()方法进行对象的复制操作。
     */
    private String name;
    private String color;

    public Dog1(String name, String color) {
        this.name = name;
        this.color = color;
    }

    @Override
    public String toString() {
        return "有一只" + color + "的狗叫" + name;
    }
    public String getName() {
        return name;
    }
    public String getColor() {
        return color;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
package kfm.bases.ObjectOriented;

public class People {
    private String name;
    private int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof People)) {
            return false;
        }
        People otherPeople = (People) obj;
        return this.name.equals(otherPeople.name) && this.age == otherPeople.age;
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age;
        return result;
    }

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

package kfm.bases.ObjectOriented;

public class ObjectExample {
    public static void main(String[] args) {
        People people1 = new People("小羊呆呆", 18);
        People people2 = new People("科学康盛人才", 20);
        People people3 = new People("小羊呆呆", 18);

        System.out.println(people1.equals(people2));
        System.out.println(people1.equals(people3));

        System.out.println(people1.toString());
        System.out.println(people1);
    }
}

/*
false
true
People{name = 小羊呆呆',age = 18}
People{name = 小羊呆呆',age = 18}
*/

在上述示例中,equals() 方法重写使得两个 People 对象的内容相同时被判定为相等。hashCode() 方法重写使得具有相同内容的 People 对象具有相同的哈希码。toString() 方法的重写使得我们在打印 People 对象时获得了有意义的信息。这些方法都是 Object 类中定义的,但通过重写,让它们是 People 类有了更具体的实现。

你可能感兴趣的:(Java,java,开发语言)