继承是面向对象编程中的一种重要概念,它允许创建一个新类,从已存在的类中继承属性和方法。在 Java 中,使用关键字 extends
来实现类之间的继承关系。
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()
。
可以继承的内容包括:
不能继承的内容包括:
在创建一个类的实例时,Java 会按照以下顺序执行:
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
关键字给子类的成员变量赋值。
重写是指子类使用与父类相同名称、相同参数列表和相同返回类型的方法来覆盖父类的方法。子类可以通过重写方法来提供特定于子类的实现逻辑。
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()
,以提供狗狗叫的实现逻辑。
隐藏是指子类使用与父类相同名称的静态方法来隐藏父类中的同名静态方法。当通过子类调用该方法时,会隐藏父类中的同名静态方法。
在Java中,实例变量和静态变量之间可以发生隐藏关系。四种可能的情况:
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
时,子类的实例变量会隐藏父类的实例变量。
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
,而父类 Parent
的 num
是一个静态变量。当在子类中访问 num
时,子类的实例变量会隐藏父类的静态变量。
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
,而父类 Parent
的 num
是一个实例变量。当在子类中访问 num
时,子类的静态变量会隐藏父类的实例变量。
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
时,子类的静态变量会隐藏父类的静态变量。
需要注意的是,当一个变量隐藏另一个变量时,隐藏的是同名的变量,而不是覆盖或重写。隐藏是在编译时决定的,而覆盖和重写是在运行时决定的。隐藏是针对具体的类及其子类,而不会影响其他类。
final
关键字可以应用于类、方法和变量。它具有以下作用:
final class MyClass {
// 类定义
}
class Parent {
final void myMethod() {
// 方法定义
}
final int num = 10;
}
class Child extends Parent {
// 编译错误!无法重写 final 方法
// 编译错误!无法修改 final 变量的值
}
在上述示例中,MyClass
类被声明为 final
,Parent
类的 myMethod()
方法和 num
变量都被声明为 final
。
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
类有了更具体的实现。