面向对象
1.学习面向对象的思想
概述:面向对象是相对面向过程而言,面向对象和面向过程都是一种思想,面向过程强调的是功能行为,面向对象则是将功能封装进对象,强调具备功能的对象,面向对象是基于面向过程的。
面向对象的三大特征:封装、继承、多态。开发:其实就是找对象,建立对象,使用对象,维护对象的关系。
例如洗衣服:
面向过程:把衣服脱下来–>找个盆–>放洗衣粉–>加水–>浸泡10分钟–>揉一揉–>清洗衣服–>拧干–>晾起来
面向对象:把衣服脱下来–>打开全自动洗衣机–>扔衣服–>按钮–>晾起来
区别:
面向过程:强调步骤和功能,这里是一步步完成洗衣操作,某个步骤完成某个功能。
面向对象:这里的对象就是有洗衣功能的洗衣机,是将功能封装进对象,强调的是具备功能的对象。
面向过程:第一步第二步第三步每步干什么每步完成某个功能。
面向对象:找到有该功能的对象,没有就创建有该功能的对象。
现实生活中的所有能够看得见,摸得着的都可以认为是一个对象。在java中,一切皆对象。
总结:面向对象就是将所有的方法和属性封装进类中,而后可以通过类的对象去调用这个类的方法和属性。
按照具体的需求完成开发时:
- 寻找是否存在具有该需求的对象
- 如果该对象不存在,则创建一个具有该需求所需的对象,先建类再创其对象
2.类和对象
类和对象是面向对象中的最核心的两个概念:
类:可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。
对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。
类: 是对一类事物的描述,是抽象的。
对象:是一类事物的实例,是具体的。
类是对象的模板,对象是类的实体。
在实际开发中,我们的重点是放在类的设计还是对象的设计上?
当然是类,因为只有类设计好了,此类的所有对象才算是设计好了
类的成员:
属性:事物的状态信息。成员变量 。在类中,方法外。
行为:事物能够做什么。成员方法。
成员变量和局部变量的区别:
在类中的位置不同
成员变量:类中,方法外
局部变量:方法中或者方法声明上(形式参数)
作用范围不一样
成员变量:类中
局部变量:方法中
初始化值的不同
成员变量:有默认值
局部变量:没有默认值。必须先定义,赋值,最后使用
在内存中的位置不同
成员变量:堆内存
局部变量:栈内存
生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
类的语法格式:
修饰符 class 类名{
属性;
方法;
}
注意点:
如果使用public来修饰类,那么类名要与文件名一致,就是java文件名要和public修饰的类名相同。
类的修饰符有三种(public,protected,default(默认啥也不写就是default))。
类的正文要使用{}括起来。
属性的声明格式:
修饰符 类型 属性名 = 初始值;
注意点:
修饰符可以使用public,protected,default,private,
其中public表示公共的,外部类可以访问,private表示私有的,只有这个类本身才能够访问,外部类不能访问。
类型可以是基本数据类型,也可以是引用数据类型。
3.方法
方法:就是将一个功能抽取出来,把代码单独定义在一个大括号内,形成一个单独的功能。
当需要这个功能的时候,就可以去调用这个方法。实现了代码的复用性和解决了代码冗余的现象。
方法表示的一段可以反复调用的代码。
方法的声明格式:
访问修饰符 [修饰符] (返回值类型|void) 方法名([参数列表])[throws Exception]{
方法体;
}
注意点:
访问修饰符有四个:public,protected,default,private,
修饰符:可以使用修饰符,也可以不使用修饰符,常见的修饰符有static,synchronize,native等
- 返回值类型|void : 返回值类型和void二选一,其中返回值类型可以书写为任意类型,包括引用数据类型和基本数据类型都可以,但是如果有返回值类型,那么这个方法体中最终都需要return 语句来声明返回值。如果声明为void,则方法体中可以不使用return。
- 方法名:每个方法都需要一个方法名,而且这个方法名要符合标识符的命名规则
[参数列表]:在方法的声明处定义的参数列表,叫做形式参数,简称形参,形参的个数,顺序,类型是任意的,形参实际上是该方法中的一个局部变量,除了这个方法之外,外部无法访问。 - [throws Exception] : 表示本方法的异常不处理,而是交由调用本方法来处理异常。
形式参数:方法声明处的参数列表,简称形参,是一个局部变量,没有默认值,作用域只在这个方法中。
实际参数:调用方法处传递的参数,简称实参,就是传具体的数据值。
形参是个变量名,实参是个具体的数据值。
方法的调用:
方法的调用:目标方法的调用有两种形式
- 调用同类中的方法,可以直接调用(也可以通过this.方法调用,this就是当前对象的意思,表示当前类的对象)
- 调用不同类中的方法,需要通过类的对象调用
非静态方法通过对象访问,静态方法通过类名调用也可通过对象访问。
方法调用的注意点:
- 调用有参方法时,传递的实际参数的个数、类型、顺序必须和方法定义的形式参数的个数、类型、顺序一致。
- 如果被调用的方法有返回值,可以在调用方法的时候用return使用相同类型的变量接收方法的返回结果。
- private修饰的方法,在外部类中是不能够访问的。
怎么编写方法:
方法的编写都是按照需求功能进行编写的,方法的形式参数和返回值类型也是根据完成功能所需要的参数,完成功能之后是否需要返回结果来定。
修饰符: public static 表明是静态方法可通过类名直接访问
返回值类型: 表示方法运行的结果的数据类型,方法执行后将结果返回到调用者
形式参数列表:方法在运算过程中的未知数据,调用者调用方法时传递实际参数
return:将方法执行后的结果带给调用者,方法执行到 return ,整体方法运行结束。
定义方法注意事项:
定义位置,类中方法外面。
返回值类型,必须要和 return 语句返回的类型相同。
不能在 return 后面写代码, return 意味着方法结束,所有后面的代码永远不会执行,属于无效代码。
练习编写方法的4个案例
1.定义方法实现两个整数的求和计算。
明确返回值类型:方法计算的是整数的求和,结果也必然是个整数,返回值类型定义为int类型。
明确参数列表:计算哪两个整数的和,并不清楚,但可以确定是整数,参数列表可以定义两个int类型的。
形式参数中的形式局部变量,由调用者调用方法时传递实参。
public static void main(String[] args) {
// 调用方法getSum,传递两个整数,这里传递的实际数据又称为实际参数
// 并接收方法计算后的结果,有返回值
int sum = getSum(5, 6);
System.out.println(sum);
}
/*
定义计算两个整数和的方法
返回值类型,计算结果是int
参数:不确定数据求和,定义int参数.参数又称为形式参数
*/
public static int getSum(int a, int b) {
return a + b;
}
程序执行,主方法 main 调用 getSum 方法,传递了实际数据 5和6 ,两个变量 a和b 接收到的就是实际参数,
并将计算后的结果返回,主方法 main 中的变量 sum 接收的就是方法的返回值。
2.比较两个整数是否相同
分析:定义方法实现功能,需要有两个明确,即 返回值 和 参数列表 。
明确返回值:比较整数,比较的结果只有两种可能,相同或不同,因此结果是布尔类型。
明确参数列表:比较的两个整数不确定,所以默认定义两个int类型的参数。
public static void main(String[] args) {
//调用方法compare,传递两个整数
//并接收方法计算后的结果,布尔值
boolean bool = compare(3, 8);
System.out.println(bool);
}
/*
定义比较两个整数是否相同的方法
返回值类型,比较的结果布尔类型
参数:不确定参与比较的两个整数
*/
public static boolean compare(int a, int b) {
if (a == b) {
return true;
} else {
return false;
} }
3.计算1+2+3...+100的和
分析:定义方法实现功能,需要有两个明确,即 返回值 和 参数 。
明确返回值:1~100的求和,计算后必然还是整数,返回值类型是int
明确参数:需求中已知到计算的数据,没有未知的数据,不定义参数
public static void main(String[] args) {
//调用方法getSum
//并接收方法计算后的结果,整数
int sum = getSum();
System.out.println(sum);
}
/*
定义计算1~100的求和方法
返回值类型,计算结果整数int
参数:没有不确定数据
*/
public static int getSum() {
//定义变量保存求和
int sum = 0;
//从1开始循环,到100结束
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
}
4.实现不定次数打印 HelloWorld
分析:定义方法实现功能,需要有两个明确,即 返回值 和 参数 。
明确返回值:方法中打印出 HelloWorld 即可,没有计算结果,返回值类型 void
明确参数:打印几次不清楚,参数定义一个整型参数
public static void main(String[] args) {
//调用方法printHelloWorld,传递整数
printHelloWorld(9);
}
/*
定义打印HelloWorld方法
返回值类型,计算没有结果 void
参数:不确定打印几次
*/
public static void printHelloWorld(int n) {
for (int i = 0; i < n; i++) {
System.out.println("HelloWorld");
} }
4.方法的重载
方法的重载:在同一个类中,方法名称相同,参数列表不同(参数的个数不同,参数的类型不同,参数的顺序不同),与方法的修饰符和方法返回值类型和形式参数名称无关。
重载方法调用:JVM通过方法的形式参数列表,调用不同的方法。
会根据传入的实际参数的个数,类型,顺序的不同找到相同形参的方法进行调用。
注意点:方法的重载和返回值类型和形参名称无关,只看参数列表不同。
方法的重载是面向对象多态的一个体现(编译时多态)。
5.对象的创建
对象的创建: 类名 对象名 = new 类名();
类是对象的模板,所以通过对象可以调用类中一切非私有的属性和方法
在基本数据类型中,一般称为变量,而在引用数据类型中,称为对象,所以变量和对象实际上是相同的概念,只是类型不同。对象就是变量。
除了基本数据类型之外的类型都是引用数据类型(3种,类,接口,数组),引用数据类型的默认值都是null。
1.对象的引用传递
1.在引用数据类型中,除了数组之外,其他类型的变量都称之为对象。既然是引用数据类型,就存在内存的引用传递问题。(基本类型没有引用传递问题)
public static void main(String[] args) {
Phone phone1 = new Phone();//实例化一个Phone类型的对象
phone1.brand = "HONOR";
phone1.color = "blue";
phone1.price = 1000;
Phone phone2 = phone1;
phone2.brand = "Apple";
phone2.color = "White";
phone2.price = 10000;
System.out.println(phone1.brand);
System.out.println(phone1.color);
System.out.println(phone1.price);
}
}
class Phone{
String brand;//手机品牌
double price;//手机价格
String color;//手机颜色
}
跟数组的引用传递一样,对象引用传递也是传递了堆内存空间的使用权。
2.对象的生命周期
- 生:对象的创建,new关键字就是在堆里面开辟一个空间,创建了一个对象。
- 生活:对象的使用,调用类的方法,属性等
- 死:对象所占用的堆内存空间没有了,对象不再被使用,或者对象的值为null,或者程序运行结束,这几种情况下,对象所占用的空间都会被Java垃圾回收机制进行回收。
3.匿名对象
new 类名();或者new 类名(参数列表);一个匿名对象只能使用一次,下次再用就创建一个新对象。
匿名对象是相对于命名对象而言的,我们在创建一个对象的时候
类名 对象名 = new 类名();这种语法的创建对象是有名字的,而如果只是用new 类名();这个语法一定是创建了对象的,而且在堆内存空间中一定是开辟了空间的,只是这个对象没有名字,没有名字的对象叫做匿名对象,而且只能使用一次。
匿名对象 :没有变量名的对象。
格式: new 类名(参数列表);
举例: new Scanner(System.in);
应用场景:创建匿名对象直接调用方法,没有变量名。 new Scanner(System.in).nextInt();
一个匿名对象,只能使用一次。下次再用就创建一个新对象。
匿名对象可以作为方法的参数和返回值
作为参数:
class Test {
public static void main(String[] args) {
// 普通方式
Scanner sc = new Scanner(System.in);
input(sc);
//匿名对象作为方法接收的参数
input(new Scanner(System.in));
}
public static void input(Scanner sc){
System.out.println(sc);
}
}
作为返回值 :
class Test2 {
public static void main(String[] args) {
Scanner sc = getScanner();
}
public static Scanner getScanner(){
//普通方式
//Scanner sc = new Scanner(System.in);
//return sc;
//匿名对象作为方法返回值
return new Scanner(System.in); }}
4.对象数组
之前数组中存储的都是基本数据类型的数据,实际上数组可以存放任意类型的数据,包括引用数据类型。
数组定义方式:
类型 数组名[] = {数据1,数据2,数据3…};
类型 数组名[] = new 类型[]{数据1,数据2,数据3…};
类型 数组名[] = new 类型[10];//创建一个长度为10的数组
public class OopDemo06 {
public static void main(String[] args) {
int arr1[] = {1,2,3,4,5,1,2,3,4,5}; //int 类型数组存储的数据是int类型
int arr2[] = new int[5]; //数组中的数据默认值都是0
Desk desk1 = new Desk();
Desk desk2 = new Desk();
Desk desk3 = new Desk();
Desk desks[] = {desk1,desk2,desk3}; //Desk 类型的数组存储的数据肯定是Desk类型
Desk desks2[] = new Desk[5];//开辟长度为5的Desk类型的数组,默认值都是null
}
}
class Desk{
double width;
double height;
double length;
}
可变参数方法
一个方法中只能传递一个可变参数,而且必须放在参数列表的最后,实际上可变参数就是一个数组。
可变参数的方法是JDK1.5之后才有新的方法的声明。之前在定义方法的时候,如果需要传递多个相同数据类型的参数,我们可以定义多个,也可以以数组的形式传递。
public static void main(String[] args) {
Arithmetic arithmetic = new Arithmetic();
int intArray[] = {1,2,3,4,5,6,7,8,9,10};
// int xyz = arithmetic.add(1,2,3,4,5,6);
int xyz = arithmetic.add(intArray);
System.out.println(xyz);
}
}
class Arithmetic{
//固定参数
public int add(int i,int j,int k,int x,int y,int z) {
int result = i + j + k + x + y + z;
return result;
}
//将数组作为参数[数据的个数根据实际参数的数组的长度来定]
public int add(int arr[]) {
int result = 0;
for (int i : arr) {
result += i;
}
return result;
}}
以上代码中两个add方法,其中一个是固定参数个数的,第二个是以数组的形式传递参数的,实际上参数的个数就是由数组的长度决定。可变参数的方法是JDK1.5之后才有新的方法的声明,可变参数实际上就是一个数组。
public int add(int …i)
public static void main(String[] args) {
Arithmetic arithmetic = new Arithmetic();
// int xyz = arithmetic.add(1,2,3);//调用可变参数方法
int xyz = arithmetic.add("----------------------",1,2,3,4,5,6,7,8,9,10);
System.out.println(xyz);
}
}
class Arithmetic{
public int add(int... i) { //可变参数实际上就是一个数组,数组名为i,可变参数int... i 就是数组int[] i
int result = 0;
for (int j : i) {
result += j;
}
return result;
}
public int add(String name,int ...i) { //可变参数必须放在参数列表的最后一个位置
int result = 0;
System.out.println(name);
for (int j : i) {
result += j;
}
return result;
}
}
可变参数方法的参数声明规则:
- 可变参数必须放在所有声明参数的最后
- 一个方法中只能声明一个可变参数
- 可变参数实际上就是一个数组。
完成Desk类型数组的数据增删改查操作。
package com.wanbangee.desk;
public class Desk {
private double width;
private double length;
private double height;
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public Desk(double width, double length, double height) {
super();
this.width = width;
this.length = length;
this.height = height;
}
public Desk() {
super();
}
}
package com.wanbangee.desk;
public class DeskOperation {
Desk[] desks = new Desk[10];
//新增
public boolean addDesk(Desk desk) {
for (int i = 0; i < desks.length; i++) {
if(desks[i] == null) {
desks[i] = desk;
return true;
}
}
return false;
}
//修改
public boolean updateDesk(Desk oldDesk,Desk newDesk) {
int index = searchDesk(oldDesk);
if(index == -1) {
return false;
}
desks[index] = newDesk;
return true;
}
//删除
public boolean deleteDesk(Desk desk) {
int index = searchDesk(desk);
if(index == -1) {
return false;
}
for (int i = index; i < desks.length-1; i++) {
desks[i] = desks[i+1];
}
desks[desks.length-1] = null;
return true;
}
//查找
public int searchDesk(Desk desk) {
int index = -1;
for (int i = 0; i < desks.length; i++) {
Desk desk1 = desks[i];
if(desk1 == null) {
break;
}
if(desk1.getHeight() == desk.getHeight() && desk1.getLength() == desk.getLength() && desk1.getWidth() == desk.getWidth()) {
index = i;
break;
}
}
return index;
}
//打印
public void printDesk() {
for (Desk desk : desks) {
if(desk == null) {
break;//表示这个数组的元素是空的,那么不能打印
}
System.out.println("desk 高度:" + desk.getHeight() + ",宽度:" + desk.getWidth() + ",长度:" + desk.getLength());
}
}
}
package com.wanbangee.desk;
import java.util.Scanner;
public class DeskOperationTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
DeskOperation deskOperation = new DeskOperation();
int temp = 0;
do {
System.out.print("提示:1表示新增,2表示修改,3表示删除,4表示查找,5表示打印,0表示退出,请输入操作的数字代号:");
temp = scanner.nextInt();
switch (temp) {
case 1:
System.out.print("请输入新增桌子的高度:");
double newDeskHeight = scanner.nextDouble();
System.out.print("请输入新增桌子的长度:");
double newDeskLength = scanner.nextDouble();
System.out.print("请输入新增桌子的宽度:");
double newDeskWidth = scanner.nextDouble();
//将键盘输入的值,封装成Desk对象的属性
Desk newDesk = new Desk(newDeskWidth,newDeskLength,newDeskHeight);
// newDesk.setHeight(newDeskHeight);
// newDesk.setLength(newDeskLength);
// newDesk.setWidth(newDeskWidth);
boolean flag = deskOperation.addDesk(newDesk);
//System.out.println("新增后的结果是:"+flag);
if(flag) {
System.out.println("新增成功");
}else {
System.out.println("新增失败");
}
break;
case 2:
System.out.print("请输入要修改桌子的高度:");
double deskHeight2 = scanner.nextDouble();
System.out.print("请输入要修改桌子的长度:");
double deskLength2 = scanner.nextDouble();
System.out.print("请输入要修改桌子的宽度:");
double deskWidth2 = scanner.nextDouble();
//将键盘输入的值,封装成Desk对象的属性
Desk desk2 = new Desk(deskWidth2,deskLength2,deskHeight2);
// desk2.setHeight(deskHeight2);
// desk2.setLength(deskLength2);
// desk2.setWidth(deskWidth2);
int index = deskOperation.searchDesk(desk2);
if(index == -1) {
System.out.println("你要修改的数不存在,修改失败");
break;
}else {
System.out.println("你要修改的数所在索引为"+index);
}
System.out.print("请输入要修改后桌子的高度:");
double deskHeight3 = scanner.nextDouble();
System.out.print("请输入要修改后桌子的长度:");
double deskLength3 = scanner.nextDouble();
System.out.print("请输入要修改后桌子的宽度:");
double deskWidth3 = scanner.nextDouble();
//将键盘输入的值,封装成Desk对象的属性
Desk desk3 = new Desk(deskWidth3,deskLength3,deskHeight3);
// desk3.setHeight(deskHeight3);
// desk3.setLength(deskLength3);
// desk3.setWidth(deskWidth3);
boolean flag3 = deskOperation.updateDesk(desk2, desk3);
//System.out.println("修改后的结果是:"+flag3);
if(flag3) {
System.out.println("修改成功");
}else {
System.out.println("修改失败");
}
break;
case 3:
System.out.print("请输入要删除桌子的高度:");
double deskHeight4 = scanner.nextDouble();
System.out.print("请输入要删除桌子的长度:");
double deskLength4 = scanner.nextDouble();
System.out.print("请输入要删除桌子的宽度:");
double deskWidth4 = scanner.nextDouble();
//将键盘输入的值,封装成Desk对象的属性
Desk desk4 = new Desk(deskWidth4,deskLength4,deskHeight4);
// desk4.setHeight(deskHeight4);
// desk4.setLength(deskLength4);
// desk4.setWidth(deskWidth4);
int index5 = deskOperation.searchDesk(desk4);
// if(index5 == -1) {
// System.out.println("找不到要删除的对象");
// }else {
// System.out.println("要删除的对象所在数组中的索引位置为:"+index5);
// }
boolean flag4 = deskOperation.deleteDesk(desk4);
//System.out.println("删除后的结果是:"+flag4);
if(flag4) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
break;
case 4:
System.out.print("请输入查找桌子的高度:");
double deskHeight1 = scanner.nextDouble();
System.out.print("请输入查找桌子的长度:");
double deskLength1 = scanner.nextDouble();
System.out.print("请输入查找桌子的宽度:");
double deskWidth1 = scanner.nextDouble();
//将键盘输入的值,封装成Desk对象的属性
Desk desk1 = new Desk(deskWidth1,deskLength1,deskHeight1);
// desk1.setHeight(deskHeight1);
// desk1.setLength(deskLength1);
// desk1.setWidth(deskWidth1);
int index1 = deskOperation.searchDesk(desk1);
//System.out.println("该对象所在数组中的索引位置为:"+index1);
if(index1 == -1) {
System.out.println("查无此对象");
}else {
System.out.println("该对象所在数组中的索引位置为:"+index1);
}
break;
case 5:
deskOperation.printDesk();
break;
case 0:
System.out.println("退出程序:");
break;
default:
System.out.println("您输入有误,请重新输入:");
break;
}
} while (temp != 0);
}
}