Java基础——非静态内部类的实例必须依赖外部类的实例存在

2024-04-23 09:28

本文主要是介绍Java基础——非静态内部类的实例必须依赖外部类的实例存在,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

之前预习多态的时候,看到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主方法内,想当然的以为不需要再实例化外部类就可以调用内部类了。。。。所以可以得知有些语法规则是要彻底的执行到底的,跟所处的范围是没有关系的,需要严格的执行。

这篇关于Java基础——非静态内部类的实例必须依赖外部类的实例存在的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/928410

相关文章

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位