Java
这就是又能写安卓,又能写mc mod的函数名一长串的语言啊!
简介
分类
java分为三个版本Java SE、Java EE(现更名为Jakarta EE)、Java ME,他们之间关系就好像Python 和 MicroPython。
特性 | JSE JRE | JEE JRE | JME JRE |
---|---|---|---|
定位 | 标准版 | 企业版 | 微型版 |
库和 API | 核心 Java 库 | 核心库 + 企业级 API | 精简库 + 设备特定 API |
JVM | 标准 JVM | 标准 JVM | 定制化 JVM(如 CLDC HotSpot) |
适用场景 | 桌面应用、小型服务器 | 企业应用、Web 服务 | 移动设备、嵌入式系统 |
- JSE JRE 只能运行基于 JSE 开发的程序。
- JEE JRE 可以运行 JSE 和 JEE 程序,因为它包含了 JSE 的所有功能。
- JME JRE 只能运行基于 JME 开发的程序,因为它的库和 JVM 是专门为资源受限设备设计的。
如官网地址显示的就是**JDK 21 is the latest Long-Term Support (LTS) release of the Java SE Platform.**正常我们用的就是java se。上述内容不重要。
我学的好像是java8的老版本,但是为了fabric 1.21.4,我使用jdk21来进行实操。
C++的过渡
- Java没有指针,有引用,但是它的引用和C++的引用不是相同的概念
- Java能够自动管理内存
- Java多平台数据类型是统一大小的
- Java类似python,声明和实现在一起,不需要头文件h和实现cpp这种形式
- 没有define这种宏
- 不支持多重继承,即不能有多个爹,为了解决钻石继承,引入了接口这个性质
- 没有全局变量,作用域最大就是类里面
- 没有struct和union,有class就足够了
- 没有goto
运行
xxx.java编译成字节码xxx.class,在不同平台上使用不同的解释器来运行
JRE = JVE + API JDK = JRE + Tools
基本工具如通过javac.exe编译,java.exe运行。
引入
hello
先写一个经典的hello world
注意:类名和文件名要相同
对于一个**.java文件**我们要知道其组成部分:
- package (0 or 1)
- import (>= 0)
- class (>= 1) 但是 public class (= 1 并且与文件同名)
注:
- package 的作用就是 c++ 的 namespace 的作用,防止名字相同的类产生冲突。
- java因强制要求类名(唯一的public类)和文件名统一,因此在引用其它类时无需显式声明。在编译时,编译器会根据类名去寻找同名文件。
from runoob
注释
和c差不多,Javadoc提供根据文档注释生成文档的功能。
类和对象
- 类 Class :含有 方法method (成员函数), 字段 field (成员变量)
- 对象 Object
- 继承 通过 class A extends B {…}
- 封装:通过public方法访问私有字段
- 多态
- 抽象:类似纯虚函数
- 接口:定义类必须实现的方法,支持多重继承。
- 重载:同c++,同名不同参
数据类型
Java由于没有指针,所以全是引用,除了基本的数据类型,全是引用数据类型。
内置
1. 整数类型
用于存储整数值,包括正数、负数和零。
数据类型 | 大小(字节) | 取值范围 | 默认值 |
---|---|---|---|
byte |
1 | -128 到 127 | 0 |
short |
2 | -32,768 到 32,767 | 0 |
int |
4 | -2³¹ 到 2³¹-1(约 -2.1亿 到 2.1亿) | 0 |
long |
8 | -2⁶³ 到 2⁶³-1 | 0L |
long在用数字表示的时候后面一定要加L,如123456789123L,否则视作int
2. 浮点类型
用于存储带小数部分的数值。
数据类型 | 大小(字节) | 取值范围 | 默认值 |
---|---|---|---|
float |
4 | 约 ±3.4e-38 到 ±3.4e38 | 0.0f |
double |
8 | 约 ±1.7e-308 到 ±1.7e308 | 0.0d |
3. 字符类型
用于存储单个字符。
数据类型 | 大小(字节) | 取值范围 | 默认值 |
---|---|---|---|
char |
2 | 0 到 65,535(Unicode 字符) | ‘\u0000’ |
4. 布尔类型
用于存储逻辑值,只有两个可能的值:true
或 false
。
不可以0或非0的整数替代true和false ,boolean不能与整数类型相互转换。
数据类型 | 大小(字节) | 取值范围 | 默认值 |
---|---|---|---|
boolean |
1(实际大小取决于 JVM 实现,可能被优化为 1 位) | true 或 false |
false |
引用
类,接口,数组都是引用类型。
数组
支持两种写法
|
|
可以通过 数组名.length
获取数组的长度。
遍历数组,一种是下标,一种是类似python的for i in xxx,和c++11之后的for auto i : xxx那样的,但是是只读的。
二维数组
以下是和C++不同的不规则数组(锯齿数组)
|
|
数组拷贝
System.arraycopy是最高效的!
流程控制
同c++
switch也需要break
还有我的大括号不换行的码风是Java毋庸置疑的正统!
变量常量
|
|
- type – 数据类型。
- identifier – 是变量名,可以使用逗号 , 隔开来声明多个同类型变量。
按Java惯例, 类名首字母用大写( Pascal) 其余的(包名、方法名、变量名) 首字母都小写(camel)
静态 static 常量 final 还可以组合 static final 数据类型 常量名 = 值;
类和接口
虽然说你要是用C++那一套也都能听懂,但是吧人家都有翻译规范了就规范点吧。
以下是Java类相关的术语中英文对照:
对照
-
类 (Class)
-
对象 (Object)
-
实例 (Instance)
-
属性/域 (Attribute/Field)
-
方法 (Method)
-
构造函数 (Constructor)
-
继承 (Inheritance)
-
父类/超类 (Superclass/Parent Class)
-
子类 (Subclass/Child Class)
-
封装 (Encapsulation)
-
多态 (Polymorphism)
-
抽象类 (Abstract Class)
-
接口 (Interface)
-
重载 (Overloading)
-
重写/覆盖 (Overriding)
-
访问修饰符 (Access Modifier)
- public
- private
- protected
- default (package-private)
-
静态 (Static)
-
final
-
this
-
super
-
包 (Package)
-
导入 (Import)
-
成员变量 (Member Variable)
-
局部变量 (Local Variable)
-
实例变量 (Instance Variable)
-
类变量 (Class Variable)
-
方法签名 (Method Signature)
-
参数 (Parameter)
-
返回值 (Return Value)
-
异常 (Exception)
-
泛型 (Generics)
-
注解 (Annotation)
-
枚举 (Enum)
-
内部类 (Inner Class)
-
匿名类 (Anonymous Class)
-
Lambda表达式 (Lambda Expression)
-
流 (Stream)
-
集合 (Collection)
-
数组 (Array)
-
反射 (Reflection)
-
序列化 (Serialization)
-
反序列化 (Deserialization)
-
线程 (Thread)
-
同步 (Synchronization)
-
异步 (Asynchronous)
类样例
|
|
1. 访问修饰符和类修饰符
-
public
:表示该类可以被任何其他类访问。如果省略,则默认为包级私有(仅在同一个包内可见)。 -
abstract
:表示这是一个抽象类,不能被实例化,只能被继承。抽象类可以包含抽象方法和具体方法。 -
final
:表示这是一个最终类,不能被继承。所有方法默认也是final
的,不能被子类重写。
2. 类声明
-
class className
:定义一个名为className
的类。 -
extends superClass
:表示当前类继承自superClass
。一个类只能继承一个父类。 -
implements InterfaceNameList
:表示当前类实现了InterfaceNameList
中列出的一个或多个接口。一个类可以实现多个接口,接口之间用逗号分隔。
3. 成员变量声明
|
|
-
修饰符:
public
、protected
、private
:控制变量的访问权限。static
:表示该变量属于类本身,而不是某个实例。final
:表示该变量的值一旦赋值后不可更改。transient
:表示该变量不会被序列化。volatile
:确保多线程环境下对该变量的修改对所有线程可见。
-
type
:变量的数据类型,如int
、String
等。 -
variableName
:变量的名称。
4. 方法声明与定义
-
修饰符:
public
、protected
、private
:控制方法的访问权限。static
:表示该方法属于类本身,可以通过类名直接调用。final
:表示该方法不能被子类重写。abstract
:表示该方法没有实现,必须在子类中被实现(仅适用于抽象类)。native
:表示该方法的实现由本地代码(如C/C++)提供。synchronized
:表示该方法在同一时间只能被一个线程访问,用于线程同步。
-
returnType
:方法的返回类型,如void
、int
、String
等。如果是void
,表示方法不返回任何值。 -
methodName
:方法的名称。 -
paramList
:方法的参数列表,多个参数用逗号分隔。例如:(int a, String b)
。 -
throws exceptionList
:声明方法可能抛出的异常类型,多个异常用逗号分隔。例如:throws IOException, SQLException
。 -
statements
:方法体内的代码块,包含具体的操作和逻辑。
示例
以下是一个结合上述元素的完整示例:
|
|
接口样例
接口其实就是某种程度上的抽象类,抽象的不能再抽象,但是它不再是具有相同特征的一类事物,而是类似一些事物具有相同的特点,我们再在子类中实现这些它的特性。侧重于行为的定义。
示例
注意,在Java 8之前,接口中的所有方法都是抽象的(即没有方法体)。Java 8之后,可以有默认方法和静态方法。
三个默认方法
注意从Java9开始finalize
就被标记成弃用,Java18正式干掉它。
继承
子类:subclass
父类/超类:superclass
Java只支持单继承: 一个类只能有一个直接父类
在面向对象编程中,继承(Inheritance) 是代码复用和逻辑分层的重要机制。Java 的继承机制遵循以下核心要点:
🧬 继承的本质
- 子类(subclass) 继承 父类/超类(superclass) 的属性和方法(
private
成员除外) - 子类可以 扩展(extend) 父类的功能,添加新属性和方法
- 子类可以 重写(override) 父类的方法(非
private
和非final
的方法)
⚠️ Java 单继承限制
- 一个类只能有一个直接父类(通过
extends
关键字) - 但可以通过接口(
implements
)实现多重继承的效果 - 继承关系形成树状层次结构(非网状结构)
🛠️ 继承的实际应用
典型场景:
- 代码复用:公共功能提取到父类
- 多态实现:通过父类引用操作子类对象
- 层次建模:表达 “is-a” 关系(如:狗是动物)
继承链示例:
Animal
↑
Mammal
↑
Dog
↑
GoldenRetriever
🔑 关键语法要素
-
extends
关键字:1
class Subclass extends Superclass { ... }
-
super
关键字: -
构造器调用规则:
- 子类构造器必须首先调用父类构造器
- 默认调用父类无参构造器(若父类没有无参构造器,必须显式调用)
❓ 为什么 Java 选择单继承?
- 避免多继承的复杂性(如著名的菱形继承问题)
- 简化语言设计,提高代码可维护性
- 通过接口机制弥补功能缺失,实现更灵活的设计
📜 访问权限
Java的继承只有extends这一种方式,和cpp不同,访问权限只由父类的修饰符决定。
修饰符 | 同类访问 | 同包访问 | 子类访问(不同包) | 不同包非子类 |
---|---|---|---|---|
public |
✅ | ✅ | ✅ | ✅ |
protected |
✅ | ✅ | ✅ | ❌ |
默认(无修饰符) | ✅ | ✅ | ❌ | ❌ |
private |
✅ | ❌ | ❌ | ❌ |
🧩 继承中的访问规则
1️⃣ public
成员
-
完全开放访问
-
子类可以直接访问父类的
public
成员 -
示例:
2️⃣ protected
成员
-
子类特权访问
-
子类可以直接访问父类的
protected
成员(即使位于不同包) -
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Parent.java(包 com.example) package com.example; public class Parent { protected String protectedField = "Protected"; } // Child.java(包 com.test) package com.test; import com.example.Parent; public class Child extends Parent { void print() { System.out.println(protectedField); // 不同包子类可直接访问 } }
3️⃣ 默认(包私有)成员
-
同包访问限制
-
只有相同包内的子类可以访问
-
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
// Parent.java(包 com.example) class Parent { String packageField = "Package-private"; } // ChildSamePackage.java(包 com.example) public class ChildSamePackage extends Parent { void print() { System.out.println(packageField); // 同包子类可访问 } } // ChildDiffPackage.java(包 com.test)→ 无法访问
4️⃣ private
成员
-
完全继承隔离
-
子类无法直接访问父类的
private
成员 -
只能通过父类提供的
public/protected
方法间接访问 -
示例:
🔧 继承中的构造方法
-
构造方法不被继承(即使父类构造方法是
public
) -
子类构造器必须调用父类构造器(通过
super()
) -
示例:
💡 关键注意事项
-
跨包继承时:
protected
成员在不同包子类中可以直接访问- 但不同包的非子类不能访问
protected
成员
-
方法重写规则:
- 重写方法的访问权限不能 缩小(如父类方法是
public
,子类重写方法不能改为protected
)
- 重写方法的访问权限不能 缩小(如父类方法是
-
成员变量访问:
- 子类可以定义与父类同名的成员变量(但不推荐,会产生隐藏现象)
-
Java 没有 C++ 式的访问继承:
// Java 不支持这种写法! // class Child extends private Parent {} // 非法语法
-
**构造方法是不能继承的 **
- 但是可以调用
-
**super访问父类的域 **
- 通过super.{field_name}来访问
- 使用super可以访问被子类所隐藏了的同名变量。
- 当覆盖父类的同名方法的同时,又要调用父类的方法,就必须使用super。