Java是一门面向对象的编程语言,所谓的面向对象,简单的说,就是在软件开发过程中,用各种各样的对象实现所需功能。
对象就好像是现实世界中不计其数的物体,根据物体的性质可以将其进行分门别类:石头、锤子、房子、汽车、空气、土地、大树等等。
同样,在Java世界中,一个对象必定属于某一个类,一个类下可以有无数个对象。
对同一类对象的性质和功能进行抽象描述的就是类class
,类就是对象的种类
。
不过,和现实世界中的分门别类不同,现实世界的类是抽象的、是虚拟的,是人类大脑思维的结果,先有实际存在的物体,后有人类对其分类。而在Java世界,必须先有类的定义,然后创建对象。
一,类的作用
类的主要作用是作为一种蓝图或模板,用于实例化对象。
它定义了对象的状态(即数据成员,如变量)和行为(即成员方法,如函数)。
通过类,我们可以实现代码的复用、封装和抽象,进而提高软件的可维护性和可扩展性。
二,类如何声明
1,定义格式
基本的类定义格式如下:
[访问修饰符] class 类名 {
// 成员变量(属性)
[修饰符] 数据类型 变量名;
// 构造函数
[修饰符] 类名([参数列表]) {
// 初始化代码
}
// 成员方法(行为)
[修饰符] 返回类型 方法名([参数列表]) {
// 方法体
}
}
```java
// 类的定义
public class Person {
// 成员变量
private String name;
private int age;
// 默认构造函数
public Person() {
System.out.println("默认构造函数被调用");
}
// 有参构造函数
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造函数被调用");
}
// 成员方法
public void displayInfo() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
2,类的访问修饰符及其作用
我们知道,方法的访问修饰符有四种:
public
:表示可以被任何其他类访问private
:限制访问权限仅限于定义它的类内部protected
:允许同一包内的类以及所有子类访问- 默认(无修饰符):仅对同一包内的类可见
需要注意的是,类的访问修饰符只有两种
:
public
:表示可以被任何其他类访问,public类名必须和文件名一致默认
(无修饰符):仅对同一包内的类可见,其他包下的类访问时会报错,如DefaultClass
:
注意:一个文件多个类
一个Java源文件可以包含多个类,但有以下限制:
- 只能有一个public类,且该类的名称必须与文件名相同
- 其他非public类可以有多个,但它们只能在同一包内访问,本质是
默认类
最佳实践:一个文件定义一个类
3,类命名的最佳实践
在Java编程中,类名的选择不仅关乎代码的可读性和维护性,也是遵循编程规范的重要体现。以下是一些关于Java类名的最佳实践原则:
-
驼峰命名法:始终使用驼峰命名法(CamelCase),即每个单词的首字母大写,其余字母小写,不使用下划线。例如,
MyClass
,而不是my_class
。 -
明确性:类名应当直接、明了地反映出类的功能或所代表的实体。避免使用模糊的名称,如
Manager
、Util
或Data
,而应该具体到实际的管理对象、工具用途或数据类型,如UserManager
、TextUtility
、WeatherData
。 -
名词优先:由于类通常代表实体、对象或抽象概念,因此类名最好是名词或名词短语,避免使用动词。如果需要表达行为或操作,这应该体现在方法名上。
-
避免缩写:除非是广泛认可的缩写(如URL、HTML),否则尽量避免使用缩写,因为缩写可能会造成理解上的困难。全称更有利于代码的自解释性,如使用
ApplicationSettings
而非AppSet
。 -
一致性:在整个项目或组织中保持类命名的一致性。一旦确定了某种命名规则或模式,应在其间保持一致,比如是否使用复数形式表示集合类(如
UsersList
vsUserList
)。 -
区分抽象类与接口:虽然在语法上没有硬性规定,但可以通过命名来暗示一个类是抽象的(如
AbstractLogger
)或者是一个接口(通常以I
开头,如ILogger
,但这更多是C#中的习惯,在Java中并不常见)。 -
长度适中:类名应该足够长以表达其含义,但也要避免过长以至于阅读不便。找到一个平衡点,通常情况下,三到四个单词组成的名称是比较合理的。
-
遵循框架或库的命名约定:如果你的项目依赖于特定的框架或库,最好遵循它们推荐的命名约定,以保持代码风格的一致性。
三,类的构成部分
类主要由以下三部分构成:
- 成员变量:描述类的属性,可以是基本数据类型或对象引用
- 构造函数:用于初始化对象,创建对象时自动调用
- 成员方法:定义类的行为,可以操作成员变量,实现特定功能
四,成员变量
Java类中的成员变量代表了类的属性或状态,变量存储了对象的数据。
1,如何声明成员变量
成员变量的声明包括访问修饰符、可选的其他修饰符(如static、final)、变量类型和变量名。基本语法如下:
[访问修饰符] [其他修饰符] 类型 变量名;
[]
包裹的部分表示可选,语法上可有可无。
2,访问修饰符
成员变量的访问修饰符和方法的访问修饰符一致:
-
public
:任何地方都能访问,包括在本类,同包下其他类,不同包下的类 -
protected
:同包内及子类可以访问,注意,不同包下的子类可以直接访问父类的protected
变量,但不能通过父类的对象访问protected
变量
-
private
:仅在定义它的类内部可以访问 -
不写(默认)
:仅在同一个包内的类可以访问
3,其他修饰符:
static
:表明这是一个类变量,属于类本身,而不属于类的某个实例,类中定义的static变量,在其他类中可以通过类名直接访问,不需要先创建类的对象
final
:表示变量的值一旦设定就不能再改变,即常量,修改final类型的变量会在编译时报错
4,类型:指定变量的数据类型,可以是基本数据类型(如int
, double
)或引用类型(如String
, Object
)
5,变量名的最佳实践
- 见名知意:变量名应清楚地表达其存储的信息或目的,如
firstName
而非fn
- 驼峰命名:每个单词首字母大写,如
studentName
- 避免缩写:除非是广为人知的缩写,否则应完整拼写,如
numberOfStudents
而非numStds
- 区分大小写:Java是区分大小写的,确保命名准确无误
- 避免保留字和关键字:不要使用Java的保留字作为变量
6,成员变量的最佳实践
-
封装:尽可能使用
private
访问修饰符来隐藏类的内部实现细节,通过公共的getter和setter方法来控制对成员变量的访问。 -
最小权限原则:给成员变量赋予最小必要的访问权限,减少耦合度和潜在的错误。
-
初始化:考虑为成员变量提供合适的默认值,特别是在没有构造函数的情况下。
-
使用final关键字:当成员变量的值不应改变时,使用
final
关键字将其声明为常量。
五,构造函数
1,定义
构造函数是一种特殊的方法,用于初始化新创建的对象。
构造函数的两个规范:
- 构造函数的名称必须与类名完全相同
- 没有返回类型(即使是void也不行,void修饰后就成为普通成员方法)
2,类别
- 默认构造函数:默认构造函数也称为无参构造函数,可以在类中显式声明,也可以缺省。如果类中没有显式定义任何构造函数,编译器会自动提供一个无参的默认构造函数,且这个默认构造函数的函数体是空的
- 有参构造函数:可以接收参数,用于初始化对象时设置初始值
代码示例
// 类的定义
public class Person {
// 成员变量
private String name;
private int age;
// 默认构造函数
public Person() {
System.out.println("默认构造函数被调用");
}
// 有参构造函数
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造函数被调用");
}
// 成员方法
public void displayInfo() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
// 主类进行测试
public class Main {
public static void main(String[] args) {
// 使用无参构造函数创建对象
Person person1 = new Person();
// 使用有参构造函数创建对象
Person person2 = new Person("Alice", 30);
person1.displayInfo(); // 输出默认值或空值,取决于成员变量的初始化
person2.displayInfo(); // 输出:Alice, 30
}
}
3,构造函数有什么用?
构造函数通常用于创建对象进行一些初始化工作。
比如银行账户类BankAccount
,这个类需要记录账户持有者的名字、账号以及初始余额。
显然一个银行账户创建时,就应该明确这个账户的所有者、账号、初始余额,构造函数中可以完成相应的初始化工作:
public class BankAccount {
private String accountHolderName; // 账户持有者名字
private String accountNumber; // 账号
private double balance; // 余额
// 无参构造函数
public BankAccount() {
this("未知", "0000000000", 0.0); // 调用另一个构造函数进行初始化
}
// 带参数的构造函数,用于初始化账户信息
public BankAccount(String accountHolderName, String accountNumber, double balance) {
// 进行参数有效性检查
if (accountHolderName == null || accountNumber == null || accountNumber.isEmpty() || balance < 0) {
throw new IllegalArgumentException("非法的账户信息");
}
// 初始化成员变量
this.accountHolderName = accountHolderName;
this.accountNumber = accountNumber;
this.balance = balance;
}
// 其他方法,如存款、取款等略...
// Getter和Setter方法略...
}
public class Main {
public static void main(String[] args) {
// 使用无参构造函数创建默认账户
BankAccount defaultAccount = new BankAccount();
System.out.println(defaultAccount.getAccountHolderName()); // 输出:未知
// 使用带参数的构造函数创建账户
try {
BankAccount myAccount = new BankAccount("张三", "1234567890", 1000.0);
System.out.println(myAccount.getAccountHolderName()); // 输出:张三
System.out.println(myAccount.getBalance()); // 输出:1000.0
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}
在这个例子中,BankAccount
类定义了两个构造函数:一个是无参构造函数,它默认初始化账户持有者名为“未知”,账号为一串零,余额为0;另一个构造函数接受三个参数,用于初始化账户的具体信息。
在带参数的构造函数中,还包含了对输入参数的合法性检查,如果提供的参数不合法(如负数余额),则抛出异常,阻止创建不合法的账户对象。
六,成员方法
点击这里查看成员方法的详细说明