LOADING

加载过慢请开启缓存 浏览器默认开启

天童爱丽丝.top

Sunshine鼠鼠的博客

一个初入计算机领域的二次元人士の小窝

Java期末拾遗-下半

2025/7/3

1.编译器和解释器的区别
编译器是“一次性翻译,整体执行”,解释器是“一边翻译,一边执行”。
对比图(改自GPT):

对比项 编译器(Compiler) 解释器(Interpreter)
翻译方式 一次性将整个源代码编译成可执行文件 逐行解释源代码并立即执行
输出结果 可执行文件(如 .exe.class 等) 无独立可执行文件,直接运行
执行效率 高(编译后运行快) 较低(每次运行都要解释)
调试方便程度 不易定位具体错误行(需要整个编译过程) 容易定位(出错立即停止)
第一次运行速度 慢(需要先编译) 快(直接运行)
依赖环境 编译后可独立运行,不再依赖编译器 每次运行都依赖解释器
常见语言 C、C++、Java(先编译成字节码) Python、JavaScript、Ruby

需要注意的是:Java既是编译型又是解释型语言。
这句话看起来矛盾,其实是因为 Java 有两个阶段的执行过程,结合了编译型语言和解释型语言的特点。
第一步:编译(Compiler)
Java 源代码(.java 文件)会先被 编译器(javac) 编译成 字节码文件(.class),这个过程是一次性编译,类似于 C、C++ 的编译阶段。
第二步:解释(Interpreter)或即时编译(JIT)
编译后的 .class 文件不是直接执行的,而是由 Java 虚拟机(JVM) 来运行:
JVM 内部会用 解释器 把字节码一行一行“翻译”成机器指令并执行。
同时,JVM 的 JIT(Just-In-Time)编译器 会把频繁执行的字节码“临时编译”为本地机器码,提高效率。

2.static变量
static 变量(也叫静态变量),是属于类(class)而不是对象(object)的变量。
static能够修饰成员变量和方法,内部类,也可以形成静态static代码块,不能修饰局部变量。
静态代码块:定义在成员位置,使用static修饰的代码块{},随着类的加载而执行,且执行一次,优先于main方法和构造方法的执行。
static 变量在内存中只存在一份,它是随着类的加载而加载的,且只加载一次。例如:
Java 程序的入口方法 main是一个 static(静态)方法。

public static void main(String[] args){}

它优先于对象存在,所以,可以被所有对象共享。
需要注意的是:静态方法不能访问非静态变量,因为它没有 this 对象。
静态方法在没有任何对象的情况下就可以被调用,而非静态变量属于某个对象,必须通过 this 才能访问。
this 代表当前对象的引用,而静态方法属于类本身,不属于任何对象,所以它没有 this。

static void print() {
    System.out.println(name); // ❌ 错误,name 是非静态变量
}

3.多态、重写与重载
重写:
重写是实现多态的必要前提之一。
子类出现重名的成员方法(返回值类型,方法名和参数列表都相同),访问是特殊情况,声明不变,将父类方法重新实现。
需要注意:1.子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
2.子类方法覆盖父类方法,必须要保证权限大于等于父类权限(例如父类是 public,子类不能是 protected),
子类抛出的异常不能比父类方法更宽泛。
例如:

class Animal {
    void makeSound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark");
    }
}

重载:
在一个类中方法名相同,但参数不同(类型或个数),返回类型可以相同或不同的多个方法。

特性 内容
是否需要继承 无需继承,可在同一个类中定义
方法名 相同
参数列表 必须不同(类型、数量或顺序不同)
返回类型 可以不同,但不能靠返回类型区分方法

例如:

class Calculator {
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }

    int add(int a, int b, int c) {
        return a + b + c;
    }
}

需要注意的是:Java支持构造函数重载(Constructor Overloading),即一个类可以有多个构造函数,只要它们的参数列表不同(参数类型、顺序或数量不同)。
多态:
多态是指同一行为,具有多个不同的表现形式。
即父类定义了一个方法,而子类方法重写该方法时方法主体不一样,
这样在不同子类里面这个方法的实现形式就不一样,能让程序更有扩展性。
需要注意:当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误,不能调用子类拥有,而父类没有的方法。想要调用子类特有的方法,必须做向下转型。
多态例如:

class Animal {
    void makeSound() { }
}

class Dog extends Animal {
    @Override
    void makeSound() {  //对于Cat子类,makeSound方法是Bark
        System.out.println("Bark");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {  //对于Cat子类,makeSound方法是Hajimi
        System.out.println("Hajimi");
    }
}

4.关系
在画类图的时候,”is-a” 和 “has-a” 是两种最基础的关系。

  1. “is-a” 关系(继承/实现),包括子类 继承 父类,或类 实现 接口。
    继承(类 → 类):空心三角箭头(子类指向父类),如:Dog ──────▷ Animal
    实现(类 → 接口):虚线空心三角箭头 或 棒棒糖表示法,如:
    Dog ⤍ «interface» Runnable或Dog ───○ Runnable
  2. “has-a” 关系(组合/聚合/关联),表示一个类包含另一个类的对象。
    组合(Composition):强依赖,部分不能脱离整体存在(如 Car 和 Engine)。
    聚合(Aggregation):弱依赖,部分可以独立存在(如 University 和 Department)。
    关联(Association):普通的持有关系(如 Student 和 Course)。
    关系类型 符号 示例 说明
    组合 实心菱形 ◆── Car ◆── Engine 生命周期绑定,强依赖
    聚合 空心菱形 ◇── University ◇── Department 生命周期独立,弱依赖
    关联 实线箭头 ───> Student ───> Course 普通持有关系

5.java易忘英语单词汇总
inherit 继承 subclass(child class)子类 equivalent 等价的、同义的
signature 署名 coexist 共存 invoke 调用 instantiate 实例化 abnormalities紊乱
execute 执行 exception handler 异常处理器 stack trace 堆栈跟踪
scope 作用域 wrapper 包装 instance 实例 arguments 参数 集合Collection

6.访问权限问题
对于父类来说:
private:仅当前类可访问(子类和其他类均不可见)。
default(包私有):同一包内的类可访问(子类如果在不同包则不能访问!)。
protected:同一包内的类 + 不同包的子类可访问。
public:所有类均可访问。

7.java文件中的注释问题

注释类型 语法 用途 是否生成 Javadoc
单行注释 // 临时注释或简短说明 ❌ 否
多行注释 /* ... */ 跨行注释,适合较长说明 ❌ 否
Javadoc /** ... */ 生成 API 文档(含 @param 等标签) ✅ 是
阅读全文

Java期末拾遗-上半

2025/6/30

哎哟,又到期末了,java有一些细碎知识还不会,
故在此收集并记录,我在期末拾来的java知识。

1.传值和传址,Java与C
传值和传址
传值和传值的区别是什么?
假如现在你电脑桌面有个word文档,传值就是你把这文档创建了一个副本,
然后你是原封不动的把这个文档提交了,或是把它修改了,都跟你最初的文档一点关系没有。
然后传址就是你把原文件改了。
对于C/C++,我们可以真正传递地址(指针),通过指针修改原始变量。
而对于Java,Jesus Crime!
我们无法修改基本变量的值!
Java 中所有参数传递本质上是值传递,但分两种情况:
对于基本类型(int, double 等),传的是值的副本,对值无法改变

public class Main {
    public static void main(String[] args) {
        int x = 10;
        change(x);
        System.out.println(x);  // 输出仍是 10
    }

    static void change(int val) {
        val = 20;  // 改的是 val 的副本
    }
}

x 的值没有变,因为change()只是把 x 的副本传进去了,这个change()只是自欺欺人罢了。
但是对于对象和数组,虽然值传递的“祖宗章程”没变,但是情况有变。
如果是对象或是数组,传的是“引用的副本”,即拷贝了一份引用数据的地址,通过改变引用数据的地址可以改对象内部。

class Person {
    String name;
}

public class Demo {
    public static void change(Person p) {
        p.name = "Alice";   // 改变对象内容 ✅
        p = new Person();   // 改变引用本身 ❌(不会影响原来的 p)
        p.name = "Sunshine";     // 改变的是新对象
    }

    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "Tom";
        change(p1);
        System.out.println(p1.name); // 输出是 Alice
    }
}

引用数据类型存储的是“对象的地址”(引用)。
在这个例子里面,name原来引用Tom的地址,使得p1的name对应为Tom。
然后再change()函数里面,将引用的数据改为“Alice”,将新的ALice的地址给name引用,从而改变了对象的内容。
但是下一步尝试将新对象赋给p,实际只是创建了一个p的副本,让这个副本指向了一个新的对象,
原来p不变,p1自然不变,还是掩耳盗铃。

2.重写euquals方法
Q1:“为什么不直接用等号 == 对比两个对象,而要写 equals() 这么麻烦?”
A:== 比较的是两个对象的内存地址是否相同(引用是否一致),即判断是否是同一个对象。
如果你不重写 equals() 方法,默认行为等同于 ==(Object类默认的实现)。
重写equals方法后,比较的是两个对象的逻辑内容是否相同(可以自定义什么算逻辑内容相同),即判断是否是“内容上相等”。
举个生活中的例子,== 相当于判断:这两张身份证是不是“完全同一张卡片”?(内存地址)
equals() 问题:这两张身份证上是不是“属于同一个人”?(内容逻辑)
Q2:正确重写equals方法示例?

public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Product product = (Product) obj;
        return initialCode.equals(product.initialCode);
    }

(当 if 语句后面只有一条语句时,可以省略大括号 {}。执行语句仅为后面的那一句,但这只是语法允许,不代表是最佳实践。)
Q3:为什么要强制转化成product类?
Object 是所有类的父类,而 equals(Object obj) 方法的参数类型是 Object。
这句代码是把一个通用的 Object 类型,强制转换成你自己定义的具体类型 Product,
否则你就无法访问 Product 类中的字段或方法,比如下一句的比较initialCode,必须是访问 Product类才可以。
所以你必须告诉编译器:”我知道这个对象其实是 Product 类型”,于是要强制转换。
由于在前面已经做了类型检查:

if (obj == null || getClass() != obj.getClass()) return false;

所以之后进行强制类型转换是安全的。

3.父类构造器与super()
Q1:父类可以没有任何构造器吗?
A:父类必须有构造器,但可以不显式写(你自己手敲)
如果你没有写任何构造器,Java 会自动帮你加一个无参构造器(默认构造器)。

class Parent {
    // 没写构造器,Java 自动添加:Parent() {}
}

一旦你写了任意一个构造器(哪怕是带参数的),Java 就不会自动添加默认构造器了。
Q2:子类怎么调用构造器?
对于子类、父类构造器而言,它只能够被调用,而不能被继承。
子类会默认调用父类的构造器,但是如果没有默认的父类构造器(即构造器是有参的),
子类必须要显示的指定父类的构造器,即使用super(),
而且必须是在子类构造器中做的第一件事(第一行代码)。
如:

super(name);  // 调用父类 Person 的构造方法 Person(String name)

父类构造器参数需要什么类型,你在括号里就填什么类型。
与此同时,如果父类有多个构造器(不同构造器参数不同)
可以重载多个子类构造器,分别调用不同的 super(…),
在括号里面填入不同父类构造器对应的数据类型即可。
补充:super(“Alice”); 和 super(name); 都是调用父类构造器的方式。
super(“Alice”); 是直接传字面量,和子类有没有参数无关。
super(name); 是传递子类构造器的参数,将子类构造器中的 name 变量传递给父类构造器。子类构造器传进什么,就传给父类,让父类帮忙构造。

4.抽象类和抽象方法
Q1:什么样的类、方法是“抽象”的?
我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类,例如:

abstract class Animal //包含抽象方法,故为抽象类
 {
    abstract void makeSound(); // 所有动物都必须有叫声(抽象方法)
}

Q2:既然没有方法主体,抽象类和抽象方法有什么用?
A:有的兄弟,有的。使用抽象类和抽象方法的主要目的是建立一个“通用模板”或“规范”,
它强制子类实现特定的方法行为,从而达到代码的可扩展性、可维护性和一致性。
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法,否则,
从最初的父类到最终的子类都不能创建对象,失去意义。所以抽象方法抽象类给子类指派了重写所有抽象方法的任务。
就像愚公临死前给子孙说了:“一定要移走门口的大山!”,子孙就必须实现这个任务(按中国传统孝道文化来说),
父亲没实现,孙子和重孙也得努力实现,直到所有抽象方法实现,当然,怎么实现是子类的事情,父类只需要指派任务就行了。
此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法,例如:

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Woof! Woof!");
    }
}

注意事项:
一.抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
二.抽象类中,可以有构造方法,是供子类(已经重写所有抽象方法)创建对象时,初始化父类成员使用的。
三.抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
抽象类中可以包含非抽象方法,写一些公共逻辑,这样子类可以复用,例如:

abstract class Animal {
    abstract void makeSound();
    
    public void breathe() {
        System.out.println("Breathing...");
    }
}

每种动物都能呼吸,但发声不一样,我们把通用的breathe()及其方法主体写在抽象类里,作为公共逻辑,特有的 makeSound() 让子类各自实现。

5.接口
Q1:接口与抽象类的区别?
A:如果抽象类比喻为魔园里面的魔法少女的话,虽然关键部分方法被抽象了,但还保留部分人的特征,
接口就是已经飞升到宇宙的圆神,变成圆环之理,成为指导所有引用该接口的类的规则了(哭,可爱的小圆和晓美焰)
接口没有构造函数,只能有常量(public static final),但是相比类可以实现多继承,即一个子类实现多个接口。
接口,是java语言中一种引用类型,是方法的集合,接口的内部主要就是封装了方法,
包含抽象方法、默认方法和静态方法,私有方法(JDK 9)。
接口的定义,与定义类相似,但是使用interface关键字。接口不能创建对象,但是可以被实现(implements,类似于被继承)。

 public interface InterFaceName {
 public abstract void method();
  public default void method() {
  System.out.println("This is a default method");
  // 默认方法需执行语句
}
 public static void method2() {
  System.out.println("This is a static method");
  // 抽象方法需执行语句
  }
 }

与抽象方法的子类类似,一个实现接口的类,需要实现接口中的所有的抽象方法,
然后创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
非抽象子类实现接口:1.必须重写接口所有的抽象方法。
2.继承了接口的默认方法,既可以直接调用,也可重写。

class类名implements接口名{
 // 重写接口中抽象方法【必须】
// 重写接口中默认方法【可选】
}

Q2:抽象方法、默认方法和静态方法的区别?
A:抽象方法必须没有方法体,必须被重写。
默认方法类必须有方法体,可以不重写直接调用,也可以重写(注意default不能省略)。
静态方法也必须有方法体,只能用接口名调用,不可以被重写,不可以通过实现类的类名或者实现类的对象调用,例如:

interface Tool {
    static void info() {
        System.out.println("Interface static method");
    }
}

class MyTool implements Tool {}

public class Main {
    public static void main(String[] args) {
        MyTool t = new MyTool();
        //t.info();         // ❌ 编译错误:不能通过对象调用接口的静态方法

        Tool.info();          // ✅ 正确:接口名调用
    }
}
阅读全文

Javafx与MVC架构

2025/6/13

大作业的基本内容我终于堂堂完成啦!并且我学会将相关代码传送到github库里
(虽然最开始不小心传到网站的库里去了,悲)
本次大作业建设公众污染反馈系统的网格员端,使用了javafx和MVC架构。
Mvc架构分为 View、Controller、Module三个结构,结构简单而分明,适合我这种构建系统初学者,
就像两个村子和中间一条大马路。
View(视图)为前端,展示数据和用户界面。
Model(模型)为后端,用于处理数据和部分简单的业务逻辑。
Controller(控制器)是两者之间的桥梁,负责处理前端的请求,同时我在里面也处理输入数据,所以感觉偏向后端,也是手敲代码最多的地方。
同时记得也要搞个common包装着封装好的类(一段处理数据的代码反复出现就要考虑封装),能有效减少工作量,也让这个系统更健壮、更易维护。
为什么使用javafx?
javafx支持 FXML:类似 HTML 的 UI 描述语言,支持界面与逻辑分离,来构造UI。(也支持CSS)
javafx自带按钮、表格(TableView)、图表(Chart)、媒体播放器等控件,比较轮椅?
javaFX 完全使用 Java 编写,我能直接使用,面向对象编程更自然。
javafx与 MVC 结构天然适配(但是我也不是很懂为什么)喵

阅读全文

更新日志3

2025/6/9

周末两天实在是很忙啊,但是觉得更新网站很有意思。
尝试加入discussion系统在新建类型上遇到了麻烦,还好有顿悟的天兵帮忙,
总之是可以正常使用评论功能了。
周日晚上努力添加了一言功能,还好一言作者有内置javascript文件,减轻了复杂程度,
但是我太笨了先在html文件修改,导致运行后修改没了。
还好现在AI还是很好用的,询问AI在layout.ejs找到了合适添加显示一言的方法,
一路跌跌撞撞,但结果是实现了页脚一言功能,
可以安心睡觉了。

阅读全文

更新日志2

2025/6/6

今天是建站第二天,再此重新研读了此hexo主题作者的教程和相关讨论后,
学会了正确构建tags、categories页面的方法,并付诸实践。
加深了对hexo架构的些许理解。
现在两个页面实现了应有的标签功能,不再是错误放置文章的地盘。
在Rain帮助下导入鼠标点击特效。
挂上了两个朋友的友链(其他朋友似乎没有blog)
网站的结构初步明朗,未来可能尝试实现评论功能。
但是编程实训在即,zzz新大版本也开了,
新功能可能没那么快实现喵。

阅读全文

Java思考1

java(或是面向对象)就是你根据你要描述的东西做一个壳,
这个壳就是类,在这个壳里面你要定义这个东西,定义它的属性和它的方法,
属性就是它的参数,方法就是它会干什么事情。
然后呢,再根据这个壳生成一个个具体的实例,这些实例呢,就是相当于是对象嘛。(在main函数中干)
以上相当于是行动前的准备工作?
你在在main函数里面,做你真正想做的事情,生成这些对象后,然后调用他们的方法来做你想做的事情。

阅读全文

鼠鼠二次元泡面理论(逆天预警)

在二次元世界中,
女孩就好像泡面。
女孩越成熟就像泡面在开水煮了越久一样;
萝莉就像面饼没泡过开水,
只能撒一些调料当干脆面吃;
少女就像泡面刚泡了两分钟,几乎是熟了但是还有些生;
熟女就是泡面完全泡熟了有的甚至煮的有些烂了。
而鼠鼠觉得泡面刚泡两分钟又软同时也有嚼劲,
所以少女赛高好吧!

阅读全文

更新日志1

2025/6/6

2025/6/6凌晨完成
更新本网站的背景、图标、作者头像、描述以及steam社区链接。
创建了about、categories、tags等分类。
并先塞入了部分内容,但是tags仍然需要整理。

阅读全文

tenndouarisu.top正式建站

2025/6/5

今天是2025/6/5,在朋友Rain的帮助下第一次搭建了自己的博客,感谢!
无论怎么讲,
天童爱丽丝.top堂堂启动喵,哈哈
在这个网站我希望记录自己的计算机学习历程和二次元发电相关(并非
Ciallo~(∠・ω< )⌒★

阅读全文

Hello World

2025/6/5

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

阅读全文
1
avatar
Sunshine

东北大学 软件学院
喜欢二次元、打游戏,努力学习中