java快速学习速查(1)
java快速学习速查(1)
在经历了艰苦卓绝的思想斗争之后,我决定走Java的全栈开发,这是个很难走的路线,但是这是最合适现在的环境的(自认为)
我将会在一周内快速解决Java的本体基础学习,会在乐扣上用题目辅助
注意:这是全栈学习的开端,而且必须要快!!
我将以更系统化和结构化的方式为你整理Java基础语法内容,并补充更多实用细节和示例。
这篇文章涉及Java基础语法,注释,对象和类,基本数据类型
Java基础语法全面解析
一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。
- 对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 类:类是一个模板,它描述一类对象的行为和状态。
- 方法:方法就是行为,一个类可以有很多方法。逻辑运算、数据修改以及所有动作都是在方法中完成的。
- 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。
一、程序结构核心概念
这是构成Java语法结构的最基本框架
类与对象
- 类:对象的蓝图/模板
1
2
3public class Dog { // 类名首字母大写
// 类内容
} - 对象:类的具体实例
1
Dog myDog = new Dog(); // 创建Dog类的对象
- 类:对象的蓝图/模板
main方法详解
1
2
3
4
5
6
7public static void main(String[] args) {
// 程序入口必须严格按此格式
// public: 访问修饰符
// static: 静态方法
// void: 无返回值
// String[] args: 命令行参数
}
二、命名规范与语法规则
编写 Java 程序时,应注意以下几点:
- 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
| 元素类型 | 规范示例 | 错误示例 |
|————-|————-|————-|
| 类名 |MyFirstClass
|myFirstClass
|
| 方法名 |calculateTotal()
|CalculateTotal()
|
| 变量名 |studentCount
|StudentCount
|
| 常量名 |MAX_VALUE
|max_value
|
重要规则:
- 源文件名必须与public类名完全匹配(包括大小写)
- 一个.java文件只能有一个public类
三、数据类型深度解析
基本数据类型(8种)
| 类型 | 大小 | 范围/示例 |
|————|————|—————|
| byte | 8位 | -128 ~ 127 |
| short | 16位 | -32768 ~ 32767 |
| int | 32位 | -2^31 ~ 2^31-1 |
| long | 64位 | 需加L后缀:100L
|
| float | 32位 | 需加f后缀:3.14f
|
| double | 64位 | 默认小数类型 |
| char | 16位 |'A'
或 Unicode |
| boolean| - |true/false
|引用数据类型
- 类对象:
String str = "Hello"
- 数组:
int[] arr = new int[5]
- 接口:
List<String> list
- 类对象:
四、变量类型对比
变量类型 | 声明位置 | 生命周期 | 初始化要求 |
---|---|---|---|
局部变量 | 方法/块内 | 方法/块执行期间 | 必须显式初始化 |
实例变量 | 类内方法外 | 对象存在期间 | 自动初始化(0/false/null) |
类变量 | 类内+static | 程序运行期间 | 自动初始化 |
1 | public class VariableDemo { |
五、数组使用详解
声明与初始化
1
2
3
4
5
6// 方式1
int[] arr1 = new int[3]; // [0,0,0]
// 方式2
int[] arr2 = {1, 2, 3};
// 方式3
int[] arr3 = new int[]{1, 2, 3};多维数组
1
2int[][] matrix = new int[3][3];
matrix[0][0] = 1;
六、枚举(Enum)高级用法
1 | public class Pizza { |
七、核心关键字分类说明
如果你要关键字全集点这里
访问控制
private
:仅本类可见protected
:本包+子类可见public
:所有类可见- 默认(不写):本包可见
类与对象
new
:创建对象Dog d = new Dog()
this
:指代当前对象super
:指代父类对象
流程控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// if-else
if(condition) {
// ...
} else if(condition2) {
// ...
} else {
// ...
}
// switch (Java 12+支持表达式形式)
int day = 3;
String dayType = switch(day) {
case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> "Weekend";
default -> "Invalid";
};
八、注释规范
单行注释
1
// 这是单行注释
多行注释
1
2
3
4/*
* 这是多行注释
* 可以跨越多行
*/文档注释(生成API文档)
1
2
3
4
5
6
7
8
9/**
* 计算两个数的和
* @param a 第一个加数
* @param b 第二个加数
* @return 两数之和
*/
public int add(int a, int b) {
return a + b;
}
九、编译与执行流程
完整步骤
1
2
31. 编写HelloWorld.java
2. 编译: javac HelloWorld.java → 生成HelloWorld.class
3. 运行: java HelloWorld常见问题解决
- 编码问题:
javac -encoding UTF-8 HelloWorld.java
- 类路径问题:
java -cp . HelloWorld
- 编码问题:
JVM执行过程
1
源代码(.java) → 编译器 → 字节码(.class) → JVM → 机器码
十、面向对象核心概念
继承示例
1
2
3
4
5
6
7
8
9
10
11class Animal {
void eat() {
System.out.println("Eating...");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Barking...");
}
}接口示例
1
2
3
4
5
6
7
8
9interface Drawable {
void draw(); // 默认public abstract
}
class Circle implements Drawable {
public void draw() {
System.out.println("Drawing circle");
}
}
最佳实践建议
代码风格
- 类名使用大驼峰:
MyClass
- 方法名使用小驼峰:
myMethod()
- 常量全大写:
MAX_COUNT
- 类名使用大驼峰:
调试技巧
- 使用
System.out.println()
进行简单调试 - 学会阅读编译错误信息
- 使用IDE的调试功能(如IntelliJ IDEA)
- 使用
Java注释全面指南
注释是编程中不可或缺的部分,好的注释能极大提升代码可读性和可维护性。下面我将详细讲解Java中的三种注释类型及其最佳实践。
你自己读得懂代码才行啊。
一、注释类型详解
1. 单行注释(Single-line)
语法:// 注释内容
特点:
- 从
//
开始到行尾 - 适用于简短解释或行尾说明
1 | // 计算订单总金额 |
2. 多行注释(Multi-line)
语法:1
2
3
4/*
* 注释内容
* 可以跨越多行
*/
特点:
- 以
/*
开始,*/
结束 - 适合较长的解释说明或临时屏蔽代码块
1 | /* |
3. 文档注释(Javadoc)
这玩意在大型工程基本上才用得到,一般情况用不到
语法:1
2
3
4/**
* 描述信息
* @tag 标签内容
*/
特点:
- 以
/**
开始,*/
结束 - 用于生成正式的API文档
- 支持HTML标签和特殊标记
1 | /** |
二、Javadoc常用标签
标签很重要,但不是现在说的
标签 | 用途 | 适用对象 |
---|---|---|
@param |
方法参数说明 | 方法 |
@return |
返回值说明 | 方法 |
@throws /@exception |
抛出异常说明 | 方法 |
@see |
参考链接 | 类/方法/字段 |
@deprecated |
标记已过时 | 类/方法/字段 |
@since |
引入版本 | 类/方法/字段 |
@version |
版本信息 | 类 |
@author |
作者信息 | 类 |
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/**
* 表示二维点的类
* @author John Doe
* @version 1.2
* @since 2020-03-15
*/
public class Point {
/**
* 计算到另一点的距离
* @param other 另一个点对象
* @return 两点间的距离
* @see Math#sqrt(double)
*/
public double distanceTo(Point other) {
// 实现代码...
}
}
三、注释最佳实践
该注释什么:
- 复杂算法逻辑
- 不直观的设计决策
- 公共API的用法
- 已知问题的临时解决方案
- 特殊业务规则
不该注释什么:
- 自我解释的简单代码
- 重复方法名的信息
- 过时的实现细节
良好注释示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 使用快速排序因为:
// 1. 数据集通常部分有序
// 2. 空间复杂度要求O(log n)
// 3. 基准测试显示比其他算法快15%
sortAlgorithm = new QuickSort();
/**
* 转换日期格式(线程安全版本)
* @deprecated 请使用{@link DateFormatter#formatSafe(Date)}
* 因为发现时区处理问题
*/
public String formatDate(Date date) {
// ...
}注释风格建议:
- 保持注释与代码同步更新
- 使用完整的句子和正确的语法
- 避免幽默或不专业的语言
- 重点说明”为什么”而不是”做什么”
四、生成API文档
使用JDK自带的javadoc工具:1
javadoc -d docs -encoding UTF-8 -sourcepath src com.example.package
常用参数:
-d
:输出目录-encoding
:指定源文件编码-sourcepath
:源代码路径-author
/-version
:包含作者/版本信息
五、特殊注释技巧
调试标记:
1
2// TODO: 需要优化数据库查询
// FIXME: 时区处理有问题条件编译(通过final变量实现):
1
2
3
4
5final boolean DEBUG = false;
if(DEBUG) {
System.out.println("调试信息");
}注释中的代码示例:
1
2
3
4
5
6
7/**
* 使用示例:
* <pre>{@code
* List<String> list = new ArrayList<>();
* list.add("item");
* }</pre>
*/接下来是很重要的一个部分
Java对象和类深度解析
面向对象编程(OOP)是Java的核心思想,下面我将从实际开发角度,通过丰富的示例详细讲解Java中类和对象的各个方面。
一、类与对象全面解析
Java 作为一种面向对象的编程语言,支持以下基本概念:
概念解释和简单示例
1、类(Class):
定义对象的蓝图,包括属性和方法。
示例:public class Car { … }
构建蓝图:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class Car {// 类名首字母大写
// 属性(特征)
String brand; // 品牌
String color; // 颜色
int year; // 年份
// 行为(功能) 成员方法
void drive() {
System.out.println("Driving...");
}//不带public也可以
//行为(功能) 成员方法
public void stop() {
System.out.println("Stopping...");
}//携带public的成员方法,在其他类中可以直接调用
//如果不带public,在其他类中不能直接调用,需要创建对象,再调用
//为了方便调用,一般都带上public
}
2、对象(Object):
类的实例,具有状态和行为。
示例:Car myCar = new Car();
实例化对象:
1 | // 创建Car类的对象 |
调用对象的时候如果不在同一个类中,需要创建对象,再调用(记得导入包)不导包绝对炸
成员变量和局部变量的区别:
1、定义位置:
- 成员变量:定义在类中,方法外。
- 局部变量:定义在方法中,参数列表或方法体中,包含方法的形参
2、作用域: - 成员变量:从该类的实例被创建时就存在,直到系统销毁这个实例。
- 局部变量:只在定义它的方法中有效,出了方法用不了。
3、默认值: - 成员变量:有默认值,如int为0,boolean为false,String为null。
- 局部变量:没有默认值,必须先定义、初始化才能使用。
4、生命周期: - 成员变量:和对象一样,对象被销毁了就回收了。
- 局部变量:和方法一样,方法被调用,或者方法执行完毕就回收了。
成员变量的生命周期比局部变量的要长
5、内存位置:
- 成员变量:堆内存,new位于堆内存。
- 局部变量:位于栈内存。
3、继承(Inheritance):
继承是用来解决代码复用的问题,方便维护和扩展。
一个类可以继承另一个类的属性和方法。
多个类存在相同的属性和方法时,可以从这些类中派生出一个新类,这个新类能吸收了它们的属性和方法。并能拓展新的能力。
示例:public class Dog extends Animal { … }
- 父类:可以叫做父类,基类,超类。
- 子类:可以叫做子类,派生类,扩展类。
继承的特性
- 子类可以继承父类的属性和方法。(儿子继承爹)
- 子类可以拓展自己的属性和方法。(儿子可以有自己的属性和方法)
- 子类可以重写父类的方法。(儿子可以有自己的方法,但是方法名和父类的方法名一样,方法体不一样)
- 子类可以访问父类的构造方法。(儿子可以有自己的构造方法,但是构造方法名和父类的构造方法名一样,方法体不一样)
想要继承任何东西,名字得不重名,方法名也不重名。并且有最近原则,优先子类的方法。
注意
- 子类不能继承父类的构造方法。(儿子不能有自己的构造方法,但是可以有自己的方法)
- 子类不能继承父类的私有属性和方法。(儿子不能继承爹的隐私)
- 子类可以继承父类的静态属性和方法。(儿子可以继承爹的静态属性和方法)
- 如果子类和父类有同名的属性和方法,子类会覆盖
(重写)
父类的属性和方法。但是子类可以通过super关键字访问父类的属性和方法。(揭老爹老底)
super用法: - 1、super.属性名:访问父类的属性。
- 2、super.方法名():调用父类的方法。
- 3、super():调用父类的构造方法。
重写:
@Override:重写的注解,用于检查方法是否正确重写了父类的方法。
写法如下:1
2
3
4
5//重写的注解,用于检查方法是否正确重写了父类的方法。
public void eat() {
super.eat();//调用父类的方法
System.out.println("在学校食堂");//拓展新的能力
}
方法重写要求:一、方法名参数列表啥的都得一样。二、返回值得小于等于父类的返回值范围。三、访问修饰符的范围大于等于父类的访问修饰符范围。四、抛出的异常的范围小于等于父类的抛出的异常范围。
访问权限大小关系:public > protected > 默认 > private
重写和重载的区别:
- 重写:
继承
体系里面,子类重新编写父类的方法。 - 重载:一个类中有多个方法,方法名相同,参数的个数,顺序,类型不同,返回值类型可以相同也可以不同。
蓝图如下:主要用到的是extends关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41// 人类父类(基类)
class Human {
// 公共属性
protected String name;
protected int age;
// 构造方法
public Human(String name, int age) {
this.name = name;
this.age = age;
}
// 基础方法
public void eat() {
System.out.println(name + "在吃饭");
}
}
// 学生子类(派生类)
class Student extends Human {
// 特有属性
private String school;
// 构造方法(调用父类构造)
public Student(String name, int age, String school) {
super(name, age); // 必须首先调用父类构造
this.school = school;
}
// 特有方法
public void study() {
System.out.println(name + "在学习");
}
// 方法重写
public void eat() {
super.eat(); // 调用父类方法
System.out.println("在学校食堂");
}
}
以上蓝图的main方法如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100public static void main(String[] args) {
// 创建人类对象
Human person = new Human("张三", 30);
person.eat(); // 调用父类方法
System.out.println("----------");
// 创建学生对象
Student student = new Student("李四", 20, "清华大学");
student.eat(); // 调用重写后的方法
student.study(); // 调用子类特有方法
System.out.println("----------");
// 多态:父类引用指向子类对象
Human human = new Student("王五", 22, "北京大学");
human.eat(); // 调用重写后的方法,多态
}
**注意:**`super();`会调用父类的无参构造方法,`this();`会调用本类的无参构造方法。
- 子类构造方法的第一行默认有`super();`,默认会调用父类的无参构造方法。
- 在类的构造方法中,访问另一个构造方法时,`super();`和`this();`不能同时出现。只能出现其中的一个。
- `super();`和`this();`都必须是构造方法的第一行。
**完整案例如下:**
```java
// 人类父类
class Human {
// 公共属性
protected String name;
protected int age;
protected String gender;
// 构造方法
public Human(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 公共方法
public void eat() {
System.out.println(name + "正在吃饭");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
public void introduce() {
System.out.println("我是" + name + ",今年" + age + "岁,性别" + gender);
}
}
// 学生子类
class Student extends Human {
// 特有属性
private String school;
private String studentId;
// 构造方法
public Student(String name, int age, String gender, String school, String studentId) {
super(name, age, gender); // 调用父类构造器
this.school = school;
this.studentId = studentId;
}
// 重写父类方法
public void introduce() {
super.introduce(); // 调用父类方法
System.out.println("我是" + school + "的学生,学号是" + studentId);
}
// 特有方法
public void study() {
System.out.println(name + "正在学习");
}
public void takeExam() {
System.out.println(name + "正在参加考试");
}
}
// 测试类
public class HumanStudentExample {
public static void main(String[] args) {
// 创建人类对象
Human person = new Human("张三", 30, "男");
person.introduce();
person.eat();
System.out.println("----------");
// 创建学生对象
Student student = new Student("李四", 20, "女", "清华大学", "2023001");
student.introduce(); // 调用重写后的方法
student.study(); // 调用子类特有方法
student.sleep(); // 调用继承自父类的方法
}
}
4、封装(Encapsulation):
在面向对象程序设计模式中,封装是隐藏对象的属性和实现细节,仅对外公开接口,然后通过设置属性访问控制级别来控制属性的读写。
将对象的状态(字段)私有化,通过公共方法访问。
示例:
private String name;
public String getName() { return name; }
封装的优点;
1.良好的封装能够减少耦合。(高内聚,低耦合)
2.类内部的结构可以自由修改。
3.可以对成员变量进行更精确的控制。
4.隐藏信息,实现细节。
封装的步骤:
1.将属性私有化,使用private
关键字修饰。
as:private String name;
2.提供公共的(getter和setter)
方法,用于获取和设置属性的值。
sa:1
2
3public String getName() {
return name;
}
你定义一个类,里面的A你不想被人知道,你就把A私有化,然后提供一个公共的方法,让别人可以获取A的值,但是你不能让别人直接修改A的值,你只能通过这个方法来修改A的值。
说人话就是《在外面身份是自己给的》
一般用private修饰属性,用public修饰方法。
私有的属性只能在本类中访问,其他类中不能访问。
公共的方法可以在其他类中访问私有属性。
this关键字
this关键字用于区分局部变量和成员变量的同名问题。
如果局部变量和成员变量的名字相同,那么在方法中访问的是局部变量,
就像这样的情况:(若是不使用this会赋值失败)1
2
3
4
5
6
7
8
9
10
11
12public class Person {
private String name;
private int age;
public void setName(String name) {
this.name = name;//可以看见形参变量名和成员变量名一样
}
public void setAge(int age) {
this.age = age;//可以看见形参变量名和成员变量名一样
}
}
封装例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// 定义一个Person类
public class Person {
// 私有属性
private String name;
private int age;
//使用一对getXX()/setXX()方法分别获取和设置这些属性的值,并且对属性进行了封装和隐藏。
//getter方法用于获取属性的值,setter方法用于设置属性的值。
// 公共方法(getter和setter)
public String getName() {
return name;
} //获取name属性的值
public void setName(String name) {
this.name = name;//this关键字表示当前对象,可以省略
} //设置name属性的值
public int getAge() {
return age;
} //获取age属性的值
public void setAge(int age) {
if (age > 0 && age < 150) {
this.age = age;//this关键字的作用是区分局部变量和成员变量的同名问题。
//如果局部变量和成员变量的名字相同,那么在方法中访问的是局部变量,
} else {
System.out.println("您是死灵法师还是练气大成!?");
}
} //设置age属性的值
}
在main中调用:
1 | public class Main { |
5、多态(Polymorphism):
对象可以表现为多种形态,主要通过方法重载和方法重写实现。
示例:
方法重载:public int add(int a, int b) { … } 和 public double add(double a, double b) { … }
方法重写:@Override public void makeSound() { System.out.println(“Meow”); }
详情建议见java快速学习速查5
6、抽象(Abstraction):
抽象方法:没有方法体的定义
抽象类:包含抽象方法的类,如果一个类有一个抽象方法,那么这个类就是个抽象类,得在类定义上加上abstract
关键字。
抽象的使用:
如果该类是个抽象类,他有两个选择
- 要么实现父类所有的抽象方法
- 要么子类也作为一个抽象类
警告:最终必须有子类实现父类的所有抽象方法,不然必然报错1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public abstract class Animal {
public abstract void eat();
// 如果一个类中有一个抽象方法,那么这个类必须是抽象类
}
public class Dog extends Animal {
public void eat() {
System.out.println("狗是杂食动物,喜欢吃骨头");
}
}
public class Test {
public static void main(String[] args) {
Dog d =new Dog();
d.eat();
}
}
使用抽象类和接口来定义必须实现的方法,不提供具体实现。
示例:
抽象类:public abstract class Shape { abstract void draw(); }
接口:public interface Animal { void eat(); }
抽象类的总结(面试题)
- 不能实例化:抽象类不能通过new来创建对象,这是因为抽象类通常包含一些没有具体实现的方法(抽象方法),这些方法要在子类中完成
- 抽象类必须被继承:抽象类存在的意义就是为了被继承
- 可以包含抽象方法和非抽象方法:抽象类可以包含抽象方法,也可以包含非抽象方法。
- 子类必须实现所有的抽象方法:如果子类继承了抽象类,那么子类必须实现所有的抽象方法。否则,子类也必须声明为抽象类。
7、接口(Interface):
定义类必须实现的方法,支持多重继承。
示例:public interface Drivable { void drive(); }
8、方法(Method):
接口是一种引用数据类型
,是抽象方法的集合,接口可以理解为一种特殊的类,里面全部是抽象方法,接口是解决java无法使用多继承的一种手段,里面全是抽象方法
接口的定义和类的定义相似,但是使用Intetface
关键字
定义类的行为,包含在类中的函数。
示例:public void displayInfo() { System.out.println(“Info”); }
1
2
3 public interface MyInterFace {
}
说明:接口中的方法默认是public abstract的,也就说,这两个不写的情况也是public abstract。1
2
3
4
5 public interface MyInterFace {
// 接口里面的抽象方法 可以不需要写 public abstract
void method1();
void method2();
}
属性:接口中的属性默认就是public static final的也就是常量
,所以接口中的属性不能被修改。1
2
3
4 public interface MyInterFace {
// CTRL+SHIFT+X 大小写转换
String USERNAME="admin123";
}
接口的使用
接口跟抽象类类似,不能直接实例化,它可以由一个实现类去实现该接口,注意是用的是实现而不能继
承。
注意:
- 实现接口使用implements关键字,继承是使用extends关键。
- 类实现接口就必须实现里面所有的抽象方法,否则它不能定义为实现类。
- 不像继承那样,类实现抽象类还可以同时实现多个接口。
9、方法重载(Method Overloading):
同一个类中可以有多个同名的方法,但参数不同。1
2
3
4
5
6
7
8
9public class MathUtils {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
1. 类(Class)的本质
类是创建对象的模板,它定义了:
- 属性(字段/成员变量):描述对象的状态
- 方法:定义对象的行为
- 构造器:用于初始化对象
定义对象的蓝图,包括属性和方法。
示例:public class Car { … }
1 | /** |
2. 对象(Object)的创建与使用
对象是类的具体实例,创建和使用过程:
类的实例,具有状态和行为。
示例:Car myCar = new Car();**
1 | public class CarTest { |
访问实例变量和方法
通过已创建的对象来访问成员变量和成员方法,如下所示:1
2
3
4
5
6/* 实例化对象 */
Object referenceVariable = new Constructor();
/* 访问类中的变量 */
referenceVariable.variableName;
/* 访问类中的方法 */
referenceVariable.methodName();
使用 Object 类型声明变量只能在编译时访问 Object 类中的方法和属性,但在运行时,你可以通过强制类型转换将其转换为特定类型,以便访问特定类型的方法和属性。
3. 内存模型解析
这是类和对象的内存中的状态解析1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16栈内存(Stack):
- 存储基本类型变量和对象引用
- myCar (引用地址0x100)
- yourCar (引用地址0x200)
堆内存(Heap):
0x100: Car对象 {
brand = "比亚迪"
color = "红色" → 修改为"蓝色"
price = 15.99
}
0x200: Car对象 {
brand = "特斯拉"
color = "白色"
price = 29.99
}
二、构造方法深度探讨
构造方法用于在创建对象时初始化对象,保证对象的数据完整性。
1. 构造方法特点
每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法(自动提供)。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法
- 与类同名
- 无返回类型(连void都没有)
- 可以重载(多个构造方法)构造重载
- 默认提供无参构造(除非显式定义其他构造方法)
- 使用构造方法创建类的对象的时候,构造方法只运行过一次
其实当使用new来实例化对象的时候,类没有自定义构造函数的时候,会自动默认提供一个无参构造函数,但是当类自定义了构造函数的时候,就会使用自定义的构造函数
2. 构造方法示例
1 | public class Student { |
构造方法的重载
如果定义了带参数的构造方法,还想使用无参数构造方法创建对象,就需要在类中显式定义一个无参数构造方法。(如果你还想new,就得手动写一个无参构造函数)
典型案例对照:(标准格式)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46package com.classTestingPackage.Class;
public class Dog {
private String name;
private String color;
private double weight;
//无参构造器
public Dog() {//如果定义了带参数的构造方法,还想使用无参数构造方法创建对象,就需要在类中显式定义一个无参数构造方法。(如果你还想new,就得手动写一个无参构造函数)
}
public void setName(String name) {
this.name = name;
}
public void setColor(String color) {
this.color = color;
}
public void setWeight(double weight) {
this.weight = weight;
}
public String getName(String name) {
return this.name;
}
public String getColor(String color) {
return this.color;
}
public double getWeight(double weight) {
return this.weight;
}
//带参构造器
public Dog(String name, String color, double weight){
this.name = name;
this.color = color;
this.weight = weight;
}
public void show(){
System.out.println("狗狗的盒:姓名:"+ name +",颜色:" + color +",体重:" + weight);
}
}
main函数部分调用示例1
2
3
4
5
6
7
8
9
10
11
12
13public class Test {
public static void main(String[] args) {
//使用带参构造器
Dog a = new Dog("花花公子", "黄色", 32.5);
a.show();
//使用无参构造器
Dog d = new Dog();
d.setName("草草公子");
d.setColor("绿");
d.setWeight(100);
}
}
3. 构造方法使用场景
1 | Student s1 = new Student(); // 使用默认构造器 |
三、封装与访问控制实践
1. 封装原则
- 将字段设为private
- 通过public方法访问
- 在方法中添加业务逻辑
2. 完整封装示例
1 | public class BankAccount { |
四、变量类型全解析
1. 三种变量对比
变量类型 | 声明位置 | 生命周期 | 初始化要求 | 访问方式 |
---|---|---|---|---|
局部变量 | 方法/块内 | 方法/块执行期间 | 必须显式初始化 | 直接访问 |
实例变量 | 类内方法外 | 对象存在期间 | 自动初始化 | 通过对象访问 |
类变量 | 类内+static | 程序运行期间 | 自动初始化 | 类名或对象访问 |
2. 变量使用示例
1 | public class VariableDemo { |
五、方法设计与重载
1. 方法组成要素
1 | [访问修饰符] [static/final/abstract] 返回类型 方法名(参数列表) [throws 异常列表] { |
2. 方法重载最佳实践
1 | public class Calculator { |
六、综合案例:员工管理系统
Employee.java
1 | import java.time.LocalDate; |
EmployeeManagement.java
1 | import java.time.LocalDate; |
七、Java文件组织规范
1. 源文件规则
- 一个
.java
文件只能有一个public
类 - 文件名必须与
public
类名完全一致(包括大小写) - 包声明(
package
)必须位于文件首行 - 导入语句(
import
)位于包声明之后,类定义之前
2. 典型文件结构
1 | // Employee.java |
八、包(package)与导入(import)机制
为了更好的组织和管理Java代码,Java引入了包的概念。包是一种命名空间,用于组织类和接口,其实就行个文件夹。
1. 包的作用
- 把功能相似的或者相关的类和接口组织在同一个包中,方便类的查找和使用。
- 防止命名冲突,当两个类的名称相同时,可以使用完整的包名来区分。
- 包限定了访问权限,拥有访问权限的类才能访问该包中的类和接口。
2. 包命名规范
- 公司域名倒写:
com.company.project
- 要求全部小写
- 不可以使用Java保留字
3. 导入使用技巧
使用import
关键字导入其他包中的类、接口或静态成员,简化代码编写。
1 | import java.util.List; // 导入单个类 |
九、开发建议与常见问题
1. 类设计原则
- 单一职责原则:一个类只做一件事
- 高内聚低耦合:内部紧密相关,外部依赖最少
- 优先使用组合而非继承
- 为所有公开API添加文档注释
2. 常见错误
- 忘记实例化对象:
MyClass obj; obj.method();
→ NullPointerException - 混淆实例变量和局部变量:使用
this
明确指代 - 过度使用静态成员:破坏面向对象特性
- 忽视封装:直接暴露字段
Java基本数据类型全面解析
Java作为一门强类型语言,其数据类型系统是编程基础中的核心。下面我将从实际应用角度,深入讲解Java的基本数据类型。
一、Java数据类型体系
1 | Java数据类型 |
二、八大基本数据类型详解
1. 整数类型
类型 | 位数 | 取值范围 | 默认值 | 包装类 | 应用场景 |
---|---|---|---|---|---|
byte | 8 | -128 ~ 127 | 0 | Byte | 二进制数据、节省空间 |
short | 16 | -32,768 ~ 32,767 | 0 | Short | 较少使用,兼容性考虑 |
int | 32 | -2^31 ~ 2^31-1 (约±21亿) | 0 | Integer | 最常用的整数类型 |
long | 64 | -2^63 ~ 2^63-1 | 0L | Long | 大整数、时间戳 |
代码示例:1
2
3
4byte fileData = -128; // 最小byte值
short pixelValue = 32767; // 最大short值
int population = 2_147_483_647; // 使用下划线增强可读性
long globalPopulation = 7_900_000_000L; // 注意L后缀
2. 浮点类型
类型 | 位数 | 取值范围 | 默认值 | 包装类 | 精度 |
---|---|---|---|---|---|
float | 32 | ±1.4E-45 ~ 3.4028235E38 | 0.0f | Float | 6-7位有效数字 |
double | 64 | ±4.9E-324 ~ 1.7976931348623157E308 | 0.0d | Double | 15位有效数字 |
重要特性:
- 浮点数遵循IEEE 754标准
- 存在舍入误差,不适合精确计算(如金融)
- 默认字面量是double类型
代码示例:1
2
3
4
5
6float piApprox = 3.14159f; // 必须加f后缀
double precisePi = 3.141592653589793;
double scientific = 1.23e10; // 科学计数法
// 浮点精度问题演示
System.out.println(0.1 + 0.2); // 输出0.30000000000000004
3. 字符类型(char)
- 16位Unicode字符
- 范围:\u0000 ~ \uffff(0~65535)
- 默认值:’\u0000’
- 包装类:Character
特殊表示方式:1
2
3char letterA = 'A'; // 直接字符
char unicodeChar = '\u0041'; // Unicode表示(也是'A')
char tab = '\t'; // 转义字符
4. 布尔类型(boolean)
- 只有true和false两个值
- 默认值:false
- 包装类:Boolean
- 大小:JVM规范未明确定义(通常按int处理)
注意事项:1
2
3boolean isJavaFun = true;
// if(isJavaFun == true) // 不推荐写法
if(isJavaFun) // 推荐写法
三、类型转换机制
1. 自动类型转换(隐式转换)
转换方向:低精度 → 高精度
1 | byte → short → int → long → float → double |
转换规则:
- 两种类型兼容
- 目标类型范围大于源类型
示例:1
2
3int i = 100;
long l = i; // 自动转换
float f = l; // 可能丢失精度(但自动转换)
2. 强制类型转换(显式转换)
语法:(目标类型)值
风险点:
- 数据溢出
- 精度丢失
- 非兼容类型转换
示例:1
2
3
4
5double d = 100.04;
long l = (long)d; // 截断小数部分,l=100
int i = (int)l; // 安全转换
byte b = (byte)128; // 溢出!b=-128
3. 特殊转换场景
char与整型的转换:1
2
3char c = 'A';
int i = c; // 自动转换,i=65
char c2 = (char)(i + 1); // c2='B'
布尔类型限制:1
2// boolean cannot = 1; // 错误!
// int number = true; // 错误!
四、类型默认值与内存分配
1. 默认值规则
数据类型 | 默认值 |
---|---|
byte/short/int/long | 0 |
float/double | 0.0 |
char | ‘\u0000’ |
boolean | false |
引用类型 | null |
示例验证:1
2
3
4
5
6
7
8
9
10
11
12
13public class DefaultValues {
static int intValue;
static boolean boolValue;
public static void main(String[] args) {
System.out.println(intValue); // 输出0
System.out.println(boolValue); // 输出false
// 局部变量必须初始化
// int localInt; // 编译错误
// System.out.println(localInt);
}
}
2. 内存占用分析
类型 | 大小 | 备注 |
---|---|---|
boolean | ~1字节 | JVM依赖,通常按int处理 |
byte | 1字节 | |
short | 2字节 | |
char | 2字节 | UTF-16编码 |
int | 4字节 | |
float | 4字节 | |
long | 8字节 | |
double | 8字节 |
数组内存计算示例:1
int[] arr = new int[100]; // 占用约100*4=400字节
五、包装类与自动装箱拆箱
java在设计类时为每个基本数据类型设计了一个对应的类,这8个类对应这8个基本数据类型统称为包装类。这些包装类都位于java.lang包下。
包装类:
- 每个基本类型都有对应的包装类
- 包装类提供了更多功能,如与字符串的转换
- 包装类对象可以为null,int不能为null
1. 基本类型与包装类对应
基本类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
1 | // byte的包装类 |
1.集合不允许存放基本数据类型,用包装类。
2.包含了每种基本类型的相关属性,和方法。
3.作为基本数据类型对应的包装类对象,提供了一系列使用的对象操作,比如类型转换,进行转换等等。
基本类型转换为包装对象的两种方式1
2
3
4
5
6
7
8
9// 基本类型转换为包装对象的两种方式
Integer i=new Integer(12);
Integer k = Integer.valueOf(23);
// Integer包装类对象转换int
int l = i.intValue();
// 将数值的字符串转换为Integer包装类对象
Integer int5=new Integer("123");
System.out.println(int5.intValue());
System.out.println(Integer.MAX_VALUE);
2. 自动装箱/拆箱机制
1 | // 自动装箱 |
这里是对照部分展示
自动装箱1
2
3
4
5// 把int转换成Integer
Integer i1=new Integer(1); //Integer i3=12;
Integer i2 = Integer.valueOf(12); //Integer i3=12;
// 自动装箱
Integer i3=12;
自动拆箱1
2
3
4
5
6Integer i=1; // 自动装箱 Integer i1=new Integer(1);
/**
* 等号右边将i对象转换基本数值 i.intValue()+5;
* 加法运算完成后,再次装箱,把基本数据类型转换对象
**/
i+=i+5;
面试题:基本数据类型和包装类有什么区别?
1.默认值
基本数据类型:有默认值,比如int的默认值0
包装类:默认是null,因为他们是引用数据类型
2.功能差异
基本数据类型:没有方法和属性,主要用于数值计算。
包装类:包含了一系列的属性和方法。
3.存储方式
基本数据类型:直接在栈内存中分配空间,存储的是具体的值。
包装类:他们是类,所以是对象在堆内存中分配空间。
注意事项:
- 包装类对象可能为null,拆箱时可能引发NullPointerException
- 整数缓存:-128~127的Integer对象会被缓存
1 | Integer a = 127; |
六、类型相关工具方法
1. 类型大小与极值
1 | System.out.println("int范围:" + Integer.MIN_VALUE + "~" + Integer.MAX_VALUE); |
2. 类型转换工具
1 | // 字符串转数字 |
3. 数学运算工具
1 | // 安全运算 |
七、最佳实践与常见问题
1. 类型选择建议
- 整数:优先使用int,大数用long
- 小数:优先使用double,除非内存敏感
- 布尔:避免用其他类型模拟boolean
- 字符:明确需要单个字符时才使用char
2. 常见陷阱
浮点数比较:1
2
3
4
5// 错误方式
if (d1 == d2) {...}
// 正确方式
if (Math.abs(d1 - d2) < 1e-6) {...}
大数溢出:1
2
3
4
5
6// 错误:发生溢出
int million = 1000000;
int result = million * million; // -727379968
// 正确:使用long
long result = (long)million * million;
自动装箱性能:1
2
3
4
5
6
7
8// 低效(创建多余对象)
Integer sum = 0;
for (int i=0; i<10000; i++) {
sum += i; // 反复装箱拆箱
}
// 高效
int sum = 0;
3. 特殊值处理
1 | // 浮点特殊值 |