背景
之前预习多态的时候,看到chatgpt3.5给的示例是经典的关于猫狗的举例。代码并不难,一看感觉就会,但是放到idea就开始报错。。。。搞了好久换了好几次方式,才突然反应过来,其实有些基础知识忘记了。。。。记录下。
过程
chatgpt3.5给的示例如下:
// Animal 类,作为基类
class Animal {
// 发出声音的方法
public void makeSound() {
System.out.println("动物发出声音");
}
}
// Dog 类,继承自 Animal 类
class Dog extends Animal {
// 重写 makeSound 方法
public void makeSound() {
System.out.println("汪汪汪!");
}
}
// Cat 类,继承自 Animal 类
class Cat extends Animal {
// 重写 makeSound 方法
public void makeSound() {
System.out.println("喵喵喵!");
}
}
// 多态示例
public class Main {
// 接受 Animal 对象并调用 makeSound 方法
public static void animalSound(Animal animal) {
animal.makeSound();
}
public static void main(String[] args) {
// 创建 Dog 和 Cat 对象
Dog dog = new Dog();
Cat cat = new Cat();
// 调用 animalSound 方法并传入不同的对象
animalSound(dog); // 输出:"汪汪汪!"
animalSound(cat); // 输出:"喵喵喵!"
}
}
将上述代码放入idea中显示如下:
package com.zj.polymorphism;
/**
* Java中多态使用示例
* 多态定义:允许不同对象对同一消息做出不同的反应
* 方法重现,方法重载,以及接口的实现体现了多态
* */
public class PolymorphismTest3 {
// Animal 类,作为基类
class Animal {
// 发出声音的方法
public void makeSound() {
System.out.println("动物发出声音");
}
}
// Dog 类,继承自 Animal 类
class Dog extends Animal {
// 重写 makeSound 方法
public void makeSound() {
System.out.println("汪汪汪!");
}
}
// Cat 类,继承自 Animal 类
class Cat extends Animal {
// 重写 makeSound 方法
public void makeSound() {
System.out.println("喵喵喵!");
}
}
// 多态示例
// 接受 Animal 对象并调用 makeSound 方法
public static void animalSound(Animal animal) {
animal.makeSound();
}
public static void main(String[] args) {
// 创建 Dog 和 Cat 对象
Dog dog = new Dog();
Cat cat = new Cat();
// 调用 animalSound 方法并传入不同的对象
animalSound(dog); // 输出:"汪汪汪!"
animalSound(cat); // 输出:"喵喵喵!"
}
}
其实是会报错的,报错如下:
Inner classes cannot have static declarations:内部类不能有静态声明;
在这个地方idea提示其实有错误,更精确的说法是非静态内部类不能有静态声明。如果该内部类是静态的话,那么其内部是可以有静态声明的,是符合Java语法的。那么就将这个Main内部类去掉就是了,单独放在外部类中,如下:
package com.zj.polymorphism;
/**
* Java中多态使用示例
* 多态定义:允许不同对象对同一消息做出不同的反应
* 方法重现,方法重载,以及接口的实现体现了多态
* */
public class PolymorphismTest3 {
// Animal 类,作为基类
class Animal {
// 发出声音的方法
public void makeSound() {
System.out.println("动物发出声音");
}
}
// Dog 类,继承自 Animal 类
class Dog extends Animal {
// 重写 makeSound 方法
public void makeSound() {
System.out.println("汪汪汪!");
}
}
// Cat 类,继承自 Animal 类
class Cat extends Animal {
// 重写 makeSound 方法
public void makeSound() {
System.out.println("喵喵喵!");
}
}
// 多态示例
// 接受 Animal 对象并调用 makeSound 方法
public static void animalSound(Animal animal) {
animal.makeSound();
}
public static void main(String[] args) {
// 创建 Dog 和 Cat 对象
Dog dog = new Dog();
Cat cat = new Cat();
// 调用 animalSound 方法并传入不同的对象
animalSound(dog); // 输出:"汪汪汪!"
animalSound(cat); // 输出:"喵喵喵!"
}
}
可是如此写之后还是会报错,报错如下:
cannot be referenced from a static context:不能够从静态上下文中引用。
就是从这里开始让我感到很疑惑的,因为一眼看上去,好像没有问题,就是在main方法中实例化Dog和Cat两个对象,然后将两个对象放到静态的animalSound方法中,传递的实例对象是子类Dog和Cat两个对象,而不是要求的Animal对象,这样的方式就已经体现了多态了(允许不同的对象对同一个消息做出不同的响应)。但是这个报错说明这样的写法有问题。
从报错上来说,不能够从静态上下文中引用,完全没头绪的。为什么不能引用,平常调用的时候不都是可以在静态Main主方法中实例化对象的吗????
总之懵逼了很久,才突然想到难道是因为静态的内部方法无法实例化同样的内部类吗?然后将main方法放到单独一个类中跟平常一样调用,结果还是失败的。。。。。这说明跟是否为静态的内部方法无关。。。
后来问chatgpt3.5联网版本才反应过来,这里的Dog和Cat是非静态内部类!!!
非静态内部类是必须要依赖外部类实例才能存在的!!!无论该非静态内部类是处于外部类的内部还是外部都是要先实例化外部类才能拿到该非静态内部类的实例
也就说,要实例化Dog和Cat对象,即使在外部类的内部,要实例化内部类也需要先实例化外部类才能得到非静态内部类的对象。
如下:
public static void main(String[] args) {
//方式一
Animal dog = new PolymorphismTest2().new Dog();
Animal cat = new PolymorphismTest2().new Cat();
animalSound(dog);
animalSound(cat);
//方式二
/*PolymorphismTest2 polymorphismTest = new PolymorphismTest2();
polymorphismTest.animalSound(dog);
polymorphismTest.animalSound(cat);*/
}
按照上面方式写就不会报错。。。。
内省
真的,折腾这么久敢情就是一个非静态的内部类的实例化调用需要先调用外部类。。。。这个知识点并不是说我不知道,而是忽视了。。。因为如果平常是在外部的一个类调用另一个类的非静态内部类的时候这种使用场景就会自然而然的先实例化外部类再去实例化内部类,这个过程都没有感知的,因为有习惯了。但是在这里,因为是在同一个外部类的Main主方法内,想当然的以为不需要再实例化外部类就可以调用内部类了。。。。所以可以得知有些语法规则是要彻底的执行到底的,跟所处的范围是没有关系的,需要严格的执行。