【Java基础】第4章_面向对象(上)-1:类、对象、属性、方法

PPT链接:点击这里

1、面向过程与面向对象

面向过程(POP) 与面向对象(OOP)

  • 面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做
  • 面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做
    image-20220719085601637

1.1、面向对象的三条主线

  • Java 类及类的成员:属性方法构造器代码块内部类
  • 面向对象的三大特征:封装继承多态性(抽象性)
  • 其它关键字:thissuperstaticfinalabstractinterfacepackageimport

1.2、面向对象的思想概述

image-20221109032155723

2、 类和对象

面向对象的两个要素

  • 类:对一类事物的描述,是抽象的、概念上的定义

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

① 可以理解为:类 = 抽象概念的人对象 = 实实在在的某个人

② 面向对象程序设计的重点是类的设计

③ 设计类,其实就是设计类的成员

2.1、Java 类及类的成员

  • 属性:对应类中的成员变量
  • 行为:对应类中的成员方法
    image-20220719090545694

2.2、类与对象的创建及使用

  • 属性 = 成员变量 = 字段 = field
  • 方法 = 成员方法 = 函数 = method
  • 创建类的对象 = 类的实例化 = 实例化类

类和对象的使用(面向对象思想落地的实现)

  1. 创建类,设计类的成员

  2. 创建类的对象

  3. 通过对象.属性对象.方法调用对象的结构

类的访问机制

image-20220719094638141

public class PersonTest {
	public static void main(String[] args) {
        
		//2. 创建Person类的对象
		Person p1 = new Person();
		
		//调用对象的结构:属性、方法
		//调用属性:“对象.属性”
		p1.name = "Tom";
		p1.isMale = true;
		System.out.println(p1.name);
		
		//调用方法:“对象.方法”
		p1.eat();
		p1.sleep();
		p1.talk("Chinese");
		
		//********************************************
		Person p2 = new Person();
		System.out.println(p2.name);//null
		System.out.println(p2.isMale);//false
		//********************************************
		//将p1变量保存的对象地址值赋给p3,导致p1和p3指向了堆空间中的同一个对象实体
		Person p3 = p1;
		System.out.println(p3.name);//Tom
		p3.age = 10;
		System.out.println(p1.age);//10
		
	}
}

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

如果创建一个类的多个对象,那么每个对象都独立的拥有一套类的属性(非 static 的),这意味着如果我们修改一个对象的属性 a,则不影响另外一个对象属性 a 的值

2.3、对象的内存解析

image-20220719095640867

  • 堆(Heap):此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在 Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配
  • 栈(Stack):是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不等同于对象本身,是对象在堆内存的首地址)。方法执行完,自动释放
  • 方法区(MethodArea):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

【案例 1】

image-20220719185018273

【案例 2】

image-20220719185145055

【案例3】

image-20220719185315837

3、类的成员之一:属性(成员变量)

成员变量 与 局部变量的 ---- 相同点

  1. 定义变量的格式:数据类型 变量名 = 变量值
  2. 先声明,后使用
  3. 变量都有其对应的作用域

成员变量 与 局部变量的 ---- 不同点

  1. 在类中声明的位置不同
    1. 成员变量:直接定义在类的一对{}
    2. 局部变量:声明在方法内、方法形参、构造器内、构造器形参的变量
  2. 关于权限修饰符的不同
    1. 成员变量:可以在声明成员变量时,使用权限修饰符指明其权限;常用的权限修饰符:privatepublic缺省protected
    2. 局部变量:不可以使用权限修饰符
  3. 默认初始化值的情况
    1. 成员变量(类的属性):根据其类型,都有默认初始化值
      1. 整型(byte、short、int、long):0
      2. 浮点型(float、double):0.0
      3. 字符型(char):0(或‘\u0000’)
      4. 布尔型(boolean):false
      5. 引用数据类型(类、数组、接口):null
    2. 局部变量:没有默认初始化值
      1. 意味着:在调用局部变量之前,一定要显式赋值
      2. 特别地:形参在调用时,赋值即可
  4. 在内存中加载的位置,亦各不相同
    1. 成员变量:加载到堆空间中(非 static)
    2. 局部变量:加载到栈空间
      image-20220719222949342
public class UserTest {
	public static void main(String[] args) {
		User u1 = new User();
		System.out.println(u1.name);//null
		System.out.println(u1.age);//0
		System.out.println(u1.isMale);//false
		
		u1.talk("韩语");
		u1.eat();
	}
}

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);
	}
}

4、类的成员之二:方法

4.1、类中方法的声明和使用

方法的声明

权限修饰符 返回值类型 方法名(形参列表){
	方法体;
}
//方法:描述类应该具有的功能

注意:staticfinalabstract也能修饰方法

举例:public void eat(){}public void sleep(int hour){}public String getName(){}public String getNation(String nation){}

说明

  • 关于权限修饰符:默认方法的权限修饰符先都使用public,Java规定的4种权限修饰符:private、public、缺省、protected
  • 返回值类型: 有返回值 vs 没有返回值
    • 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:return 数据
    • 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要使用return。但是,如果使用的话,只能return;表示结束此方法的意思
  • 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
  • 形参列表:方法名可以声明0个、1个,或多个形参
    • 格式:数据类型1 形参1,数据类型2 形参2,...
  • 方法体:方法功能的体现

return 关键字的使用

  • 使用范围:使用在方法体中
  • 作用:① 结束方法;② 针对于有返回值类型的方法,使用return 数据方法返回所要的数据
  • 注意:return关键字后不可声明执行语句

注意:在方法的使用中

  • 可以调用当前类的属性或方法
  • 特殊的:方法A中又调用了方法A → 递归方法
  • 方法中不能定义其他方法
public class CustomerTest {
	public static void main(String[] args) {
		
		Customer cust1 = new Customer();
		cust1.eat();
		cust1.sleep(8);
	}
}
//客户类
class Customer{
	
	//属性
	String name;
	int age;
	boolean isMale;
	
	//方法
	public void eat(){
		System.out.println("客户吃饭");
		return;//return后不可以声明表达式
	}
	
	public void sleep(int hour){
		System.out.println("休息了" + hour + "个小时");
		
		eat();
//		sleep(10);//递归
	}
	
	public String getName(){
		if(age > 18){
			return name;
		}else{
			return "Tom";
		}
	}
	
	public String getNation(String nation){
		String info = "我的国籍是:" + nation;
		return info;
	}
	
	public void info(){ //错误,方法中不能定义其他方法
//		public void swim(){
//			
//		}
	}
}

4.2、理解 “万事万物皆对象”

  • 在Java语言范畴中,我们将结构、功能等封装到类中,通过类的实例化,来调用具体的结构功能
    • Scanner,String等
    • 文件:File
    • 网络资源:URL
  • 涉及到Java语言与前端html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象

4.3、对象数组的内存解析

引用类型的变量,只可能存储量两类值:null 或 地址值(含变量类型)

【案例1】

Student[] stus= new Student[5];//引用数据类型都是null
stus[0] = new Student();//将Student类中3个属性的地址值赋给stus[0]
sysout(stus[0].state);//1
sysout(stus[1]);//null
sysout(stus[1].number);//异常
stus[1] = new Student();
sysout(stus[1].number);//0

class Student{
  int number;//学号
  int state = 1;//年级
  int score;//成绩
}

image-20220719223405614

【案例2】

image-20220719223611129

4.4、匿名对象的使用

  • 理解:创建的对象,没有显示的赋值给一个变量名,即为匿名对象

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

public class InstanceTest {
	public static void main(String[] args) {
        
		Phone p = new Phone();
		System.out.println(p);//地址值
        
		p.sendEmail();//这两个p都指向堆空间中的同一个对象
		p.playGame();
		
		//匿名对象
		new Phone().sendEmail();//这里new了两个对象,堆空间中有两个不同的区域
		new Phone().playGame();
		
		new Phone().price = 1999;//道理同上
		new Phone().showPrice();//0.0
		
		//************************************************
		PhoneMall mall = new PhoneMall();
		mall.show(p);
		//匿名对象的使用
		mall.show(new Phone());//传参
	}
}

class PhoneMall{
    //方法中的形参可以是任意数据类型,即可以使Phone类型,通过Phone类的对象调用Phone类中的属性和方法
	public void show(Phone phone){
		phone.sendEmail();
		phone.playGame();
	}
}

class Phone{
	double price;//价格
	
	public void sendEmail(){
		System.out.println("发送邮件");
	}
	public void playGame(){
		System.out.println("玩游戏");
	}
	public void showPrice(){
		System.out.println("手机价格为:" + price);
	}
}

4.5、自定义数组的工具类

求数组的最大值、最小值、总和、平均值、反转数组、复制数组、数组排序、遍历数组、查找指定元素

class ArrayUtil {
	//*****求数组的最大值*****
	public int getMax(int[] arr) {//传递数组的地址值
		int maxValue = arr[0];
		for (int i = 1; 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 = 1; 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 int getAvg(int[] arr) {
		int avgValue = getSum(arr) / arr.length;
		return avgValue;
	}

	//*****反转数组*****
	public void reverse(int[] arr) {
		for (int i = 0; i < arr.length / 2; i++) {
			int temp = arr[i];
			arr[i] = arr[arr.length - i - 1];
			arr[arr.length - i - 1] = temp;
		}
	}

	//*****复制数组*****
	public int[] copy(int[] arr) {//返回数组类型
		int[] arr1 = new int[arr.length];
		for (int i = 0; i < arr1.length; i++) {//i的大小是由arr1.length决定的
			arr1[i] = arr[i];
		}
		return arr1;
	}

	//*****数组排序*****
	public void sort(int[] arr) {
		// 冒泡排序
		for (int i = 0; i < arr.length - 1; i++) {
			for (int j = 0; j < arr.length - 1 - i; j++) {
				if (arr[j] > arr[j + 1]) {
//					int temp = arr[j];
//					arr[j] = arr[j + 1];
//					arr[j + 1] = temp;
					//或者
					swap(arr,j,j + 1);
				}
			}
		}
	}
	//*****交换数组中指定两个位置元素的值*****
	public void swap(int[] arr,int i,int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}

	//*****遍历数组*****
	public void print(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + ",");
		}
	}
    
	//*****查找指定元素*****
	public int getIndex(int[] arr, int dest) {
		//线性查找
		for (int i = 0; i < arr.length; i++) {
			if (dest==arr[i]) {
				return i;//return有结束方法的作用
			}
		}
		return -1;//返回一个负数,表示没有找到
	}
}

//测试类
public class ArrayUtilTest {

	public static void main(String[] args) {
        int[] arr = new int[]{32,5,26,74,0,96,14,-98,25};
		ArrayUtil util = new ArrayUtil();
        
		int max = util.getMax(arr);
		System.out.println("最大值为:" + max);
		
		System.out.print("排序前:");
		util.print(arr);
		
		util.sort(arr);
		System.out.print("排序后:");
		util.print(arr);
		
		System.out.println("查找:");
		int index = util.getIndex(arr, 5);
		if(index > 0){
			System.out.println("找到了,索引地址:" + index);
		}else{
			System.out.println("没找到");
		}
	}
}

4.6、方法的重载(overload)

  • 定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可

  • 特点:判断是否是重载跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系

  • 在通过对象调用方法时,确定某一个指定的办法是:方法名(参数列表)

两同一不同: 同一个类、相同方法名,形参列表不同(形参个数不同,形参类型不同)

public class OverLoadTest {
    
	public static void main(String[] args) {
		OverLoadTest test = new OverLoadTest();
		test.getSum(1,2);//调用的第一个,输出1
	}

	//如下的4个方法构成了重载
	public void getSum(int i,int j){
		System.out.println("1");
	}
	public void getSum(double d1,double d2){
		System.out.println("2");
	}
	public void getSum(String s,int i){
		System.out.println("3");
	}
	public void getSum(int i,String s){
		System.out.println("4");
	}
	
	//如下的3个方法 不能 与上述4个方法构成重载
//	public int getSum(int i,int j){
//		return 0;
//	}
//	public void getSum(int m,int n){
//		
//	}
//	private void getSum(int i,int j){
//		
//	}
}

判断是否与void show(int a,char b,double c){}构成重载

a)void show(int x,char y,double z){} // no
b)int show(int a,double c,char b){} // yes
c)void show(int a,double c,char b){} // yes
d)boolean show(int c,char b){} // yes
e)void show(double c){} // yes 
f)double show(int x,char y,double z){} // no
g)void shows(){double c} // no

4.7、可变个数的形参

  • JavaSE 5.0 中提供了 Varargs(variable number of arguments) 机制,允许直接定义能和多个实参相匹配的形参。从而可以用一种更简单的方式,来传递个数可变的实参
  • 具体使用
    • 可变个数形参的格式:数据类型 ... 变量名
    • 当调用可变个数形参的方法时,传入的参数的个数可以是:0个,1个,2个…
    • 可变个数形参的方法与本类中 “方法名相同 形参不同” 的方法之间构成重载
    • 可变个数形参的方法与本类中 方法名相同,形参类型也相同 的数组之间不构成重载。即二者不可共存
    • 可变个数形参在方法中的形参中,必须声明在末尾,且最多只能声明一个可变形参
public class MethodArgs {
	public static void main(String[] args) {
        
		MethodArgs test = new MethodArgs();//因为main()是静态的,调用非静态方法就必须通过对象调用
		test.show("hello");//调用①
		test.show("hello","world");//调用②
		test.show();//调用②

		test.show(new String[] { "AA", "BB", "CC" });//传一个数组,调用②
	}

	public void show(String s){//------------------------------①
		System.out.println("show(String①)");
	}
    
	public void show(String... strs) {//可以看做数组------------②
		System.out.println("show(String ...strs②)");
		//遍历
		for (int i = 0; i < strs.length; i++) {
			System.out.println(strs[i]);
		}
	}

	//此方法与 ② 不可共存
//	public void show(String[] strs){
//	
//	}

	public void show(int i, String... strs) {//String... strs 必须声明在末尾

	}
	//The variable argument type String of the method show must be the last parameter
//	public void show(String... strs,int i,) {//错误,必须声明在末尾
//
//	}
}

4.8、方法参数的值传递机制(重点)

关于变量的赋值

  • 如果变量是基本数据类型,此时赋值的是变量所保存的 数据值
  • 如果变量是引用数据类型,此时赋值的是变量所保存的 数据的地址值
public class ValueTransferTest {
	
	public static void main(String[] args) {
		//*****************基本数据类型*****************
		int m = 10;
		int n = m;
		System.out.println("m = " + m + ", n = " + n);//m = 10, n = 10
		
		
		//*****************引用数据类型*****************
		Order o1 = new Order();
		o1.orderId = 1001;
		Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体
		System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);//o1.orderId = 1001,o2.orderId = 1001
		
		o2.orderId = 1002;
		System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);//o1.orderId = 1002,o2.orderId = 1002
	}
}

class Order{
	int orderId;
}

4.8.1、针对基本数据类型

方法的形参的传递机制:值传递

  • 形参:方法定义时,声明的小括号内的参数
  • 实参:方法调用时,实际传递给形参的数据

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

public class ValueTransferTest1 {
	public static void main(String[] args) {
		
		int m = 10;
		int n = 20;
		System.out.println("m = " + m + ", n = " + n);//m = 10, n = 20
        
        //交换两个变量的值的操作
//		int temp = m;
//		m = n;
//		n = temp;
		
		ValueTransferTest1 test = new ValueTransferTest1();
		test.swap(m, n);
		System.out.println("m = " + m + ", n = " + n);//m = 10, n = 20
	}
	
	public void swap(int m,int n){//只是swap()方法中的m n变化,main中并没有改变
		int temp = m ;
		m = n;
		n = temp;
	}
}

原理如下:

4.8.2、针对引用数据类型

如果参数是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值

public class ValueTransferTest2 {
	public static void main(String[] args) {
        
		Data data = new Data();
		data.m = 10;
		data.n = 20;
		System.out.println("m = " + data.m + ", n = " + data.n);//m = 10, n = 20

		//交换m和n的值
//		int temp = data.m;
//		data.m = data.n;
//		data.n = temp;

		ValueTransferTest2 test = new ValueTransferTest2();
		test.swap(data);//理解:两个date都指向堆空间中同一个对象实体
		System.out.println("m = " + data.m + ", n = " + data.n);//m = 20, n = 10
	}
	
	public void swap(Data data){ //因为m和n在Data类中,需要用Data类的对象调用,所以Data类的对象作为形参
		int temp = data.m;
		data.m = data.n;
		data.n = temp;
	}
}

class Data{
	int m;
	int n;
}

原理如下:

4.9、递归(recursion)方法

  • 递归方法:一个方法体内调用它自身
  • 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制
  • 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环
public class RecursionTest {
	public static void main(String[] args) {

		// 例1:计算1-100之间所有自然数的和
		// 方法1:
		int sum = 0;
		for (int i = 1; i <= 100; i++) {
			sum += i;
		}
		System.out.println("sum = " + sum);

		// 方法2:递归
		RecursionTest test = new RecursionTest();
		int sum1 = test.getSum(100);
		System.out.println("sum1 = " + sum1);
	}

	//计算1-n之间所有自然数的和
	public int getSum(int n) {
		if (n == 1) { //先算1
			return 1;
		} else {
			return n + getSum(n - 1);//从大往小进行计算
		}
	}

	// 例2:计算1-n之间所有自然数的乘积:归求阶乘(n!)的算法
	public int getSum1(int n) {
		if (n == 1) {
			return 1;
		} else {
			return n * getSum1(n - 1);//从大往小进行计算
		}
	}
    
    //例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值
	public int f(int n){
		if(n == 0){
			return 1;
		}else if(n == 1){
			return 4;
		}else{
			return 2*f(n - 1) + f(n - 2);//f(n)=f(n+2) - 2f(n+1)这样写会栈溢出
		}
	}
 
    //例4:斐波那契数列
	//例5:汉诺塔问题
	//例6:快排
}

4.10、练习

4.10.1、练习1

【代码实现】

public class Person {
	String name;
	int age;
	int sex;//sex=1表示为男性,sex=0表示为女性
	
	public void study(){
		System.out.println("studying");
	}
	
	public void showAge(){
		System.out.println("age:" + age);
	}
	
	public int addAge(int i){
		age += i;
		return age;
	}
}
public class PersonTest {
	public static void main(String[] args) {
		Person p1 = new Person();
		
		p1.name = "Tom";
		p1.age = 18;
		p1.sex = 1;
		
		p1.study();
		p1.showAge();
		
		int newAge = p1.addAge(2);//用int型接受,因为下面要用到这个值
		System.out.println(p1.name + "的年龄为" + newAge);
		System.out.println(p1.age);	//20
		
		//*******************************
		Person p2 = new Person();
		p2.showAge();	//0
		p2.addAge(10);  //也可以不用int类型接受,因为不需要输出信息,但是age已经改变
		p2.showAge();	//10
		
		p1.showAge();	//20
	}
}

4.10.2、练习2(对象数组题目)

定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息

提示:
1) 生成随机数:Math.random(),返回值类型double;  
2) 四舍五入取整:Math.round(double d),返回值类型long

【代码实现1】

public class StudentTest {
	public static void main(String[] args) {
		
//		Student s1 = new Student();//new20个对象
//		Student s1 = new Student();
//		Student s1 = new Student();
//		Student s1 = new Student();
		
		//声明Student类型的数组
		Student[] stus = new Student[20];  //String[] arr = new String[10];
		//用Student类型的数组存放
		for(int i = 0;i < stus.length;i++){
			//给数组元素赋值
			stus[i] = new Student();//给每一个元素new一个对象,stus[i]就是对象
			//给Student对象的属性赋值
			stus[i].number = (i + 1);
			//年级:[1,6]
			stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);
			//成绩:[0,100]
			stus[i].score = (int)(Math.random() * (100 - 0 + 1));
		}
		
		//遍历学生数组
		for(int i = 0;i < stus.length;i++){
//			System.out.println(stus[i].number + "," + stus[i].state + "," + stus[i].score);
			System.out.println(stus[i].info());
		}
		
		System.out.println("********************");
		//问题一:打印出3年级(state值为3)的学生信息。
		for(int i = 0;i <stus.length;i++){
			if(stus[i].state == 3){
				System.out.println(stus[i].info());
			}
		}
		
		System.out.println("********************");
		//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
		for(int i = 0;i < stus.length - 1;i++){
			for(int j = 0;j < stus.length - 1 - i;j++){
				if(stus[j].score > stus[j + 1].score){
					//如果需要换序,交换的是数组的元素:Student对象!!!
					Student temp = stus[j];//[注意]:Student temp  这里是将整个对象换位置
					stus[j] = stus[j + 1];
					stus[j + 1] = temp;
				}
			}
		}
		
		//遍历学生数组
		for(int i = 0;i <stus.length;i++){
			System.out.println(stus[i].info());
		}
		
	}
}

class Student{
	int number;//学号
	int state;//年级
	int score;//成绩
	
	//显示学生信息的方法
	public String info(){
		return "学号:" + number + ",年级:" + state + ",成绩:" + score;//谁调用就是谁的
	}
}

【代码实现2】(用封装的思想)

//1.此代码是对StudentTest.java的改进:将操作数组的功能封装到方法中
//2.优化时是将遍历 冒泡 查找三种方法封装到StudentTest1类中的,所以建立对象要用StudentTest1类,也可以新建立一个类,用这个类new对象(方法不能套方法)

public class StudentTest1 {
	public static void main(String[] args) {
		
		//声明Student类型的数组
		Student1[] stus = new Student1[20];  
		
		for(int i = 0;i < stus.length;i++){
			//给数组元素赋值
			stus[i] = new Student1();
			//给Student对象的属性赋值
			stus[i].number = (i + 1);
			//年级:[1,6]
			stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);
			//成绩:[0,100]
			stus[i].score = (int)(Math.random() * (100 - 0 + 1));
		}
		
		StudentTest1 test = new StudentTest1();
		
		//遍历学生数组
		test.print(stus);
		
		System.out.println("********************");
		//问题一:打印出3年级(state值为3)的学生信息。
		test.searchState(stus, 3);
		
		System.out.println("********************");
		//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
		test.sort(stus);
		
		//遍历学生数组
		test.print(stus);
		
	}
	
	//遍历Student1[]数组的操作
	public void print(Student1[] stus){
		for(int i = 0;i <stus.length;i++){
			System.out.println(stus[i].info());
		}
	}
	//查找Stduent数组中指定年级的学生信息
	public void searchState(Student1[] stus,int state){//在那个数组中找,找那个年纪的
		for(int i = 0;i <stus.length;i++){
			if(stus[i].state == state){
				System.out.println(stus[i].info());
			}
		}
	}
	
	//给Student1数组排序
	public void sort(Student1[] stus){
		for(int i = 0;i < stus.length - 1;i++){
			for(int j = 0;j < stus.length - 1 - i;j++){
				if(stus[j].score > stus[j + 1].score){
					//如果需要换序,交换的是数组的元素:Student对象!!!
					Student1 temp = stus[j];
					stus[j] = stus[j + 1];
					stus[j + 1] = temp;
				}
			}
		}
	}
}

class Student1{
	int number;//学号
	int state;//年级
	int score;//成绩
	
	//显示学生信息的方法
	public String info(){
		return "学号:" + number + ",年级:" + state + ",成绩:" + score;
	}
}

4.10.3、练习3(画内存图)

public class TransferTest3{
	public static void main(String args[]){
		TransferTest3 test = new TransferTest3();
		test.first();
	}
	
	public void first(){
		int i = 5;
		Value v = new Value();
		v.i = 25;
		second(v,i);
		System.out.println(v.i);
	}
	
	public void second(Value v,int i){
		i = 0;//这里的i是first()方法中传过来的,在栈空间中i从5变为0
		v.i = 20;
		Value val = new Value();
		v = val;
		System.out.println(v.i+" "+i);
		
	}
}
class Value {
	int i = 15;
} 

4.10.4、练习4(貌似是考察方法的参数传递)

【代码实现】

public static void method(int a,int b){
	a = a * 10;
	b = b * 20;
	System.out.println(a);
	System.out.println(b);
	System.exit(0);//直接退出程序,不让main方法中的Sysout输出
}

4.10.5、练习5

定义一个int型的数组:int[] arr = new int[]{12,3,3,34,56,77,432};
让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值。遍历新的数组。

【代码实现】

//错误写法
for(int i = 0; i < arr.length; i++){
	arr[i] = arr[i] / arr[0];
}

//正确写法1, 倒着写
for(int i = arr.length –1;i >= 0;i--){
	arr[i] = arr[i] / arr[0];
}

//正确写法2
int temp = arr[0];
for(int i = 0;i < arr.length;i++){
	arr[i] = arr[i] / temp;
}

4.10.6、练习6

int[] arr = new int[10];
System.out.println(arr);//地址值?

char[] arr1 = new char[10];
System.out.println(arr1);//地址值?

【代码实现】

public class ArrayPrint {
	
	public static void main(String[] args) {
		int[] arr = new int[]{1,2,3};
        //传进去的是一个Object的对象
		System.out.println(arr);//地址值
		
		char[] arr1 = new char[]{'a','b','c'};
        //传进去的是一个数组,里面遍历数据了
		System.out.println(arr1);//abc
	}
}
/*
PrintStream类中有很多println()重载的方法,使用时就会自动匹配相对应的方法
public void println()
public void println(boolean x) 
public void println(char x) 
public void println(int x)
public void println(long x) 
public void println(float x)
public void println(double x)

public void println(char x[]) 
public void println(String x) 
public void println(Object x) 
*/

4.10.7、练习7(斐波那契数列)

输入一个数据n,计算斐波那契数列(Fibonacci)的第n个值
1  1  2  3  5  8  13  21  34  55
规律:一个数等于前两个数之和
要求:计算斐波那契数列(Fibonacci)的第n个值,并将整个数列打印出来

【代码实现】

public class Recursion {
	public static void main(String[] args) {
		Recursion test = new Recursion();
		int value = test.fibonacci(10);
		System.out.println(value);
	}
	
	public int fibonacci(int n) {
		if (n == 1 || n == 2) {
			return 1;
		} else {
			return f(n - 1) + f(n - 2);
		}
	}
}

物竞天择,适者生存,加油吧 !!!


版权声明:本文为qq_45930444原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>