Java-类的知识进阶

Java类的知识进阶

类的继承(扩张类)

Java类的继承是指一个类可以继承另一个类的属性和方法,从而使得子类可以重用父类的代码。继承是面向对象编程中的重要概念,它可以帮助我们避免重复编写代码,提高代码的复用性和可维护性。

在Java中,使用关键字extends来实现继承。子类继承父类后,可以使用父类中的属性和方法,同时还可以增加自己的属性和方法。父类中的属性和方法可以使用protected关键字来保护,这样子类就可以访问这些属性和方法。

当子类继承父类时,子类可以重写父类的方法,从而实现子类自己的功能。子类也可以使用super关键字来调用父类的构造方法和方法。

Java中的继承是单继承的,即一个子类只能继承一个父类。但是,Java中可以通过接口实现多继承,一个类可以实现多个接口。

继承有助于代码的复用和扩展,但是也需要注意继承的合理使用。过度的继承会导致代码的复杂性和耦合性增加,同时也会影响代码的性能。因此,在使用继承时需要根据具体情况进行合理的设计和使用。

继承父类的构造函数

Java中,子类继承父类的构造函数有以下几种情况:

  1. 如果子类没有定义构造函数,则默认继承父类的无参构造函数。

  2. 如果子类定义了构造函数,则需要在构造函数中显式调用父类的构造函数,可以使用super关键字来调用父类的构造函数。例如:

public class Parent {
    public Parent(int x) {
        // 父类构造函数
    }
}

public class Child extends Parent {
    public Child(int x) {
        super(x); // 调用父类构造函数
        // 子类构造函数
    }
}
  1. 如果父类没有无参构造函数,而子类又没有显式调用父类的构造函数,则编译器会报错。这时,需要在子类的构造函数中显式调用父类的某个构造函数。例如:
public class Parent {
    public Parent(int x) {
        // 父类构造函数
    }
}

public class Child extends Parent {
    public Child() {
        super(0); // 调用父类构造函数
        // 子类构造函数
    }
}

创建子类的对象

在Java中创建子类的对象,可以使用以下步骤:

  1. 定义一个子类,该子类继承自父类。

  2. 在子类中定义构造函数,可以使用super关键字调用父类的构造函数。

  3. 在主程序中创建子类的对象,可以使用子类的构造函数来创建对象。

例如,以下是一个简单的例子,演示如何创建子类的对象:

class Animal {
    public void eat() {
        System.out.println("Animal is eating");
    }
}

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

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat(); //调用父类的方法
        dog.bark(); //调用子类的方法
    }
}

在这个例子中,Animal类是父类,Dog类是子类。在Dog类中定义了一个bark()方法,该方法是子类特有的方法。在主程序中创建了一个Dog对象,然后调用了父类的方法和子类的方法。

调用父类的构造函数

在Java中,可以使用super关键字来调用父类的构造函数。super关键字必须放在子类构造函数的第一行,并且只能调用一次。调用父类构造函数的语法如下:

public class SubClass extends SuperClass {
    public SubClass() {
        super(); // 调用父类无参构造函数
    }

    public SubClass(int arg) {
        super(arg); // 调用父类有参构造函数
    }
}

在子类构造函数中使用super关键字调用父类构造函数时,可以使用无参构造函数或有参构造函数。如果不调用父类构造函数,则会默认调用父类的无参构造函数。

指定父类的构造函数

在Java中,可以使用super关键字来调用父类的构造函数。下面是指定父类构造函数的语法:

class Subclass extends Superclass {
    Subclass() {
        super(); // 调用父类的默认构造函数
    }

    Subclass(int x) {
        super(x); // 调用父类的带参构造函数
    }
}

在子类的构造函数中,使用super关键字来调用父类的构造函数。如果父类有多个构造函数,可以根据需要选择调用哪一个构造函数。需要注意的是,如果子类的构造函数没有显式地调用父类的构造函数,Java会默认调用父类的默认构造函数。

在子类内部存取

父类中protected或public

父类的成员变量和方法,可以使用super关键字来访问。例如,如果父类有一个名为“age”的成员变量和一个名为“getName”的方法,子类可以使用以下代码来访问它们:

public class Parent {
    protected int age;
    protected String getName() {
        return "Parent";
    }
}

public class Child extends Parent {
    public void printInfo() {
        // 访问父类的成员变量
        System.out.println(super.age);
        // 调用父类的方法
        System.out.println(super.getName());
    }
}

在子类中,super.age表示访问父类的age成员变量,super.getName()表示调用父类的getName方法。注意,这里使用了protected修饰符来使父类的成员变量和方法对子类。可见如果没有使用protected或public修饰符,子类将无法访问它们。

父类有私有变量时,需要使用getter和setter方法。这是因为,私有变量只能在本类中访问,无法被子类直接访问。所以,我们需要在父类中定义公共的getter和setter方法,以便子类可以通过这些方法访问父类的私有变量。

例如,假设我们有一个父类Person,其中有一个私有变量name:

public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在子类Student中,如果我们想要访问父类Person的name变量,就需要使用父类的getter和setter方法:

public class Student extends Person {
    public void printName() {
        System.out.println(getName());
    }

    public void changeName(String newName) {
        setName(newName);
    }
}

在printName方法中,我们使用了父类的getName方法来获取name变量的值。在changeName方法中,我们使用了父类的setName方法来修改name变量的值。这样,我们就可以在子类中存取父类的私有变量了。

重载

重载方法

Java中,类中可以定义多个同名方法,只要它们的参数列表不同,这就是方法重载(overloading)。

方法重载的规则:

  1. 方法名必须相同

  2. 参数列表必须不同(个数不同或者类型不同,顺序不同也算)

  3. 方法的返回类型可以相同也可以不同

  4. 仅仅返回类型不同不足以成为方法的重载

例子:

public class MyClass {
    public void print(int x) {
        System.out.println("This is an integer: " + x);
    }

    public void print(String x) {
        System.out.println("This is a string: " + x);
    }

    public void print(int x, String y) {
        System.out.println("This is an integer: " + x + " and this is a string: " + y);
    }
}

在上面的例子中,MyClass类中定义了三个print方法。第一个print方法接收一个整型参数,第二个print方法接收一个字符串参数,第三个print方法接收一个整型参数和一个字符串参数。这三个方法的方法名相同,但是它们的参数列表不同,因此它们构成了方法的重载。

用父类的参数处理对象

在Java中,可以使用父类的参数来处理对象。这通常涉及到使用继承和多态性的概念。

首先,在父类中定义一个参数类型为父类的方法,该方法将接收一个父类的对象作为参数。然后,在子类中重写该方法,并使用子类的对象来调用它。

例如,假设有一个Animal类和一个Dog类继承自它。Animal类有一个方法叫做makeSound(),它接收一个Animal对象作为参数并打印出该对象的声音。在Dog类中,可以重写makeSound()方法,并使用Dog对象来调用它。

下面是一个示例代码:

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

public class Dog extends Animal {
    @Override
    public void makeSound(Animal a) {
        System.out.println("This dog barks");
    }

    public static void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = new Dog();
        animal.makeSound(animal); // prints "This animal makes a sound"
        dog.makeSound(dog); // prints "This dog barks"
        animal.makeSound(dog); // prints "This animal makes a sound"
    }
}

在此示例中,Animal类有一个makeSound()方法,它接收一个Animal对象作为参数并打印出该对象的声音。Dog类继承自Animal类,并重写了makeSound()方法,以便使用Dog对象来打印出狗的声音。

在main()方法中,创建了一个Animal对象和一个Dog对象。然后,使用这些对象来调用makeSound()方法,以便演示使用父类的参数来处理对象的概念。

方法重载的重要性

Java方法重载的重要性在于可以提高代码的可读性和可维护性。通过方法重载,可以使用相同的方法名来实现不同的功能,使代码更加简洁和易于理解。同时,方法重载还可以避免使用过多的方法名,减少代码的冗余和重复,提高代码的重用性。此外,方法重载还可以使代码更加灵活,能够适应不同的需求和情况,提高代码的适应性和扩展性。总之,Java方法重载是Java编程中非常重要的一部分,可以提高代码质量和开发效率。

使用与父类相同名称的成员

在Java中,如果一个子类想要使用与父类相同名称的成员变量或方法,可以使用super关键字来引用父类的成员。

对于成员变量,可以使用super关键字来访问父类的成员变量。例如:

public class Parent {
    public int x = 10;
}

public class Child extends Parent {
    public int x = 20;

    public void printX() {
        System.out.println("Child x: " + x); // 输出20
        System.out.println("Parent x: " + super.x); // 输出10
    }
}

对于成员方法,可以使用super关键字来调用父类的方法。例如:

public class Parent {
    public void print() {
        System.out.println("Parent");
    }
}

public class Child extends Parent {
    public void print() {
        System.out.println("Child");
        super.print(); // 调用父类的print方法
    }
}

使用super关键字可以方便地在子类中使用与父类相同名称的成员。

添加final

在Java中,可以使用关键字final来修饰类,表示该类不能被继承。在类的定义前加上关键字final即可。

例如:

final public class MyClass {
    // 类的成员变量和方法
}

这样定义的类MyClass就是一个final类,不能被其他类继承。

需要注意的是,如果一个类被声明为final,那么它的所有方法都默认为final方法,即不能被子类重写。如果需要允许子类重写某个方法,可以在该方法前加上关键字override。

Object类的继承

创建类的阶层

  1. 定义类名和访问修饰符
  2. 定义类的属性,包括变量和常量
  3. 定义类的构造方法,用于初始化对象
  4. 定义类的方法,包括普通方法、静态方法和抽象方法
  5. 定义类的内部类或枚举类型
  6. 重写Object类的方法,如equals、hashCode和toString方法
  7. 实现接口,包括单个接口和多个接口
  8. 定义类的静态代码块或实例代码块
  9. 定义类的内部类或枚举类型的构造方法、方法和属性
  10. 定义类的内部类或枚举类型的静态代码块或实例代码块

了解Object类

Java Object类是所有Java类的超类,它定义了所有Java类都具有的默认行为。Object类有以下几个重要的方法:

  1. equals():比较两个对象是否相等。默认实现是比较两个对象的内存地址,可以被子类重写以定义自己的相等逻辑。

  2. hashCode():返回对象的哈希码。默认实现是返回对象的内存地址的哈希码,可以被子类重写以定义自己的哈希码计算逻辑。

  3. toString():返回对象的字符串表示。默认实现是返回类名和对象的内存地址的字符串表示,可以被子类重写以定义自己的字符串表示逻辑。

  4. getClass():返回对象的类对象。

  5. notify()和notifyAll():用于多线程同步,唤醒等待在对象上的线程。

  6. wait():用于多线程同步,使当前线程等待,直到其他线程调用notify()或notifyAll()方法唤醒它。

Object类是Java语言中最基本的类,所有的Java对象都直接或间接继承自Object类。因此,Object类的方法对Java程序的编写和调试都具有非常重要的意义。

定义toString()方法

在Java中,toString()方法是一个Object类中的方法,它用于返回对象的字符串表示形式。如果没有重写该方法,则默认实现返回一个包含对象类名和哈希码的字符串。

在实际应用中,程序员通常会根据自己的需要重写toString()方法,以便更好地描述对象的状态和属性。例如,可以使用该方法将对象的各个属性以字符串形式连接起来,以便于输出和调试。

以下是一个示例代码,展示如何重写toString()方法:

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

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

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

在上面的示例中,我们重写了toString()方法,将Person对象的name和age属性以字符串形式输出。当我们在程序中调用该方法时,就会得到一个包含这些信息的字符串。

例如,下面的代码片段将创建一个Person对象,并输出它的字符串表示形式:

Person p = new Person("Alice", 25);
System.out.println(p.toString());

输出结果如下:

Person [name=Alice, age=25]

使用equals()方法

Java中的equals()方法是用来比较两个对象是否相等的方法。在Java中,所有的类都继承了Object类,Object类中有一个equals()方法,但是它的默认实现是比较两个对象的引用地址是否相等,即是否为同一个对象。因此,如果我们想要比较两个对象的内容是否相等,就需要重写equals()方法。

重写equals()方法的步骤如下:

  1. 检查传入的对象是否为null,如果为null,直接返回false。

  2. 检查传入的对象是否为当前对象的实例,如果是,直接返回true。

  3. 检查传入的对象是否属于同一个类,如果不是,直接返回false。

  4. 将传入的对象转换为当前类的实例。

  5. 比较当前对象的每个属性是否与传入对象的属性相等,如果有任何一个属性不相等,直接返回false。

  6. 如果所有属性都相等,返回true。

下面是一个示例代码,演示如何重写equals()方法:

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

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

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        if (age != other.age) {
            return false;
        }
        return true;
    }
}

在这个示例中,我们重写了Person类的equals()方法,比较了两个Person对象的name和age属性是否相等。如果两个Person对象的name和age属性都相等,那么equals()方法就会返回true,否则返回false。

使用getClass()方法

在Java中,getClass()方法是Object类中的一个方法,可以用来获取一个对象的运行时类。它的语法如下:

public final Class getClass()

该方法返回一个Class对象,该对象表示当前对象所属的类。例如:

public class MyClass {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        Class<?> c = obj.getClass();
        System.out.println(c.getName());
    }
}

在上面的代码中,我们创建了一个MyClass对象,并调用了它的getClass()方法来获取它的运行时类。然后我们使用Class对象的getName()方法来获取该类的名称,并将其打印到控制台上。运行结果为:

MyClass

这说明getClass()方法确实返回了当前对象所属的MyClass类。

你可能感兴趣的:(Java,java,jvm,servlet,类)