首先安装好idea和jre
1创建第一个java文件:HelloWorld
1.1再scr目录下创建一个pakeage(com.example.name)
在Java中,通常会使用包(package)来组织类文件。包名通常是小写字母,可以是单个词或多个词(通过点分隔)。例如,com.example.project
。
为什么需要package
- 避免命名冲突: 当不同的开发者或组织开发功能类似的类时,包可以帮助区分属于不同项目或模块的同名类。
- 管理权限: 包可以帮助控制类和类成员的可见性(例如使用
public
,protected
, 和private
)。 - 维护性: 包提供了一个逻辑分层的结构,使得大型项目的管理更为方便。
创建包并在包内创建类是一种良好的编程实践,有助于代码的组织和维护。确保项目结构清晰有助于随着项目规模的扩大,维持代码的可管理性。
1.2创建一个class
- 现在,在新创建的包(即新的文件夹)内,右键点击。
- 选择
New
>Java Class
。 - 在弹出的对话框中输入您的类名,例如
HelloWorld
。按 Enter 确认。- 这会在
com/example/name
文件夹内创建一个名为HelloWorld.java
的文件。
- 这会在
这样,就可以再类中创建第一个代码"HelloWorld"了。
package com.example.myapp; // 这行声明了类所在的包
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
为什么需要类
在Java中,class
关键字用来定义一个类,它是Java编程语言中面向对象编程的核心概念之一。理解类的重要性和功能是理解Java和面向对象编程的基础。以下是类的一些基本功能和为什么它们在Java中如此重要:
1. 封装(Encapsulation)
类提供了封装的机制,允许将数据(属性)和与数据相关的方法(行为)封装在一个单独的实体(对象)中。这有助于将信息隐藏在对象内部,只允许通过定义好的接口(即公共方法)访问,从而减少系统的复杂性并提高安全性。
2. 继承(Inheritance)
类支持继承,这意味着你可以创建一个新类基于一个已存在的类。新类(称为子类)继承了父类的属性和方法,可以添加新的属性和方法或覆盖现有的方法。这促进了代码的重用,提高了代码的可维护性和扩展性。
3. 多态(Polymorphism)
类允许多态性,这是面向对象程序设计中的一个关键特性。多态允许方法或对象具有多种形态。它允许你通过父类引用调用子类的方法,具体的行为取决于引用的对象的实际类型。这使得程序更加灵活和可扩展。
4. 创建对象(Instantiation)
类是对象的蓝图或模板。你可以使用类来创建(实例化)对象。每个对象将拥有类中定义的属性和方法。这允许程序员使用类多次创建数百万个对象,每个对象都具有相同类型的属性和行为但保持独立的状态。
5. 组织和模块化(Organization and Modularity)
类提供了一种很好的方式来组织和模块化代码。它们允许你将程序划分为独立的、可管理的、逻辑上相关的单元。每个类可以被单独开发和测试,减少了整体编程错误的风险,并提高了代码的可读性和可维护性。
6. 接口实现(Implementing Interfaces)
在Java中,类可以实现接口。接口是一种规范,它定义了一组方法,但不提供这些方法的实现。一个类通过实现接口来承诺提供这些方法的具体实现。这是一种设计策略,用于定义对象应具有的功能,同时保留实现细节的灵活性。
总之,类是Java编程中实现抽象、封装、继承和多态性的基础,是构建和扩展应用程序的基石。通过使用类,Java开发人员可以创建灵活、可维护和高效的应用程序。
public static void main(String[] args)
是Java程序的主入口点。每个Java应用程序都需要这个方法来运行。我们可以逐部分解释这个方法的各个组成部分:
1. public
这是一个访问修饰符,public
意味着这个方法可以从任何地方被访问,不受限制。这对于程序的主入口点是必要的,因为它需要被Java运行时环境(JRE)调用,无论这个方法位于什么位置。
2. static
static
关键字意味着这个方法是静态的,它可以在没有创建类实例的情况下直接被调用。由于 main
方法在程序启动时被调用,此时还没有任何对象被创建,因此它必须是静态的,以便可以直接通过类而非类的实例来调用。
3. void
这表示 main
方法没有返回值。void
是Java中表示无返回类型的关键字。
4. main
这是方法的名称,Java程序的执行入口是通过调用名为 main
的方法实现的。这个名称在Java中是特别规定的,用来指示程序的开始点。
5. String[] args
这表示 main
方法接收一个参数,即 args
,它是一个 String
类型的数组。这个数组包含了在启动程序时传递给程序的命令行参数。例如,如果你在命令行中运行 java MyClass arg1 arg2
,那么 args
数组将包含 ["arg1", "arg2"]
。
用途和重要性
- 用途: 主要用于程序的启动,也是程序接收命令行参数的地方。
- 重要性: 没有这个方法,Java应用程序将无法启动和运行。
这个方法的标准形式对于所有Java应用程序是必须的,除非程序是由其他Java程序、Web服务或其他特殊方式启动的(例如在一个Web服务器环境中)。对于大多数独立运行的Java应用程序,main
方法是必须的。
2.Java基础语法
数据类型
在Java中,数据类型主要分为两大类:基本数据类型和引用数据类型
1. 基本数据类型
基本数据类型直接存储数值,它们在内存中占用固定大小的空间。Java定义了八种基本数据类型,分为四类:
-
整数类型:
byte
:占用1字节(8位),范围从-128到127。short
:占用2字节(16位),范围从-32,768到32,767。int
:占用4字节(32位),范围从-2^31到2^31-1,是Java中最常用的整数类型。long
:占用8字节(64位),范围从-2^63到2^63-1,用于存储大整数。
-
浮点类型(用于表示有小数部分的数值):
float
:占用4字节(32位),提供约6-7位有效数字。double
:占用8字节(64位),提供约15位有效数字,是默认的浮点数类型。
-
字符类型:
char
:占用2字节(16位),用于存储单个字符(如 'A'、'3'、'%'),基于Unicode编码。
-
布尔类型:
boolean
:表示逻辑值true
或false
。虽然实际大小依赖于虚拟机,但通常非常小。
2. 引用数据类型
引用数据类型包括类、数组、接口等,它们引用的是内存中的对象。引用数据类型的变量存储的实际上是对象在内存中的地址。
变量声明和初始化
变量声明
在Java中,每个变量在使用前都必须声明,声明时需要指定变量的类型和名称。
int age; // 声明了一个整型变量名为age
double price; // 声明了一个双精度浮点型变量名为price
boolean isJavaFun; // 声明了一个布尔型变量名为isJavaFun
初始化变量
初始化是指在声明变量时或之后给变量赋值。
int age = 25; // 声明并初始化整型变量age
double price = 19.99; // 声明并初始化浮点型变量price
boolean isJavaFun = true; // 声明并初始化布尔型变量isJavaFun
运算符
算术运算符
+
:加法-
:减法*
:乘法/
:除法%
:求余数,返回两数相除的余数。
比较运算符
==
:等于!=
:不等于>
:大于<
:小于>=
:大于等于<=
:小于等于
逻辑运算符
&&
:逻辑与,两个条件都为true结果才为true。||
:逻辑或,两个条件中至少一个为true结果就为true。!
:逻辑非,反转条件的真值。
public class Main {
public static void main(String[] args) {
int a = 5, b = 3;
boolean result;
// 算术运算
System.out.println("a + b = " + (a + b)); // 输出 8
System.out.println("a - b = " + (a - b)); // 输出 2
System.out.println("a * b = " + (a * b)); // 输出 15
System.out.println("a / b = " + (a / b)); // 输出 1
System.out.println("a % b = " + (a % b)); // 输出 2
// 比较运算
result = (a == b); // false
System.out.println("a == b is " + result);
result = (a != b); // true
System.out.println("a != b is " + result);
// 逻辑运算
result = (a > 1 && b < 5); // true
System.out.println("a > 1 && b < 5 is " + result);
result = (a < 1 || b < 5); // true
System.out.println("a < 1 || b < 5 is " + result);
result = !(a < 1); // true
System.out.println("!(a < 1) is " + result);
}
}
3.流程控制语句
在Java中,控制流程语句用于控制程序执行的顺序,根据不同的条件执行不同的代码块。控制流程语句主要包括条件语句、循环语句和选择语句。
条件语句(if, else-if, else)
条件语句用于基于一个或多个条件执行不同的代码块。
- if语句:如果条件为真(true),则执行大括号内的代码。
- else-if语句:可以跟在if语句后,如果if的条件为假(false)且else-if的条件为真,执行else-if内的代码。
- else语句:跟在if或else-if之后,如果所有前面的条件都不为真,执行else内的代码。
int score = 85;
if (score >= 90) {
System.out.println("Excellent");
} else if (score >= 75) {
System.out.println("Good");
} else {
System.out.println("Needs Improvement");
}
三元运算符是一种简洁的if-else
语句形式,适用于简单的条件判断和赋值操作。其语法是:condition ? expr1 : expr2
。
int score = 85;
String result = (score >= 75) ? "Pass" : "Fail";
System.out.println(result);
循环语句(for, while, do-while)
循环语句用于重复执行一段代码直到满足特定条件。
- for循环:在循环开始前初始化变量,定义循环继续的条件,以及每次循环结束时的操作。
- while循环:只要循环的条件为真,循环就会继续执行。
- do-while循环:类似while循环,但至少执行一次,因为条件检查在循环的末尾。
for (int i = 0; i < 5; i++) {
System.out.println("i = " + i);
}
int j = 0;
while (j < 5) {
System.out.println("j = " + j);
j++;
}
int k = 0;
do {
System.out.println("k = " + k);
k++;
} while (k < 5);
如何选择for
循环和while
循环?
for
循环适用于已知循环次数的情况,而while
循环适用于循环次数不确定,但需要满足特定条件的情况。
do-while
循环和while
循环的区别是什么?
do-while
循环至少执行一次,因为条件检查在循环体之后,而while
循环可能一次也不执行,因为条件检查在循环体之前。
// do-while循环示例
int k = 0;
do {
System.out.println("k = " + k);
k++;
} while (k < 5);
// while循环示例
int l = 0;
while (l < 5) {
System.out.println("l = " + l);
l++;
}
如何提前退出循环(使用break
和continue
)?
答案:
break
语句用于提前退出循环。continue
语句用于跳过当前循环迭代并开始下一次迭代。
// 使用break退出循环
for (int i = 0; i < 10; i++) {
if (i == 5) {
break;
}
System.out.println("i = " + i);
}
// 使用continue跳过当前迭代
for (int j = 0; j < 10; j++) {
if (j % 2 == 0) {
continue;
}
System.out.println("j = " + j);
}
switch语句
switch语句用于基于不同的case执行不同的代码块。通常用于变量有多个固定选项时,作为if-else语句的一个更清晰的替代。
int day = 4;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
case 4:
System.out.println("Thursday");
break;
case 5:
System.out.println("Friday");
break;
case 6:
System.out.println("Saturday");
break;
case 7:
System.out.println("Sunday");
break;
default:
System.out.println("Invalid day");
}
switch
语句中break
的重要性是什么?
break
语句用于终止switch
语句中的当前代码块,并防止执行后续的case
标签。如果没有break
,程序会继续执行后续的case
代码,直到遇到break
或switch
语句结束。
int number = 2;
switch (number) {
case 1:
System.out.println("One");
case 2:
System.out.println("Two");
case 3:
System.out.println("Three");
default:
System.out.println("Default");
}
Two
Three
Default
因为case 2
没有break
,程序继续执行case 3
和default
代码块。
switch
语句和if-else
语句的区别和适用场景?
switch
语句适用于检查一个变量是否等于一系列整数、枚举、字符串或字符的情况。它使代码更清晰和易于阅读。if-else
语句适用于更复杂的条件判断,可以处理任意的布尔表达式。
小案例
编写一个Java程序来模拟一个简单的计算器。要求如下:
- 使用
Scanner
类读取用户的输入。 - 用户可以选择加、减、乘、除四种运算。
- 用户输入两个数。
- 输出结果。
- 使用switch语句处理不同的运算选择。
import java.util.Scanner;
public class SimpleCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter first number:");
double firstNumber = scanner.nextDouble();
System.out.println("Enter second number:");
double secondNumber = scanner.nextDouble();
System.out.println("Choose an operation (+, -, *, /):");
char operation = scanner.next().charAt(0);
double result;
switch (operation) {
case '+':
result = firstNumber + secondNumber;
break;
case '-':
result = firstNumber - secondNumber;
break;
case '*':
result = firstNumber * secondNumber;
break;
case '/':
if (secondNumber != 0) {
result = firstNumber / secondNumber;
} else {
System.out.println("Cannot divide by zero");
return;
}
break;
default:
System.out.println("Invalid operation");
return;
}
System.out.println("The result is: " + result);
}
}
4.数组和字符串详细教学
1. 数组详解
a. 单维数组
数组是用来存储固定数量的相同类型数据的集合。在Java中,数组也是一个对象。
示例代码:
int[] ages = new int[5]; // 声明一个整数数组,容量为5
ages[0] = 18; // 初始化数组的第一个元素
for (int i = 0; i < ages.length; i++) {
System.out.println("Age " + (i+1) + ": " + ages[i]);
}
b. 数组的初始化
数组可以在声明时直接初始化。
double[] scores = {9.5, 8.9, 7.6, 9.8, 8.8}; // 声明并初始化一个浮点数数组
c. 多维数组
多维数组在Java中通常用于表示表格数据,如矩阵。
示例代码:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}; // 创建一个3x3的矩阵
Java中如何复制数组?有哪些方式?
1.**使用循环复制:**最直接的方式,通过循环遍历原数组,将元素复制到新数组。
2.**System.arraycopy方法:**Java提供的方法,可以更快速地复制数组。
int[] src = {1, 2, 3, 4, 5};
int[] dest = new int[5];
System.arraycopy(src, 0, dest, 0, src.length);
3.**Arrays.copyOf:**另一种简洁的数组复制方法,返回复制的新数组。
int[] copied = Arrays.copyOf(src, src.length);
创建一个包含10个元素的数组,使用System.arraycopy
和Arrays.copyOf
两种方法分别复制这个数组,然后打印复制的数组。
import java.util.Arrays;
public class ArrayCopyDemo {
public static void main(String[] args) {
// 创建并初始化一个包含10个元素的数组
int[] originalArray = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
// 使用System.arraycopy方法复制数组
int[] copiedArray1 = new int[10]; // 创建一个新数组用于复制
System.arraycopy(originalArray, 0, copiedArray1, 0, originalArray.length);
System.out.println("使用System.arraycopy复制的数组: " + Arrays.toString(copiedArray1));
// 使用Arrays.copyOf方法复制数组
int[] copiedArray2 = Arrays.copyOf(originalArray, originalArray.length);
System.out.println("使用Arrays.copyOf复制的数组: " + Arrays.toString(copiedArray2));
}
}
2. 字符串详解
a. 字符串的不可变性
在Java中,字符串是不可变的,即字符串一旦被创建,它的值就不能被改变。
b. 常用字符串方法
String s = "Hello World";
System.out.println("长度: " + s.length()); // 返回字符串的长度
System.out.println("转小写: " + s.toLowerCase()); // 将字符串转换为小写
System.out.println("包含检查: " + s.contains("World")); // 检查字符串中是否包含子字符串
System.out.println("字符位置: " + s.indexOf('o')); // 返回指定字符首次出现的字符串内的索引
System.out.println("替换字符: " + s.replace('l', 'p')); // 替换字符串中的字符
方法和封装
1. 定义方法
方法在Java中是执行特定任务的代码块。方法可以带有参数,并可以返回一个值。
public class Calculator {
// 定义一个方法来计算两个整数的和
public int add(int num1, int num2) {
return num1 + num2;
}
public static void main(String[] args) {
Calculator calc = new Calculator();
int result = calc.add(5, 3);
System.out.println("Sum: " + result);
}
}
在Java中,Calculator calc = new Calculator();
这行代码实际上是做了几件事情:
-
类型声明:
Calculator
指定了calc
变量可以存储的对象类型,即它声明calc
是Calculator
类型的。这告诉Java编译器和运行时系统,calc
将具有Calculator
类的所有属性和行为。 -
变量命名:
calc
是变量的名字。这是你将用来引用存储在该变量中的Calculator
对象的名字。 -
对象实例化:
new Calculator()
创建了Calculator
类的一个新实例。new
是一个特殊的Java关键字,用于创建类的新对象。它调用了Calculator
类的构造器(构造函数),这是一个特殊的方法,用于初始化新对象。 -
赋值操作:
=
是赋值运算符,它将new Calculator()
创建的新对象的引用赋给了calc
变量。这意味着之后你可以通过calc
访问该对象。
这种写法是面向对象编程的常规做法,具体到Java中,每次你想创建一个类的实例时,都需要这样做。这使得你可以利用类定义的方法和属性,实现数据封装和方法调用等功能。
简单来说,这行代码定义了一个类型为 Calculator
的变量 calc
,并且通过 new Calculator()
创建了一个 Calculator
类的新实例,并将这个新创建的对象的引用赋值给了 calc
。这样,你就可以使用 calc
来调用 Calculator
类中定义的任何方法和访问其属性。
面向对象编程(Object-Oriented Programming, OOP)是一种编程范式,它使用“对象”来设计软件。对象是数据和方法的集合,数据表示对象的状态,而方法可以看作是在数据上操作的行为。OOP主要基于四个基本概念:封装、继承、多态和抽象。
面向对象编程的核心概念
- 封装:隐藏对象的内部细节,只暴露所需的接口。这有助于减少系统的复杂性,并增强对象之间的独立性。
- 继承:允许一个类继承另一个类的特征(属性和方法),这有助于代码重用和实现层次模型。
- 多态:允许一个接口接受多种具体对象的实现,具体对象的类型可以在运行时决定,这提供了接口与实现之间的解耦。
- 抽象:允许操作具体事物的高级模型,它提供了忽略不相关细节的能力,专注于与当前目标相关的方面。
创建一个新的类Multiplier
,定义一个方法multiply
,接收两个参数,并返回它们的乘积。
public class Multiplier {
// 定义一个方法来计算两个整数的乘积
public int multiply(int num1, int num2) {
return num1 * num2;
}
public static void main(String[] args) {
Multiplier myMultiplier = new Multiplier();
int result = myMultiplier.multiply(4, 5);
System.out.println("Product: " + result);
}
}
2. 方法重载
方法重载是类中存在多个同名方法,但它们的参数类型或数量不同。
public class Printer {
public void print(String data) {
System.out.println("Printing String: " + data);
}
public void print(int data) {
System.out.println("Printing Integer: " + data);
}
}
方法重载允许一个类中存在多个同名的方法,但这些方法的参数列表必须不同。参数列表的不同可以是参数的数量、类型或者它们的顺序。这种机制增加了程序的灵活性,允许执行相似但稍有不同的任务的方法共享同一个名称。
方法重载的规则
- 参数数量不同:方法名称相同,但接受的参数数量不同。
- 参数类型不同:方法名称相同,参数数量相同,但一或多个参数的类型不同。
- 参数顺序不同:方法名称相同,参数数量和类型相同,但参数的顺序不同。(注意,这种情况在实践中较少使用,因为它可能导致代码可读性差。)
方法重载的好处
- 提高可读性:对于执行相似功能但参数不同的方法,使用同一个名字可以让代码更容易理解。
- 增加程序的灵活性:可以根据不同的参数类型或数量来调用不同的方法体,实现细微的功能差异。
- 简化名称管理:不需要为每种操作定义一个新的方法名,使得方法的管理更加简单。
public class Display {
// 方法重载:打印整数
public void print(int i) {
System.out.println("Integer: " + i);
}
// 方法重载:打印浮点数
public void print(double d) {
System.out.println("Double: " + d);
}
// 方法重载:打印字符串
public void print(String s) {
System.out.println("String: " + s);
}
}
在这个例子中,print
方法被重载了三次,分别接受整数、浮点数和字符串类型的参数。这允许调用者使用相同的方法名print
来打印不同类型的数据。
- 不是由返回类型区分:方法重载与方法的返回类型无关,即仅返回类型不同的方法不能称为重载。
- 构造器也可以重载:在Java中,构造器也可以重载,这为对象的初始化提供了灵活。
在Printer
类中添加一个新的重载方法print
,它应该能打印一个浮点数。
public class Printer {
public void print(String data) {
System.out.println("Printing String: " + data);
}
public void print(int data) {
System.out.println("Printing Integer: " + data);
}
// 添加方法重载来打印浮点数
public void print(double data) {
System.out.println("Printing Double: " + data);
}
public static void main(String[] args) {
Printer myPrinter = new Printer();
myPrinter.print("Hello");
myPrinter.print(100);
myPrinter.print(99.9);
}
}
3. 封装
封装是面向对象编程的一个核心概念,它通过将数据(变量)和代码(方法)绑定到一起,并限制外部访问,来保护对象的状态和行为。
public class Account {
private double balance; // 私有字段,外部无法直接访问
// 构造函数
public Account(double initialBalance) {
if (initialBalance > 0) {
this.balance = initialAdjustment(initialBalance);
}
}
// 公共方法,允许外部访问私有字段
public double getBalance() {
return balance;
}
// 公共方法,允许外部修改私有字段
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
// 私有方法,外部无法访问
private double initialAdjustment(double initial) {
return initial - 10; // 假设每个新账户需要扣除10元的服务费
}
}
在这个示例中,balance
是一个私有变量,因此外部代码不能直接访问和修改它。外部代码只能通过 deposit
方法和 getBalance
方法与 balance
交互,这些方法提供了额外的逻辑,如验证输入和执行计算。此外,initialAdjustment
方法被声明为私有,这意味着它只能在类内部被调用。
通过封装,可以确保Account
类的balance
字段不会无意间被外部类修改到非法状态,同时还简化了外部类与该字段的交互。封装使得开发者可以在不影响使用该类的代码的情况下更改类的内部实现。这就是封装增加代码灵活性和可维护性的方式。
封装的主要目的:
- 保护数据:防止外部代码随意更改内部状态,这样可以避免对象被置于不一致的状态。
- 降低耦合:外部代码不需要了解对象内部的复杂性,只需要通过公共接口与对象交互,从而减少系统各部分之间的依赖关系。
- 增加灵活性和可维护性:内部实现可以自由改变,而不会影响到那些使用该对象的外部代码。
如何实现封装:
封装在Java中通常是通过使用访问修饰符来实现的。Java提供了四种访问级别:
- private:最严格的访问级别,private修饰的成员只能被同一个类的方法访问。
- default(没有指定修饰符):只允许同一个包内的其他类访问。
- protected:允许同一个包内的其他类以及所有子类访问。
- public:允许任何其他类访问。
通常,将类的字段(成员变量)声明为私有(private),这样它们就只能被类本身的方法访问和修改。然后通过公共(public)方法(如getters和setters)来访问和更新这些私有字段。这种方法不仅可以保护字段不受外部影响,还可以在用户尝试设置新值时添加验证逻辑,或者在返回值之前修改值。
修改Person
类,增加email
属性及其get和set方法
public class Person {
private String name;
private int age;
private String email; // 新增属性
public Person(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// email的get和set方法
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public static void main(String[] args) {
Person person = new Person("John", 30, "john@example.com");
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
System.out.println("Email: " + person.getEmail());
}
}
6.面向对象基础
1. 类和对象
类是对象的蓝图或原型。对象是类的实例。
在面向对象编程(OOP)中,类和对象是核心概念,它们帮助程序员在软件项目中模拟现实世界的情景。理解类和对象以及它们之间的关系对于掌握面向对象编程至关重要。
类(Class)
类是一个蓝图或模板,它定义了创建特定类型对象的规范。类描述了对象的数据属性和可以对这些数据执行的操作(方法)。简而言之,类是属性(数据字段)和方法(函数)的集合。
类的组成元素:
- 字段(Attributes):也称为属性或变量,字段表示对象的状态。在类中声明为变量。
- 方法(Methods):方法表示对象可以执行的操作。类中的方法是一些定义在类中的函数,用于操作数据,执行操作,或与外界交互。
- 构造函数(Constructors):用于初始化新对象的特殊方法。构造函数在对象创建时自动调用。
示例:定义一个简单的类
假设我们要在一个程序中处理书籍信息,我们可以创建一个Book
类。
public class Book {
// 字段
private String title;
private String author;
private int year;
// 构造函数
public Book(String title, String author, int year) {
this.title = title;
this.author = author;
this.year = year;
}
// 方法
public void displayInfo() {
System.out.println(title + " written by " + author + " in " + year);
}
}
对象(Object)
对象是根据类的定义创建的实例。如果类是蓝图,对象就是根据这个蓝图构建的房子。每个对象都拥有类定义的属性和方法的具体实例。
对象的特性:
- 状态:对象的属性表示其当前状态。
- 行为:对象的方法表示它可以进行的操作。
- 身份:系统中的每个对象都有一个唯一的身份。
创建和使用对象的示例
基于上面定义的Book
类,我们可以创建并使用Book
对象。
public class Main {
public static void main(String[] args) {
// 创建Book类的对象
Book myBook = new Book("1984", "George Orwell", 1949);
// 调用对象的方法
myBook.displayInfo();
}
}
在这个例子中,myBook
是一个对象,它是根据 Book
类的蓝图创建的。每个 Book
对象都会有自己的标题(title)、作者(author)和出版年份(year),这些数据是对象的状态。displayInfo
方法是对象的行为,它可以让对象展示自己的信息。
类与对象的关系
- 类定义一种数据类型:从更广泛的编程角度看,类定义了一种新的数据类型。但与基本数据类型不同,这种类型的行为和数据是用户定义的。
- 对象是类的实例化结果:对象是通过调用类的构造函数实例化的。每个对象都拥有类的所有属性和方法的副本。
理解类和对象及其互动是面向对象编程成功的关键。类提供结构和行为的模板,而对象则是这些模板的实际实例,你可以在程序中创建和操作这些实例以解决实际问题。
创建Car
类的对象并调用displayInfo
方法
public class Car {
String color;
int year;
public Car(String color, int year) {
this.color = color;
this.year = year;
}
void displayInfo() {
System.out.println("Car color: " + color + ", Year: " + year);
}
public static void main(String[] args) {
Car myCar = new Car("Red", 2020);
myCar.displayInfo();
}
}
2.构造函数
构造函数是一种特殊类型的方法,它在创建新对象时自动调用,用于初始化对象的状态。构造函数的主要目的是为新创建的对象分配内存并初始化其成员变量的值。
特性
- 与类同名:构造函数的名称必须与其所在类的名称完全相同。
- 没有返回类型:构造函数不返回值,甚至不使用
void
。 - 可以被重载:一个类可以有多个构造函数,每个构造函数通过其参数列表的不同来区分。
public class Vehicle {
private String model;
private int year;
// 无参构造函数
public Vehicle() {
this.model = "Unknown";
this.year = 2020;
}
// 带参数的构造函数
public Vehicle(String model, int year) {
this.model = model;
this.year = year;
}
public void displayInfo() {
System.out.println("Model: " + model + ", Year: " + year);
}
}
在这个例子中,Vehicle
类有两个构造函数:一个无参构造函数,它提供了默认值;另一个是带参数的构造函数,它允许在创建对象时设置model
和year
。
实现Bike
的gearDown
方法
public class Bike {
int gear;
public Bike(int startGear) {
gear = startGear;
}
void gearUp() {
gear++;
}
// 实现gearDown方法
void gearDown() {
if (gear > 1) {
gear--;
}
}
public static void main(String[] args) {
Bike myBike = new Bike(3);
myBike.gearUp();
myBike.gearDown();
System.out.println("Current Gear: " + myBike.gear);
}
}
3.this关键字
this
关键字在Java中用于引用当前对象,也就是正在执行的方法所属对象的引用。
用途
- 区分成员变量和参数名:当方法的参数名与类的成员变量名相同,可以使用
this
来区分成员变量和参数变量。 - 在一个构造函数中调用另一个构造函数:使用
this()
调用形式可以从一个构造函数调用同一个类的另一个构造函数。 - 传递当前对象作为参数:在需要将当前对象传递给另一个方法或作为返回值时使用。
- 调用当前类的方法:使用
this
调用同一个类中的其他方法。
public class Point {
private int x;
private int y;
// Constructor
public Point(int x, int y) {
this.x = x; // this.x refers to the field; x refers to the parameter
this.y = y;
}
// Method that returns a string representation of the object
public String getLocation() {
return "X: " + this.x + ", Y: " + this.y; // Using 'this' is optional here
}
// Method to set a new location
public void setLocation(int x, int y) {
this.x = x; // Again, 'this' differentiates the parameter x from the field x
this.y = y;
}
}
在这个 Point
类中,使用 this.x
和 this.y
来明确指定成员变量 x
和 y
,与方法参数 x
和 y
区分开。
总结来说,构造函数和 this
关键字是面向对象编程中管理和操作对象状态的重要工具。构造函数确保了对象在使用前被适当初始化,而 this
关键字提供了在类的内部代码中引用当前对象自身的方法,这有助于代码的清晰和维护。
使用Box
类的对象
public class Box {
private int length;
private int width;
public Box(int length, int width) {
this.length = length;
this.width = width;
}
public void displayDimensions() {
System.out.println("Length: " + length + ", Width: " + width);
}
public static void main(String[] args) {
Box myBox = new Box(10, 20);
myBox.displayDimensions();
}
}
7.小项目
1. 继承(Inheritance)
继承是面向对象编程中的一个核心概念,允许一个类(子类)继承另一个类(父类)的属性和方法。继承支持代码重用,也方便功能的扩展。
// 父类
public class Animal {
public void eat() {
System.out.println("This animal eats food.");
}
}
// 子类
public class Dog extends Animal {
public void bark() {
System.out.println("The dog barks.");
}
}
2. 接口(Interface)
接口定义了一个合约。一个类可以实现一个或多个接口,从而承诺提供接口中声明的所有方法的具体实现。
public interface Flyable {
void fly();
}
public class Bird implements Flyable {
public void fly() {
System.out.println("Bird flies in the sky.");
}
}
3. 抽象类(Abstract Class)
抽象类是不能被实例化的类,通常用作基类。抽象类可以包含抽象方法(没有具体实现的方法)和具体方法。
public abstract class Vehicle {
public abstract void move();
public void start() {
System.out.println("Vehicle starts.");
}
}
public class Car extends Vehicle {
public void move() {
System.out.println("Car moves on roads.");
}
}
4. 多态(Polymorphism)
多态允许通过父类的引用来调用在不同子类中具有不同实现的方法。
public class Animal {
public void sound() {
System.out.println("Animal makes a sound.");
}
}
public class Cat extends Animal {
public void sound() {
System.out.println("Cat meows.");
}
}
public class Dog extends Animal {
public void sound() {
System.out.println("Dog barks.");
}
}
项目描述:图书管理系统
目标:设计一个简单的图书管理系统来管理图书信息和用户的借阅记录。
主要功能:
- 添加新图书
- 显示所有图书
- 借出图书
- 归还图书
类设计
- Book - 表示图书信息
- Library - 管理图书的添加、借出和归还
- User - 管理借书的用户信息
public class Book {
private String title;
private String author;
private boolean isBorrowed;
public Book(String title, String author) {
this.title = title;
this.author = author;
this.isBorrowed = false;
}
public void borrow() {
this.isBorrowed = true;
}
public void returnBook() {
this.isBorrowed = false;
}
public boolean isBorrowed() {
return isBorrowed;
}
@Override
public String toString() {
return "Title: " + title + ", Author: " + author + ", Borrowed: " + (isBorrowed ? "Yes" : "No");
}
}
import java.util.ArrayList;
import java.util.List;
public class Library {
private List<Book> books;
public Library() {
this.books = new ArrayList<>();
}
public void addBook(Book book) {
books.add(book);
}
public void displayBooks() {
for (Book book : books) {
System.out.println(book);
}
}
public void borrowBook(String title) {
for (Book book : books) {
if (book.toString().contains(title) && !book.isBorrowed()) {
book.borrow();
System.out.println("Book borrowed: " + title);
return;
}
}
System.out.println("Book not available for borrowing: " + title);
}
public void returnBook(String title) {
for (Book book : books) {
if (book.toString().contains(title) && book.isBorrowed()) {
book.returnBook();
System.out.println("Book returned: " + title);
return;
}
}
System.out.println("Book was not borrowed: " + title);
}
}
public class Main {
public static void main(String[] args) {
Library library = new Library();
library.addBook(new Book("1984", "George Orwell"));
library.addBook(new Book("The Hobbit", "J.R.R. Tolkien"));
System.out.println("Available books:");
library.displayBooks();
library.borrowBook("1984");
library.displayBooks();
library.returnBook("1984");
library.displayBooks();
}
}
运行Main.java
将初始化图书馆,添加图书,然后模拟借阅和归还过程。你可以观察到输出中图书状态的变化。