java 4 (面向对象上)

java——面向对象(上)

java是一门面向对象的语言

1.java类及类的成员:属性、方法、构造器;代码块、内部类

2.面向对象的三大特征:封装性、继承性、多态性、(抽象性)

3.其它关键字:this、super、static、final、abstract、interface、package、import

面向过程&面向对象

面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做

面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做

面向对象的思想概述

面向对象的两个要素

**类(Class)**是对一类事物的描述,是抽象的,概念上的定义

**对象(Object)**是实际存在的该类事物的每个个体,因此也称为实例(instance)

设计类就是设计类的成员

类的成员(1-2):属性和方法

常见的类成员:属性、行为(方法)

属性:成员变量------>field/域、字段

方法:成员方法------>函数(C语言)------>method

三步骤:
step1:创建类,设计类的成员
step2:创建类的对象
step3:通过“对象.属性”或“对象.方法”调用对象的结构

class Person{
    
    
	
	//属性
	String name;
	int age;
	boolean isMale;
	//方法
	public void eat() {
    
    
		System.out.println("人可以吃饭");
	}
	public void sleep() {
    
    
		System.out.println("人可以睡觉");
	}
	public void talk(String language) {
    
    
		System.out.println("人可以说话,使用的是"+language);
	}
}

当我们创建一个类后,我们怎么使用呢——对象:java的实例化

/*类和对象的使用(面向对象思想落地的实现)
三步骤:
step1:创建类,设计类的成员
step2:创建类的对象
step3:通过“对象.属性”或“对象.方法”调用对象的结构
*/
public class personTest {
    
    
	public static void main(String[] args) {
    
    
		//创建person类的对象
		//step2:创建类的对象
		Person p1=new Person();
		//Scanner scanner=new Scanner(System.in)
		//调用对象的结构:属性、方法
		//step3:通过“对象.属性”或“对象.方法”调用对象的结构
		//调用属性:“对象.属性”
		p1.name="Tom";
		p1.isMale=true;
		System.out.println(p1.name);
	
		//调用方法:“对象.方法”
		p1.eat();
		p1.sleep();
		p1.talk("Chinese");
	}
}

//step1:创建类,设计类的成员
class Person{
    
    
	
	//属性
	String name;
	int age;
	boolean isMale;
	//方法
	public void eat() {
    
    
		System.out.println("人可以吃饭");
	}
	public void sleep() {
    
    
		System.out.println("人可以睡觉");
	}
	public void talk(String language) {
    
    
		System.out.println("人可以说话,使用的是"+language);
	}
}	

现在我们再创建一个对象

Person p2=new Person();
System.out.println(p2.name);//Tom?   null? 
System.out.println(p2.isMale);//false
Person p3=p1;    //将p1变量保存的对象地址赋值给p3,导致p1和p3指向了堆空间中同一个对象实体
System.out.println(p3.name);//Tom

结果为null,这是什么意思呢?

当我们new了之后,我们就在堆空间申请一片内存空间:当我们创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性(非static);这就意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值

对象的内存解析

image-20220918162528821

类中属性的使用

属性(成员变量)vs局部变量

1.相同点

​ 1.1定义变量的格式:数据类型 变量名=变量值

​ 1.2先声明、后使用

​ 1.3变量都有其对应的作用域

2.不同点

​ 2.1在类中声明的位置不同

​ 属性:直接定义在类的一对{}内

​ 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量

​ 2.2关于修饰符的不同

​ 属性:可以在声明属性时,指明其权限,使用权限修饰符

​ 常用的权限修饰符:private、public、缺省、protected—>封装性

​ 目前,大家声明属性时,都使用缺省就可以了

​ 局部变量:不可以使用权限修饰符

​ 2.3默认初始化值的情况:

​ 属性:类的属性根据其类型都有默认初始化值(类比一维数组元素的初始化值)

​ 整型(byte、short、int、long):0

​ 浮点型(float、double):0.0

​ 字符型(char):0

​ 布尔型(boolean):false

​ 引用数据类型(类、数组、接口):null

局部变量:没有默认初始化值

​ 意味着我们调用局部变量前,一定要赋值

​ 特别的,形参在调用时,再赋值即可

2.4在内存中加载的位置:

属性:加载到堆空间中(非static)

局部变量:加载到栈空间

package Class_and_Object;

public class UserTest {
    
    
	public static void main(String[] args) {
    
    
		User u1=new User();
		//下面查看属性的初始化值
		System.out.println(u1.name);
		System.out.println(u1.age);
		System.out.println(u1.isMale);
	}
}
class User{
    
    
	//属性
	String name;
	public int age;
	boolean isMale;
	//方法
	public void talk(String language) {
    
    
        //language是局部变量;这里可以在调用的时候赋值(因为是形参)
		System.out.println("我们使用"+language+"进行交流");
	}
	public void eat() {
    
    
		String food="米饭";//局部变量
		System.out.println("我们的主食是"+food);
	}
}

类中方法的使用

方法:描述类应该具有的功能

​ 比如:Math类:sqrt() \random()…

1.举例:

class Customer{
    
    
	//属性
	String name;
	int age;
	boolean isMale;
	//方法
	public void eat() {
    
    
		System.out.println("客户吃饭");
	}
	public void sleep(int hour) {
    
    
		System.out.println("休息了:"+hour+"小时");
	}
	public String getName() {
    
    
		return name;
	}
	public String getNation(String nation) {
    
    
		String information="我的国籍是:"+nation;
		return information;
	}
}

这里运用到的方法为:

public void eat()

public void sleep(int hour)

public String getName()

public String getNation(String nation)

2.声明方法:

格式:

权限修饰符 返回值类型 方法名(形参列表){    //形参列表根据实际情况不止一个
	方法体;
}  

3.说明

​ **3.1关于权限修饰符:**默认方法的权限修饰符先都使用public

java规定的四种权限修饰符:private、public、缺省、protected  ------>封装性

​ **3.2返回值类型:**有返回值 vs 没有返回值

​ 3.2.1如果方法有返回值:则必须在方法声明时。指定返回值的类型;同时方法中需要用return关键字来返回返回指定类型的变量或常量;

​ 如果方法没有返回值:则在方法声明时,使用void来表示,通常,没有返回值的方法中,就不用使用return;但是,如果使用return的话,表示结束此方法的意思

​ 3.2.2我们定义方法的时候该不该有返回值?经验主义

​ **3.3方法名:**属于标识符(见名知意)

​ **3.4形参列表:**方法可以声明0个、1个、多个形参

格式:数据类型1 形参1,数据类型2 形参2,......

4.return关键字的使用:

​ (1.使用范围,使用在方法体中

​ (2.作用:结束方法;

​ 针对有返回值类型的方法,使用“return 数据”方法返回所需要的数据

​ (3.注意点:return关键字后面不可以声明执行语句

5.方法的使用中,可以调用当前类的属性或方法

​ 【特殊的】,方法A中又调用了方法A:递归方法

​ 方法中,不可以定义方法

实例1:求圆的面积

public class CircleTest {
    
    
	public static void main(String[] args) {
    
    
		Circle c1=new Circle();
		c1.radius=2;
		double area=c1.findArea();
		System.out.println(area);
	}
}
class Circle{
    
    
	//属性
	double radius;       //半径
	//求圆的面积
	public double findArea() {
    
    
		double area=3.14*radius*radius;
		return area;
	}
}
public class Print_Matrix_class {
    
    
	public static void main(String[] args) {
    
    
		Print_Matrix_class test = new Print_Matrix_class();
		test.print_methed();
	}

//编写一个能打印*矩形的方法
	public void print_methed() {
    
    
		for (int i = 1; i <= 10; i++) {
    
    
			for (int j = 1; j <= 8; j++) {
    
    
				System.out.print("*");
			}
			System.out.println();
		}
	}
}

注意括号的包含关系 print_methed()这个方法是包含在public class 类当中的,相当于是整个文件的大类,因此我们在使用方法时仍然需要创建实例化对象:Print_Matrix_class test = new Print_Matrix_class();其中的test就是我们所创造的对象

实例2:打印矩形

public class Print_Matrix_class {
    
    
	public static void main(String[] args) {
    
    
		Print_Matrix_class test = new Print_Matrix_class();
		int area=test.print_methed();
		//方式1:
		System.out.println("面积为:"+area);
		//方式2:
		System.out.println(test.print_methed());
	}

//编写一个能打印*矩阵的方法
	public int print_methed() {
    
    
		for (int i = 1; i <= 10; i++) {
    
    
			for (int j = 1; j <= 8; j++) {
    
    
				System.out.print("*");
			}
			System.out.println();
		}
	//System.out.println(10*8);
		return 10*8;	
	}
}
System.out.println(test.print_methed());

对于这段语句,输出语句也可以在括号内使用【方法】,这里将方法看作成了一个变量,变量的值即是该方法的返回值(该类调用方法不会报错)

public class Print_Rectangle_class02 {
    
    
	public static void main(String[] args) {
    
    
		Print_Rectangle_class02 test = new Print_Rectangle_class02();
		int result=test.method(5, 5);
		//方法1:
		System.out.println(result);
		//方法2:
		System.out.println(test.method(5, 5));
	}

	public int method(int m, int n) {
    
    
		for (int i = 0; i < m; i++) {
    
    
			for (int j = 0; j < n; j++) {
    
    
				System.out.print("*");
			}
			System.out.println();
		}
	return m*n;
	}
}

实例3:打印学生信息

public class Students_class {
    
    
	public static void main(String[] args) {
    
    
		// 声明20个对象
		// student s1=new student(); //太多了
		// 声明student类型的数组
		student[] stu = new student[20]; // 对象数组

		for (int i = 0; i < 20; i++) {
    
    
			// 给数组元素赋值
			stu[i] = new student();
			// 给student对象属性赋值
			stu[i].number = i + 1;
			// 年级在1-6之间取随机数
			stu[i].state = (int) (Math.random() * (6 - 1 + 1) + 1);
			// 成绩在0-100范围
			stu[i].score = (int) (Math.random() * (100 - 0 + 1) + 1);
		}
		// 遍历学生数组
		for (int i = 0; i < stu.length; i++) {
    
    
			// System.out.println(stu[i]); 输出的结果为地址
			// 对于这类引用类型的变量,不是null那么就存地址
			// 这里因为stu已经new了,那么它就已经不是null了
			// 如果我们需要打印出值,我们需要引用它
			System.out.println(stu[i].number + "," + stu[i].state + "," +stu[i].score);
		}
		// 使用方法来实现
		// 方法1:
		for (int j = 0; j < stu.length; j++) {
    
    
			String info = stu[j].Studentinfo();
			System.out.println(info);
		}
		// 方法2:
		for (int j = 0; j < stu.length; j++) {
    
    
			System.out.println(stu[j].Studentinfo());
		}
		
		//打印出state3年级学生的成绩
		for (int j = 0; j < stu.length; j++) {
    
    
			if(stu[j].state==3) {
    
    
				System.out.println(stu[j].Studentinfo());
			}
		}
		//使用冒泡排序队学生成绩排序
		for(int i=0;i<stu.length-1;i++) {
    
            //控制每一大轮
			for(int j=0;j<stu.length-1-i;j++) {
    
      //控制每一轮中的交换
				if(stu[j].score>stu[j+1].score) {
    
    
					student temp=stu[j];
					stu[j]=stu[j+1];
					stu[j+1]=temp;
				}
			}
		}
		for (int i = 0; i < stu.length; i++) {
    
    
			System.out.println(stu[i].number + "," + stu[i].state + "," +stu[i].score);
		}
	}
}

class student {
    
    
	// 属性
	int number; // 学号
	int state; // 年级
	int score; // 成绩
	// 方法
	// 显示学生信息
	public String Studentinfo() {
    
    
		return "学号" + number + "年级" + state + "成绩" + score;
	}
}

【注意】:在冒泡排序中我们需要注意的是,我们定义临时变量时不要忘记变量类型是student

student temp=stu[j];

然后就是在交换时,错误的写法是:

student temp.score=stu[j];
stu[j].score=stu[j+1].score;
stu[j+1].score=temp;

因为如果只对score进行交换那么该学生的成绩即是别人的成绩了,因此在交换时要交换的是这个学生的整个属性

实例4:对实例三的改进

将操作数组的功能封装到方法中

public class Students_class02 {
    
    
	public static void main(String[] args) {
    
    
		// 声明20个对象
		// student s1=new student(); //太多了
		// 声明student类型的数组
		student1[] stu = new student1[20]; // 对象数组

		for (int i = 0; i < 20; i++) {
    
    
			// 给数组元素赋值
			stu[i] = new student1();
			// 给student对象属性赋值
			stu[i].number = i + 1;
			// 年级在1-6之间取随机数
			stu[i].state = (int) (Math.random() * (6 - 1 + 1) + 1);
			// 成绩在0-100范围
			stu[i].score = (int) (Math.random() * (100 - 0 + 1) + 1);
		}
		Students_class02 test=new Students_class02 ();     //在Students_class02 中造了方法,我们在使用前需要new一个对象
		test.traverse_print(stu);
		test.searchState(stu,6);
		test.sort(stu);
	}
	//遍历
	public void traverse_print(student1[] stu) {
    
    
		for (int i = 0; i < stu.length; i++) {
    
    
			System.out.println(stu[i].number + "," + stu[i].state + "," + stu[i].score);
		}
	}
	//选择年级
	public void searchState(student1[] stu, int state) {
    
    
		for (int j = 0; j < stu.length; j++) {
    
    
			if (stu[j].state == state) {
    
    
				System.out.println(stu[j].Studentinfo());
			}
		}
	}
	//按成绩排序
	public void sort(student1[] stu) {
    
    
		for (int i = 0; i < stu.length - 1; i++) {
    
     // 控制每一大轮
			for (int j = 0; j < stu.length - 1 - i; j++) {
    
     // 控制每一轮中的交换
				if (stu[j].score > stu[j + 1].score) {
    
    
					student1 temp = stu[j];
					stu[j] = stu[j + 1];
					stu[j + 1] = temp;
				}
			}
		}
	}
}
class student1 {
    
    
	// 属性
	int number; // 学号
	int state; // 年级
	int score; // 成绩
	// 方法
	// 显示学生信息
	public String Studentinfo() {
    
    
		return "学号" + number + "年级" + state + "成绩" + score;
	}	
}

面向对象的知识点总结

1.面向对象思想编程内容的三条主线是什么

​ a.类及类的成员:属性、方法、构造器、代码块、内部类

​ b.面向对象的三大特征:封装、继承、多态

​ c.其它关键字:this,super,abstract,interface,static,final,package,import

面向对象的编程思想?

2.面向对象中类和对象的理解:对象是类的实例化(对象是由类new出来的)

​ 类:抽象的、概念上的内容

​ 对象:实实在在存在的一个个体(在内存中真正占据空间)

3.类和对象的创建和执行操作的三步

创建类------>类的实例化------>调用对象的结构:“对象.属性” “对象.方法”

4.内存分配情况

img

5.面向过程:功能行为,以函数为最小单位

​ 面向对象:强调了具备了功能的对象

6.内存解析说明

preson p1=new person();
preson p2=new person();
preson p3=p1;    //没有新建一个对象,共用一个堆空间

JVM(java虚拟机)内存结构

编译完源程序以后,生成一个或多个字节码文件,我们使用JVM类的加载器和解释器对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析

我们将new出来的结构(比如:数组、对象)加载到空间中。补充:对象的属性(非static的)加载到堆空间中

万事万物皆对象

1.在Java语言范畴中,我们都将功能结构等封装到类中,通过类的实例化,来调用具体的功能结构

2.涉及到java语言与前端HTML、后端数据库交互时,前后端结构在java层面交互时,都体现为类、对象

​ Scanner,String等

​ 文件、File

​ 网络资源,URL

对象数组的内存解析

img

匿名对象的使用

代码引入:

public class Anonymous_Objects {
    
    
	public static void main(String[] args) {
    
    
		Phone p=new Phone();
		//p=null;
		System.out.println(p);    //带类型的地址
		p.playGame();
		p.sendEmail();  //有名字的对象:p(对象名)
		
		//匿名对象
		new Phone().sendEmail();
		new Phone().playGame();   //这两个用的就不是一个对象了(每new一个就是一个新对象)
		
		new Phone().price=1999;
		new Phone().showPrice();  //0.0(double类型,再次说明不是同一对象了)
	}
}
class Phone{
    
    
	double price;
	public void sendEmail() {
    
    
		System.out.println("发送邮件");
	}
	public void playGame() {
    
    
		System.out.println("玩游戏");
	}
	public void showPrice() {
    
    
		System.out.println(price);
	}
}

理解:

1.我们创建的对象,没有显示的赋给一个变量名,即为匿名对象

2.特征:匿名对象只能调用一次

3.使用:如下

class PhoneMall{
    
    
	public void showPhone(Phone iphone) {
    
      //
		iphone.sendEmail();
		iphone.playGame();
	}
}

PhoneMall p2=new PhoneMall();
p2.showPhone(new Phone());//匿名对象(new一个Phone类型的对象,只使用这一次)

自定义数组的工具类

通过上述的代码,我们体会到了将具体的思路封装到方法中,在我们使用的时候只需要调用这个方法即可,给我们程序带来了极大的方便,因此我们可以试着将数组的一系列方法也给包装到方法中去

//自定义数组工具类
public class Custom_Array_Tool_Class {
    
    
	// 求数组的最大值
	public int getMax(int[] arr) {
    
    
		int maxValue = arr[0];
		for (int i = 0; i < arr.length; i++) {
    
    
			if (maxValue < arr[i]) {
    
    
				maxValue = arr[i];
			}
		}
		return maxValue;
	}

	// 求数组的最小值
	public int getMin(int[] arr) {
    
    
		int minValue = arr[0];
		for (int i = 0; i < arr.length; i++) {
    
    
			if (minValue > arr[i]) {
    
    
				minValue = arr[i];
			}
		}
		return minValue;
	}

	// 求数组的总和
	public int getSum(int[] arr) {
    
    
		int sum = 0;
		for (int i = 0; i < arr.length; i++) {
    
    
			sum += arr[i];
		}
		return sum;
	}

	// 求数组的平均值
	public double getAverage(int[] arr) {
    
    
		int sum = 0;
		for (int i = 0; i < arr.length; i++) {
    
    
			sum += arr[i];
		}
		double averageValue = (sum * 1.0) / arr.length;
		return averageValue;
	}

	// 反转数组
	public void flipsArray(int[] arr) {
    
    
		for (int i = 0; i < arr.length / 2; i++) {
    
    
			int temp = arr[i];
			arr[i] = arr[arr.length - 1 - i];// 这里需要注意数组下标为arr.length-1代表的是最后一个元素
			arr[arr.length - 1 - i] = temp;
		}
	}

	// 复制数组
	public void copyArray(int[] arr) {
    
    
		int[] arr_copy = new int[arr.length];
		for (int i = 0; i < arr.length; i++) {
    
    
			arr_copy[i] = arr[i];
		}
	}

	// 数组排序
	public void sortArray(int[] arr) {
    
    
		for (int i = 0; i < arr.length; i++) {
    
    
			for (int j = 0; j < arr.length - 1 - i; j++) {
    
    
				if (arr[j] < arr[j + 1]) {
    
    
					int tem = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = tem;
				}
			}
		}
	}

	// 遍历数组
	public void throughArray(int[] arr) {
    
    
		for (int i = 0; i < arr.length; i++) {
    
    
			System.out.print(arr[i] + "\t");
		}
	}

	// 查找指定元素(线性查找)
	public int searchElement(int[] arr, int target) {
    
    
		for (int i = 0; i < arr.length; i++) {
    
            //这样就不用像之前那样再定义布尔变量啥的了
			if (target == arr[i]) {
    
    
				return i;
			}
		}
		return -1;//返回负数代表没找到
	}
}

测试:(使用)

//使用我们自定义的数组工具Custom_Array_Tool_Class
public class Use_My_Arraytools {
	public static void main(String[] args) {
		
		Custom_Array_Tool_Class tool=new Custom_Array_Tool_Class();      //对象是类的实例化
		int[]arr=new int[]{32,45,67,44,-11,22,78,100,-56,-99,28};
		int max=tool.getMax(arr);
		System.out.println("最大值为:"+max);
		int min=tool.getMin(arr);
		System.out.println("最小值为:"+min);
		//等等
	}
}

再谈方法:方法的重载

1.概念:在同一个类中,允许在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可

​ 两同一不同:同一个类、相同方法名

​ 参数列表不同;参数个数不同;参数类型不同

2.举例:Arrays类中重载的sort()/binarySearch()

​ 调用System.out.println()方法就是经典的方法的重载

3.判断是否重载:

​ 跟方法的权限修饰符、返回值类型、形参变量名、方法都没有关系

4.在通过对象调用方法时,如何确定某一个指定方法:

​ 方法名------>参数列表

再谈方法:可变个数的形参

1.jdk5.0新增的内容

2.具体使用

​ 2.1格式

public void show(String ... strs){
    
    
    System.outy.println("show(String ... strs)");
}

​ 2.2当调用可变个数形参方法时,传入的参数个数可以是0个、1个、2个…

​ 2.3可变个数形参的方法与本类中方法名相同,形参不同的方法直接构成重载

​ 2.4可变个数形参的方法与本来中方法名相同,形参类型也相同的数组之间不构成重构(换句话说:二者不能共存)

意思是两者可以相互的取代

public void show(String ... strs){
    
    
    System.outy.println("show(String ... strs)");
}
public void show(String[] strs){
    
    
    System.outy.println("show(String ... strs)");
}

并且在调用时两者也可以相互的表示

test.show(new String[]{
    
    "AA","BB","CC"});
test.show("AA","BB","CC");

因此我们可以理解为:系统对于可变个数的形参,仍然是把它当作一个数组,但是相比数组来说书写更简单

​ 2.5可变个数形参在方法的形参中,必须声明在末尾

public void show(int i,String ... strs);   //right
public void show(String ... strs,int i);   //wrong

​ 2.6可变个数形参在方法的形参中,最多只能声明一个可变形参

再谈方法:方法参数的值传递机制

变量的赋值

public class Value_of_Method {
    
    
	public static void main(String[] args) {
    
    
		// 对于引用数据类型的值传递
		Order o1 = new Order();
		o1.OrderId = 1;
		Order o2 = o1;
		System.out.println("o1.OrderId=" + o1.OrderId + "\t" + "o2.OrderId=" + o2.OrderId);

		o2.OrderId = 2;
		System.out.println("o1.OrderId=" + o1.OrderId + "\t" + "o2.OrderId=" + o2.OrderId);
	}
}

class Order {
    
    
	int OrderId;
}

运行结果如下:

image-20220920160953365

分析:赋值以后,对于引用数据变量类型来说,o1和o2的地址值相同,都指向了堆空间中同一个对象实体

关于变量的赋值:

1.如果变量是基本数据类型,此时赋值的是变量所保存的数据值

2.如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值

方法形参的值传递机制

1.形参:方法定义时,声明的小括号内的参数

实参:方法调用时,实际传递给形参的数据

2.值传递机制

引入:

public class Value_Transfer02 {
    
    
	public static void main(String[] args) {
    
    
		int m=10;
		int n=20;
		System.out.println("m="+m+",n="+n);
		//交换两个变量
		//int temp=m;
		//m=n;
		//n=temp;
		//交换的操作很常用,我们不妨将此封装到方法中
		Value_Transfer02 useSwap=new Value_Transfer02();
		useSwap.Swap(m,n);
		System.out.println("m="+m+",n="+n);
	}
	
	public void Swap(int m,int n){
    
    
		int temp=m;
		m=n;
		n=temp;
	}
}

运行结果如下:

image-20220920162605973

我们发现并未达到我们的交换的目的!

通过内存来理解:

img

造成原因:如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值

img

因此:如果变量是引用数据类型,此时赋值的变量所保存的数据的地址值

运用到数组上:

public class Arraysorting_class {
    
    
	public static void main(String[] args) {
    
    
		int[] arr=new int[] {
    
    -12,22,45,-87,-22,56,78,23,-66};
		Arraysorting_class arrnum=new Arraysorting_class();
		for(int i=0;i<arr.length;i++) {
    
    
			for(int j=0;j<arr.length-1-i;j++) {
    
    
				if(arr[j]<arr[j+1]) {
    
    
					arrnum.Swap(arr, i, j);
				}
			}
		}
		for(int i=0;i<arr.length;i++) {
    
    
			System.out.print(arr[i]+" ");
		}
	}
	public void Swap(int[] arr,int i,int j) {
    
    
		int tem=arr[j];
		arr[j]=arr[j+1];
		arr[j+1]=tem;
	}
}

【总结】:值传递机制

​ 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值

​ 如果变量是引用数据类型,此时赋值的变量所保存的数据的地址值

实例:

public class UseClass_Circle {
    
    
	//main方法
    public static void main(String[] args) {
    
    
		PassObject Use=new PassObject();
		Circle c=new Circle();
		Use.printAreas(c, 5);
		System.out.println("now radius is:"+c.radius);
	}
}
//输出半径和对应的圆面积
public class PassObject {
    
    

	public void printAreas(Circle c, int time) {
    
    //在这里已经定义了一个Circle类型的形参c了
		System.out.println("Radius\t\tArea");
		for (int i = 1; i <= time; i++) {
    
    
			c.radius = i;
			// 不用匿名对象
			double area = c.findArea();
			System.out.println(c.radius + "\t\t" + area);
			// 用匿名对象
			// System.out.println(c.radius + "\t\t" + c.findArea());
		}
		c.radius = time + 1;
	}
}
//Circle类
class Circle {
    
    
	double radius;

	public double findArea() {
    
    
		return 3.14 * radius * radius;
	}
}

再谈方法:递归方法的使用

1.递归方法:一个方法体内调用它自身

2.方法的递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无需控制循环;递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环

实例1:求和

public class Recursion_Test {
    
    
	public static void main(String[] args) {
    
    
		//实例1:计算1-100所有自然数的和
		//循环
		int sum=0;
		for(int i=1;i<=100;i++) {
    
    
			sum+=i;
		}
		System.out.println(sum);
		Recursion_Test Test=new Recursion_Test();
		int Result=Test.getSum(100);
		System.out.println(Result);
		//System.out.println(Test.getSum(100));//匿名对象
	}
		
	
	//递归方法
	public int getSum(int n){
    
    //前n个数求和等于前n-1个数求和加上第n个数
		if(n==1) {
    
    
			return 1;
		}
		else {
    
    
			return n+getSum(n-1);
		}
	}
}

同理的,我们可以写出n的阶乘的计算

实例2:求阶乘

public int getFactorial(int n){
    
    
		if(n==1) {
    
    
			return 1;
		}
		else {
    
    
			return n*getFactorial(n)
		}
	}
}

实例3:应用

已知有一个数组:f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n),其中n是大于0的整数,求f(10)的值

//已知有一个数组:f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n),其中n是大于0的整数,求f(10)的值
public class Recursion_Test2 {
    
    
	public static void main(String[] args) {
    
    
		Recursion_Test2 Use = new Recursion_Test2();
		int Result = Use.getNum(10);
		System.out.println(Result);
	}

	public int getNum(int n) {
    
    
		if (n == 0) {
    
    
			return 1;
		} else if (n == 1) {
    
    
			return 4;
		} else {
    
    
			return 2 * getNum(n - 1) + getNum(n - 2);
            // f(n+2)=2*f(n+1)+f(n)--->f(n)=2*f(n-1)+f(n-2)
		}
	}
}

实例4:斐波那契数列

//斐波那契数列
public class Recursion_Test3 {
    
    
	public static void main(String[] args) {
    
    
		Recursion_Test3 Use=new Recursion_Test3();
		System.out.println(Use.Fibonacci(10));
	}
	public int Fibonacci(int n) {
    
    
		if(n==1) {
    
    
			return 1;
		}
		else if(n==2) {
    
    
			return 1;
		}
		else {
    
    
			return Fibonacci(n-1)+Fibonacci(n-2);
		}
	}
}

阶段性总结

1.什么是方法的重载?

​ 两同一不同:同一个类、相同方法名

​ 参数列表不同;参数个数不同;参数类型不同

------>如何调用一种确定的方法:方法名------>参数列表

方法的重载和重写的区别?:没什么关系

2.java方式中参数传递机制的继续体现

​ 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值

​ 如果变量是引用数据类型,此时赋值的变量所保存的数据的地址值(含变量的数据类型)

3.成员变量和局部变量

4.return关键字的使用:结束方法、针对于有返回值的方法:return+返回数据

5.内存结构:栈(局部变量)、堆(new出来的结构:对象(成员变量)、数组)

面向对象特征一:封装与隐藏

封装性的引入

我们程序设计追求:“高内聚,低耦合”

高内聚:类的内部数据操作细节自己完成,不允许外部干涉

低耦合:仅对外暴露少量的方法用于使用

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想

引入:当我们创建一个类的对象后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没有其它制约条件;但是在实际问题中,我们往往要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如,setLegs,同时我们要避免用户再使用"对象.属性“的方式对属性进行赋值。则需要将属性声明为私有的(private),此时针对于属性就体现了封装性

public class Animal_Test {
    
    
	public static void main(String[] args) {
    
    
		Animal a=new Animal();
		a.name="Peter";
		a.age=2;
		a.setLegs(4);
		a.show();
		//a.legs=-4;    //虽然我们设计了方法setLegs能对输入的不合法数据进行辨析,但是我们							仍然能通过访问属性来修改legs的值
		//因此我们将属性legs设为一个私有属性:private,就不能在修改了
	}
}
class Animal{
    
    
	String name;
	int age;
	private int legs;  //腿的个数
	
	public void eat() {
    
    
		System.out.println("动物吃东西");
	}
	public void show() {
    
    
		System.out.println("name="+name+",age="+age+",legs="+legs);
	}
	//对属性的设置
	public void setLegs(int l) {
    
    
		if(l>=0&&l%2==0) {
    
    
			legs=l;
		}
		else {
    
    
			legs=0;
		}
	}
	//对属性的获取
	public int getLegs() {
    
    
		return legs;
	}
}

封装性的体现

我们将类的属性私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx);这样的话:

a.legs=4;     //wrong

四种权限修饰符

封装性的体现,需要权限修饰符来配合

1.java规定的四种权限(从小到大排列):

private、缺省、protected、public

缺省的意思就是什么都没有写

image-202209211352522252.四种权限可以修饰类及类的内部结构:属性、方法、构造器、内部类

3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类

修饰类的话,只能用:缺省、public

总结封装性:java提供了四种权限修饰来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小

类的成员(3):构造器

任何一个类都有构造器(Constructor)

类的前两个成员:属性和方法

构造器的作用:

1.创建对象(new对象时new接的都是构造器)

2.初始化对象的属性

//创建对象
public class PersonTest {
    
    
	public static void main(String[] args) {
    
    
		//创建类的对象:new+构造器
		Person p=new Person();  //Person():构造器
		p.eat();
	}
}
class Person{
    
    
	//属性
    String name;
	int age;
	//方法
	public void eat() {
    
    
		System.out.println("人可以吃饭");
	}
	public void sleep() {
    
    
		System.out.println("人可以睡觉");
	}
}

说明

1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器

2.定义构造器的格式:

权限修饰符 类名(形参列表){    //构造器名与类同名

}

class Person{
    
    
	//属性
    String name;
	int age;
	//构造器
    //作用1:创建对象
	public Person() {
    
    
		System.out.println("已被调用");
	}
    //作用2:给对象进行初始化
    public Person(String s){
    
    
        name=s;
    }
	//方法
	public void eat() {
    
    
		System.out.println("人可以吃饭");
	}
	public void sleep() {
    
    
		System.out.println("人可以睡觉");
	}
}

3.一个类种定义多个构造器,彼此构成重载

4.一旦我们显示定义了类的构造器之后,系统就不再提供默认的空参构造器

5.一个类中,至少会有一个构造器(默认/自己写的)

实例:三角形

public class TriangleTest {
    
    
	public static void main(String[] args) {
    
    
		Triangle t1=new Triangle();
		t1.setBase(2.0);
		t1.setHight(2.4);
		//t1.base=2.5;     wrong:private(存在但不可见)
		System.out.println("base:"+t1.getBase()+",hight:"+t1.getHight());
		//通过构造器的初始化
		Triangle t2=new Triangle(4.0,2.5);
		System.out.println("base:"+t2.getBase()+",hight:"+t2.getHight());
	}
}
public class Triangle {
    
    
	private double base;    //底
	private double hight;   //高
	
	//构造器
	public Triangle() {
    
    
		//空参
	}
	public Triangle(double b,double h) {
    
    
		base=b;
		hight=h;
	}
	
	public void setBase(double b) {
    
    
		base=b;
	}
	public double getBase() {
    
    
		return base;
	}
	public void setHight(double h) {
    
    
		hight=h;
	}
	public double getHight() {
    
    
		return hight;
	}
}

总结:属性赋值的先后属性

1.默认初始化

2.显式初始化

3.构造器中赋值

4.通过“对象.方法”(封装性)或“对象.属性”赋值

以上操作的先后顺序: 1------>2------>3------>4

javaBean

javaBean是一种Java语言写成的可重用组件

所谓javaBean,是指符合如下标准的java类:

类是公开的
一个无参的公共的构造器
有属性,且有对应的get、set方法
//javaBean
public class customer2 {
    
       //类是公开的
	private int id;
	private String name;

	public customer2() {
    
    
						   //一个无参的公共的构造器
	}
	//有属性,且有对应的get、set方法
	public void setId(int i) {
    
    
		id = i;
	}

	public int getId() {
    
    
		return id;
	}

	public void setName(String s) {
    
    
		name = s;
	}

	public String getname() {
    
    
		return name;
	}
}

关键字:this的使用

this关键字的使用:

1.this可以用来修饰:属性、方法、构造器

2.this理解为:当前对象

​ 2.1在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表面此变量是属性,而非形参

​ 2.2在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表面此变量是属性,而非形参

实例:account

public class Account {
    
    
	//属性
	private int id;     //账号
	private double balance; //余额
	private double annualInterestRate; //年利率
	//构造器
	public Account(int id,double balance,double annualInterestRate) {
    
    
		this.id=id;
		this.balance=balance;
		this.annualInterestRate=annualInterestRate;
	}
	//get/set方法:Source
	public int getId() {
    
    
		return id;
	}
	public void setId(int id) {
    
    
		this.id = id;
	}
	public double getBalance() {
    
    
		return balance;
	}
	public void setBalance(double balance) {
    
    
		this.balance = balance;
	}
	public double getAnnualInterestRate() {
    
    
		return annualInterestRate;
	}
	public void setAnnualInterestRate(double annualInterestRate) {
    
    
		this.annualInterestRate = annualInterestRate;
	}
	//取钱
	public void withdraw(double amount) {
    
    
		if(balance<amount) {
    
    
			System.out.println("余额不足");
		}
		else {
    
    
			System.out.println("成功取出"+amount+"元");
		}
	}
	public void deposit(double amount) {
    
    
		if(amount>0) {
    
    
			balance+=amount;
			System.out.println("成功存入:"+amount+"元");
		}
	}
}
public class Customer {
    
    
	private String firstName;
	private String lastName;
	private Account account;     //在属性中出现自定义类型的变量(引用数据类型)
	//构造器
	public Customer(String f,String l) {
    
    
		this.firstName=f;
		this.lastName=l;
	}
	//get-set
	public String getFirstName() {
    
    
		return firstName;
	}
	public void setFirstName(String firstName) {
    
    
		this.firstName = firstName;
	}
	public String getLastName() {
    
    
		return lastName;
	}
	public void setLastName(String lastName) {
    
    
		this.lastName = lastName;
	}
	public Account getAccount() {
    
    
		return account;
	}
	public void setAccount(Account account) {
    
    
		this.account = account;
	}
}
public class Test {
    
    
	public static void main(String[] args) {
    
    
		Customer c=new Customer("peter","smith");         //先实例化一个客户
		Account a=new Account(1000, 2000, 0.0123);        //再为它创建一个账户
		c.setAccount(a);                                  //这样这个账户就是这个客户的了    
		//可以连续.(访问)
		c.getAccount().deposit(100);   //存入100
		c.getAccount().withdraw(1000); //取出1000
		c.getAccount().withdraw(50);
	}
}

【总结】:

1.关联关系:在属性中出现自定义类型的变量(引用数据类型)

2.对象数组(定义多个变量,本身就输入引用类型,也可以作为属性出现)

3.连续操作

c.getAccount().deposit(100);  
c.getAccount().withdraw(1000); 
c.getAccount().withdraw(50);

注意的是,前面的方法一定是有返回值,形成新的对象,再调用下一个属性或方法

关键字:package的使用

1.为了更好的实现项目中类的管理,提供包的概念

2.使用package声明类或接口所属的包,声明在源文件的首行

image-20220926111314185

3.包,属于标识符,遵循标识符的命名规则、规范、见名知意

4.每"."一次就代表一层文件目录

补充:同一个包下,不能命名同名的接口、类

​ 不同的包下,可以命名同名的接口、类

关键字:import的使用

import:导入

1.在源文件中显式的使用import结构导入指定包下的类、接口

2.声明在包的声明和类的声明之间

3.如果需要导入多个结构,则并列写出即可

4.可以用“xxx.*”的方式,表示可以导入xxx包下的所有结构

//并列写出
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
//或者:
import java.util.*;

5.如果使用的类或接口是java.lang包下定义的,则可以省略import结构

6.如果使用的类或接口是本包下定义的,则可以省略import结构

7.如果在源文件中,使用了不同包下的同名的类,必须至少一个类使用全类名的方式显式

8.使用“xxx.*”的方式表面可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入

9.import static:导入指定类或接口中静态结构(属性或方法)

MVC设计模式

image-20220926115203778

猜你喜欢

转载自blog.csdn.net/kevvviinn/article/details/129420908