LOADING

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

Mouz.CN

Sunshine鼠鼠的博客

记录日常的收获和发电

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~(∠・ω< )⌒★

阅读全文
1 ... 2
avatar
Sunshine

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