1. “万事万物皆对象”

  2. 对象数组的内存解析

  3. 匿名对象

  4. 自定义数组的工具类

  5. 方法重载

  6. 可变个数形参的方法

  7. 理解变量的赋值

  8. 值传递机制

  9. 递归方法的使用和举例

 

1,理解“万事万物皆对象”

 

    在Java语言的范畴中,将某个事物的功能、结构封装到类中,通过类的实例化来调用具体的功能结构。比如将字符串描述为String类、将输入流描述为Scanner类;将文件描述为File类;将网络资源描述为URL类
    超出Java本身的范畴时,比如涉及到与前端HTML、后端的数据库交互时,前后端中的结构在Java层面都体现为类和对象。比如HTML中的一种标签,在Java中就是对应一个类;在数据库中的一张表的结构对应Java中的一个类,表中具体的数据行对应Java中由这个类创建的对象
 

2,对象数组的内存解析

    说出这段代码在内存中的执行情况,描述尽量准确详细
day09-面向对象(上)_面向对象章节
 

3,匿名对象

package com.atguigu.java;

public class InstanceTest {
	public static void main(String[] args) {
		Phone p = new Phone();
		System.out.println(p);
		p.sendEmail();
		p.playGame();
		// 匿名对象,没有将创建的对象赋值给一个变量名
		new Phone().sendEmail(); // 两个对象
		new Phone().playGame(); // 匿名对象只能调用一次,因为没有赋值给一个引用类型的变量,所以不知道该变量的地址值
		// 匿名对象的使用
		PhoneMall mall = new PhoneMall();
		mall.show(new Phone());
	}
}

class Phone {
	double price;
	
	public void sendEmail() {
		System.out.println("发送电子邮件");
	}
	public void playGame() {
		System.out.println("玩游戏");
	}
}

class PhoneMall {
	public void show(Phone phone) {
		phone.sendEmail(); // 将一个匿名对象赋值给了show()方法的形参,就是赋值给了一个引用类型的局部变量,所以可以多次调用这个匿名对象
		phone.playGame();
	}
}

 

4,自定义数组的工具类

 

package com.atguigu.java;

/*
 * 自定义数组的工具类
 * 
 */
public 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) {

		return getSum(arr) / arr.length;
	}

	//如下的两个同名方法构成了重载
	// 反转数组
	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 void reverse(String[] arr){
		
	}

	// 复制数组
	public int[] copy(int[] arr) {
		int[] arr1 = new int[arr.length];
		for (int i = 0; i < arr1.length; i++) {
			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],arr[j + 1]);
					//正确的:
					swap(arr,j,j + 1);
				}

			}

		}
	}
	
	//错误的:交换数组中指定两个位置元素的值
//	public void swap(int i,int j){
//		int temp = i;
//		i = j;
//		j = temp;
//	}
	//正确的:交换数组中指定两个位置元素的值
	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] + "\t");
		}
		System.out.println();
	}

	// 查找指定元素
	public int getIndex(int[] arr, int dest) {
		// 线性查找:

		for (int i = 0; i < arr.length; i++) {

			if (dest == arr[i]) {
				return i;
			}

		}

		return -1;//返回一个负数,表示没有找到
	}

}

 

5,方法重载

    在同一个类中,允许存在两个以及上同名的方法,但它们的参数个数或类型要不同,这些方法之间就是重载的关系。方法重载是先有这样确切的需求,再有这样的定义
    对于不同的操作对象,要实现相同功能的方法,往往需要定义相同的方法名以起到见名知意的效果。比如对一个数组进行排序的方法,这个数组既可是int类型,也可是double类型,这是就需要两个同名的方法sort()分别对这两类数组进行排序。这两个方法的区别就是参数
    在通过对象调用方法时,可能有多个同名的方法,方法名+参数列表就能指定一个明确的方法

 

package com.atguigu.java1;

public class OverLoadTest {
	// 以下方法满足重载的定义
	public void getSum(int i, int j) { // 当调用getSum(1,2)时这个方法被调用
		
	}
	public void getSum(double d1, double d2) { // 当上一个方法被注释后,调用getSum(1,2)时这个方法被调用,double接收了int类型的值
		
	}
	public void getSum(String s, int i) {
		
	}
	public void getSum(int i, String s) { // 不同类型参数的位置不同也能判断出是两个不同的方法
		
	}
	// 重载跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系
	// 错误的重载
//	public int getSum(int i, int j) {
//		
//	}
//	public void getSum(int m, int n) {
//		
//	}
//	private void getSum(int i, int j) {
//		
//	}
//	public void getSum(int i, int j) {
//		System.out.println(i + j);
//	}
}
    println()也是一个重载方法,在PrintStream.class中对每个传入的不同类型的参数都定义了一个println()方法

 

day09-面向对象(上)_面向对象章节_02

 

6,可变个数的形参

 

    在JDK 5.0加入的新特性。可以定义能与0个、一个或多个实参相匹配的形参,从而能够传递个数可变的实参

 

package com.atguigu.java1;

public class MethodArgsTest {
	public static void main(String[] args) {
		MethodArgsTest test = new MethodArgsTest();
		test.show(12);
		test.show("hello"); // Ctrl+左键点show方法,可以看到被执行的是第二个show方法,因为传入的只有一个参数,所以优先考虑最契合的方法
		test.show("hello","world"); // 两个参数,调用第三个show方法
		test.show(); // 没有参数,调用第三个show方法
//		test.show(new String[]{"hello","world"}); // 传入的是一个String类型数组对象
	}
	
	// 以下方法构成重载
	public void show(int i) {
		
	}
	
	public void show(String s) {
		System.out.println("show(String)");
	}
	
	public void show(String ... strs) { // 可以将strs看作是一个String类型数组变量,只是下面的show方法的简化写法,所以在这里甚至传入一个数组对象new String[]{"hello","world"}也是对的
		System.out.println("show(String ... strs");
		for(int i = 0 ; i < strs.length ; i++) {
			System.out.println(strs[i]);
		}
	}
	
//	public void show(String[] strs) { // 再定义这个方法会报错,编译器认为它和上面的可变个数的形参的方法相同
//									// 这是因为在JDK 5.0之前,要传入不固定个数的参数的方式就是传入数组
//	}
	
//	public void show(String ... strs, int i) { // 这样写会有歧义,当传入两个参数时,编译器不知道是该将两个都给strs还是一个给strs一个给i
//											// 可变个数的形参只能放在最后,所以也最多只能定义一个可变个数形参,因为当定义多个时,总有一个在另一个的前面
//	}
}

 

7,理解变量的赋值

    对于变量的赋值操作,如果变量是基本数据类型,赋值是将一个变量保存的值赋给了另一个变量,相当于在内存中有了两个值相同的变量;如果变量是引用数据类型,赋值是将变量保存的对象的地址值赋给了另一个引用类型变量,在内存中只要一个对象,但有两个变量存储了它的地址值

 

 

8,值传递机制

    形参:声明在方法的()中的变量;实参:调用方法时要给方法传递的值
    Java中给方法的形参传值时遵循值传递机制,在调用一个方法给它传值时,实际就相当于变量的赋值操作
    对于基本数据类型的传参。想要交换两个int类型变量的值
package com.atguigu.java1;

public class ValueTransferTest {
	public static void main(String[] args) {
		int m = 10;
		int n = 20;
		ValueTransferTest test = new ValueTransferTest();
		test.swap(m, n); // 把main方法中的局部变量m和n的值传给了swap方法中的局部变量的m和n,相当于有了两份m和n
		System.out.println("m=" + m +" " + "n=" + n); // swap方法中的m和n交换后就消失了,并没有对main方法中的m和n做过交换操作
	}												// m=10 n=20
	
	public void swap(int m, int n) {
		int temp = m;
		m = n;
		n = temp; // 交换的是swap方法中的m和n,当方法结束,局部变量也消失了
	}
}

    

    对于引用数据类型的传参。若要交换m和n的值
package com.atguigu.java1;

public class ValueTransferTest1 {
	public static void main(String[] args) {
		Data data = new Data();
		data.m = 10;
		data.n = 20;
		ValueTransferTest1 test = new ValueTransferTest1();
		test.swap(data); // Data类型的对象只有一个,将它的引用传给了swap方法
		System.out.println("m=" + data.m + " " + "n=" + data.n); // m=20 n=10
	}
	
	public void swap(Data data) { // 复制了一份对象的地址值给swap方法的局部变量data
		int temp = data.m;
		data.m = data.n;
		data.n = temp; // 变量data操作的还是原来的那个对象
	}
}

class Data {
	int m;
	int n;
}

    说出上面两个程序在内存中的执行情况

 

day09-面向对象(上)_面向对象章节_03

day09-面向对象(上)_面向对象章节_04

    练习

day09-面向对象(上)_面向对象章节_05

    说出上述程序在内存中的执行的完整情况,从局部变量入栈到出栈、对象的创建和销毁

 

day09-面向对象(上)_面向对象章节_06

    网红题

day09-面向对象(上)_面向对象章节_07

    a和b是基本数据类型,这题中想要在方法中改变a和b的值是不可能的
    System.exit(0);会直接终止程序,也就不会执行后面的打印语句

 

day09-面向对象(上)_面向对象章节_08

    重置下打印流

 

day09-面向对象(上)_面向对象章节_09

    按照错误写法,第一次循环时就将数组的首位元素置为1了

 

 day09-面向对象(上)_面向对象章节_10
    乍一看第二个打印语句应该也是输出一个数组对象的地址值
day09-面向对象(上)_面向对象章节_11
    之前说方法重载时,println()也是一个重载方法,可以看到当传入的是一个int类型的数组时调用的是println(Object),当传入char类型数组时调用的是println(char[]),这两个方法的方法体是不同的,前者会输出对象的地址值,后者输出char类型数组的所有元素
day09-面向对象(上)_面向对象章节_12
day09-面向对象(上)_面向对象章节_13
package com.atguigu.java1;

public class PassObject {
	
	public static void main(String[] args) {
		PassObject test = new PassObject();
		Circle c = new Circle();
		test.printAreas(c, 5);
		System.out.println("now radius is " + c.radius);
	}
	
	public void printAreas(Circle c, int time) {
		System.out.println("Radius\t\tArea");
		for(int i = 1 ; i <= time ; i++) {
			c.radius = i;
			System.out.println(c.radius + "\t\t" + c.findArea());
		}
		c.radius = time + 1;
	}
}

class Circle {
	double radius;
	
	public double findArea() {
		return Math.PI * radius * radius;
	}
}
 

9,递归方法的使用和举例

    一个方法的方法体中调用了它自己,这是一种隐式的循环,如果没有终结条件,它会一直调用下去
    计算1-100之间所有整数的和
package com.atguigu.java1;

public class RecursionTest {
	
	public static void main(String[] args) {
		RecursionTest test = new RecursionTest();
		System.out.println(test.getSum(100));
	}
	
	public int getSum(int n) {
		if(n == 1) {
			return 1;
		}else {
			return n + getSum(n - 1);
		}
	}
	
}
    已知一个数列,f(0) = 1, f(1) = 4, f(n+2) = 2f(n+1) + f(n),其中n是大于0的整数,求f(10)
package com.atguigu.java1;

public class RecursionTest {
	
	public static void main(String[] args) {
		RecursionTest test = new RecursionTest();
		System.out.println(test.f(10));
	}
	
	public int f(int n) {
		if(n == 0) {
			return 1;
		}else if(n == 1) {
			return 4;
		}else {
//			return f(n + 2) - 2 * f(n + 1); // 错误写法,递归不会到达终止条件
			return 2 * f(n - 1) + f(n - 2);
		}
	}
	
}