课后作业

1.

 

TestInherits.java内容
class Grandparent
{


    public Grandparent()
    {

        System.out.println("GrandParent Created.");

    }


    public Grandparent(String string)
    {

        System.out.println("GrandParent Created.String:" + string);

    }

}



class Parent extends Grandparent
{


    public Parent()
    {

        super("Hello.Grandparent.");

        System.out.println("Parent Created");

        // super("Hello.Grandparent.");

    }

}



class Child extends Parent
{


    public Child()
    {

        System.out.println("Child Created");

    }

}



public class TestInherits
{


    public static void main(String args[])
    {

        Child c = new Child();

    }

}

运行结果:

 结果分析:

创建Child对象时,先调用GrandParent的构造方法,接着调用了Parent的构造方法,接着调用Child的构造方法

对Parent进行以下更改后

 会出现以下错误信息:

也就是说通过 super 调用基类构造方法,必须是子类构造方法中的第一个语句。

 

2、

 

 

ExplorationJDKSource.java内容
public class ExplorationJDKSource {

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(new A());
    }

}

class A{}

运行结果:

 

System.out.println()会调用A类的toString()方法,

可A类里面没有定义toString()方法,但所有类都继承自Object类,Object内存在着toString()方法,会输出类名以及@哈希值

于是就会输出A@404b9385的结果

 

3、

(1)覆盖方法的允许访问范围不能小于原方法
class Animal {
    // 父类的方法具有protected访问权限
    protected void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    // 子类中的方法的访问权限不能小于父类中的方法
    // 下面的代码会导致编译错误,因为覆盖的方法的访问权限比父类的方法的访问权限更严格(private < protected)
    private void makeSound() {
        System.out.println("Dog barks");
    }
}

(2)覆盖方法所抛出的异常不能比原方法更多

class Parent {
    // 父类方法声明抛出IOException
    void doSomething() throws IOException {
        // 省略具体实现
    }
}

class Child extends Parent {
    // 子类方法声明抛出IOException和SQLException,这是不允许的
    @Override
    void doSomething() throws IOException, SQLException {
        // 省略具体实现
    }
}
异常规范的目的是确保代码的可靠性和一致性。如果子类覆盖方法抛出了比父类方法更多的异常,那么在使用父类引用调用子类对象的方法时,就会引发问题,因为父类引用无法处理子类方法可能抛出的额外异常。这会导致编译时错误,增加了代码的不稳定性和难以维护性。
(3)声明为final方法不允许覆盖
class Parent {
    // 使用final关键字声明的方法
    public final void finalMethod() {
        System.out.println("This is a final method in the Parent class.");
    }
}

class Child extends Parent {
    // 尝试覆盖父类的final方法,会导致编译错误
    // @Override
    // public void finalMethod() {
    //     System.out.println("This is an attempt to override the final method.");
    // }
}

public class Main {
    public static void main(String[] args) {
        Parent parent = new Parent();
        parent.finalMethod(); // 输出: This is a final method in the Parent class.

        Child child = new Child();
        child.finalMethod(); // 调用继承的final方法,输出同样的结果
    }
}

在Java中,使用final关键字声明的方法表示该方法是最终方法,不允许被子类覆盖(即不允许子类中有相同方法签名的方法覆盖该方法)。这是一种限制,通常用于确保特定方法在继承关系中具有不变性和稳定性。

(4)不能覆盖静态方法
class Parent {
    static void staticMethod() {
        System.out.println("父类的静态方法");
    }
}

class Child extends Parent {
    static void staticMethod() {
        System.out.println("子类的静态方法");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent.staticMethod(); // 调用父类的静态方法
        Child.staticMethod();  // 调用子类的静态方法
        
        // 输出:
        // 父类的静态方法
        // 子类的静态方法
    }
}

在Java中,静态方法是属于类的方法,而不是属于实例对象的方法。因此,静态方法不能被覆盖(override)。当子类中定义了一个与父类中的静态方法具有相同方法签名的静态方法时,实际上是隐藏了父类的静态方法,而不是覆盖了它。

在上面的例子中,虽然子类Child中定义了一个与父类Parent中的静态方法相同的静态方法staticMethod(),但它并没有覆盖父类的静态方法。在调用Child.staticMethod()时,实际上调用的是子类的静态方法,而不是父类的静态方法。

 

4.

 

class Mammal {}
class Dog extends Mammal {}
class Cat extends Mammal{}

public class TestCast {
    public static void main(String args[]) {
        Mammal m;
        Dog d = new Dog();
        Cat c = new Cat();
        m = d;  // 此行没有问题,将Dog对象赋给Mammal类型的变量
        d = m;  // 编译错误,不能将Mammal类型的变量赋给Dog类型的变量
        d = (Dog) m;  //运行时错误,会抛出异常,不能将父类强转为子类
        d = c;  // 编译错误,不能将Cat类型的变量赋给Dog类型的变量
        c = (Cat) m;  //运行时错误,会抛出异常,不能将父类强转为子类
  } }

 

5、

 

 运行结果:

 

首先创建了一个Parent类的实例parent,并调用了它的printValue()方法,输出结果是Parent.printValue(), myValue=100。接着,创建了一个Child类的实例child,并调用了它的printValue()方法,输出结果是Child.printValue(), myValue=200

然后,将child赋值给parent,这样parent引用指向了一个Child对象。在Java中,实例变量(非静态变量)的访问是基于引用类型的,而不是实际对象的类型。所以,当调用parent.printValue()时,它实际上调用的是Child类中的printValue()方法,输出结果是Child.printValue(), myValue=200

接着,parent.myValue++会使用Parent类中的myValue变量,它的值会被增加到101。因此,再次调用parent.printValue()时,输出结果是Child.printValue(), myValue=200,因为Child类中的myValue变量的值没有改变。

最后,通过强制类型转换((Child)parent).myValue++,将parent引用强制转换为Child类型,并增加myValue变量的值,使其变为201。再次调用parent.printValue()时,由于引用类型是Child,因此输出结果是Child.printValue(), myValue=201

总结:

当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定,这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。
如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。
如果子类被当作父类使用,则通过子类访问的字段是父类的!

posted on 2023-10-13 21:18  Daniel350  阅读(11)  评论(0编辑  收藏  举报