Java基础编程 第四章 面向对象编程(上)
学习面向对象内容的三条主线
Java类及类的成员
- 属性、方法、构造器;代码块、内部类
面向对象的三大特征
- 封装性、继承性、多态性、(抽象性)
其它关键字
- this、 super、 static、 final、 abstract、interface、package、import
4.1面向过程和面向对象
面向过程(POP:Procedure Oriented Programming)与面向对象(OOP:Object Oriented Programming)
二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
- 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
面向对象的三大特征
- 封闭(Encapsulation)
- 继承(Inheritance)
- 多态(Polymorphism)
- 程序员从面向过程的执行者转化成了面向对象的指挥者
- 面向对象分析方法分析问题的思路和步骤:
- 根据问题需要,选择问题所针对的现实世界中的实体
- 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念暗恋我客户的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
4.2 Java语言的基本元素:类和对象
- 类(Class)和对象(Object)是面向对象的核心概念
- 类是对一类事物的描述,是抽象的、概念上的定义
- 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)
- 例如:人:可以理解为:类=抽象概念的人;对象=实实在在的某个人
- 面向对象程序设计的重点是类的设计
- 类的设计,其实就是类的成员的设计
4.3 对象的创建和使用
一、设计类,其实就是设计类的成员
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数 = method二、类和对象的使用(面向对象思想落地的实现)
创建类,设计类的成员
创建类的对象
通过“对象.属性”或“对象.方法”调用对象的结构三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)意味着, 如果我们修改一个对象的属性a,则不影响另一个对象属性a的值。
四、对象的内存解析
//测试类 public class PersonTest { public static void main(String[] args) { //创建Person类的对象 Person p1 = new Person(); //调用对象的结构:属性、方法 //调用属性: 对象.属性 p1.name = "Jack"; p1.isMale = true; System.out.println(p1.name); //调用方法: 对象.方法 p1.eat(); p1.sleep(); p1.talk("Chinese"); } } //人的这个类 class Person { //属性 String name; int age = 10; boolean isMale; //方法 public void eat() { System.out.println("人可以吃饭"); } public void sleep() { System.out.println("人可以睡觉"); } public void talk(String language) { System.out.println("人可以说话,使用的是:" + language); } }
四、对象的内存解析
/* * 类中属性的使用 * 属性(成员变量) 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(或'\u0000') * 布尔型(booleam):false * 引用数据类型(类、数组、接口):null * * 局部变量:没有默认初始化值 * 意味着,我们在调用局部变量之前,一定要显式赋值 * 特别的:形参在调用时赋值即可 * 2.4在内存中加载的位置: * 属性:加载到堆空间中(非static) * 局部变量:加载到栈空间 * * */ public class UserTest { } class User{ String name; 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() * Scanner类:nextInt() * Arrays类:sort()、binarySearch()、toString()、equals() * 1.举例: * public void eat() {} * public void sleep(int hour) {} * public String getName() { * public String getNation(String nation) {} * 2.方法的声明:权限修饰符 返回值类型 方法名(形参列表){ * 方法体 * } * 注意:static final abstract 来修饰的方法,后面再讲 * 3.说明: * 3.1关于权限修饰符: * java规定的4种权限修饰符:private、public、缺省、protected ---封闭性再细说 * 3.2 返回值类型:有返回值 VS 没有返回值 * 3.2.1 如果 方法有返回值,则必须在方法声明时,指定返回值的类型,同时,方法中,需要使用 * return关键字来返回指定类型的变量或常量:“return 数据;” * 如果方法没有返回值,则方法声明时,使用void来表示。通常没有返回值的方法中,就不需要使用 * return,但是,如果使用的话,只能“return;”表示结束此方法的意思。 * 3.2.2 我们定义方法该不该有返回值? * (1)题目要求 * (2)凭经验:具体问题具体分析 * 3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意” * 3.4 形参列表:方法可以声明0个,1个,或多个形参。 * 3.4.1 格式:数据类型1 形参1,数据类型2 形参2,... * 3.4.2 我们定义方法明,该不该定义形参? * (1)题目要求 * (2)凭经验:具体问题具体分析 * 3.5 方法体:方法功能的体现 * * 4. return 关键字的使用: * 1、使用范围:使用在方法体中 * 2、作用:(1)结束方法 * (2)针对于有返回值类型的方法,使用“return 数据”方法返回所要的数据 * (3)注意点:return关键字后面不可以声明执行语句。 * 5.方法的使用中,可以调用当前类的属性或方法 * 特殊的:方法A中又调用了方法A:递归方法。 * 方法中不可以定义方法。 * * */ public class CustomerTest { public static void main(String[] args) { Customer cust1 = new Customer(); cust1.eat(); //测试形参是否需要设置的问题 // int[] arr = new int[]{6,8,3,4}; // cust1.sort(arr); } } 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; //return后不可以声明表达式 // System.out.println("我叫顺顺"); } public String getNation(String nation) { String info = "我的国籍是:" + nation; return info; } //体会形参是否需要设置 public void sort(int[] arr) { } // //写死了,无法调用 // public void sort1() { // int[] arr = new int[]{10,5,6,7,80} // } }
/* * 要求: * 1、创建Person类的对象,设置该对象的name、age和sex属性,调用study方法, * 输出字符串“studying”,调用showAge()方法显示age值, * 调用addAge()方法给对象的age属性增加2岁。 * 2、创建第二个对,执行上述操作,体会同一个类的不同对象之间的关系 * */ 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); System.out.println("新年龄" + newAge);//20 System.out.println(p1.age);//20 //******************************************* Person p2 = new Person(); p2.showAge();//0 } } public class Person { String name; int age; /* * sex 为 1 时,表示男性 * sex 为 0 时,表示女性 * */ int sex; public void study() { System.out.println("studying"); } public void showAge() { System.out.println("age: " + age); } public int addAge(int i) { age += i; return age; } } /* 练习3 * 2、利用面向对象的编程方法,设计类Circle计算圆的面积。 * */ //测试类 public class CircleTest { public static void main(String[] args) { Circle c1 = new Circle(); c1.radius = 15; //对应方式一: double area = c1.findArea(); System.out.println("圆的面积为:" + area); //对应方式二: c1.findArea1(); } } //圆 class Circle { //属性 double radius; //求圆的面积 //方式一: public double findArea() { double area = Math.PI * radius * radius; return area; } //方式二: public void findArea1() { double area1 = Math.PI * radius * radius; System.out.println("圆的面积为:" + area1); } }
//练习3 public class Exer3Test { public static void main(String[] args) { Exer3Test test = new Exer3Test(); //3 - 1 test.mathod1(); //3 - 2 //方式一 int area = test.method2(); System.out.println("面积为:" + area); //方式二 System.out.println("面积为:" + test.method2()); //3 - 3 int area1 = test.method3(12, 8); System.out.println("面积为:" + area1); } // 3-1 public void mathod1() { for (int i = 0; i < 10; i++) { for (int j = 0; j < 8; j++) { System.out.print("* "); } System.out.println(); } System.out.println("---------------------"); } //3-2 public int method2() { for (int i = 0; i < 10; i++) { for (int j = 0; j < 8; j++) { System.out.print("* "); } System.out.println(); } return 10 * 8; } //3 - 3 public int method3(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; } }
public class StudentTest { public static void main(String[] args) { //声明Student类型的数组 Student[] stus = new Student[20];//String[] arr = new String[]; for (int i = 0; i < stus.length; i++) { stus[i] = new 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 + 1); } //遍历学生数组 for (int i = 0; i < stus.length; i++) { System.out.println(stus[i].Info()); } System.out.println("***************************"); //打印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]; 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; } } //项目优化后&amp;amp;lt;/pre&amp;amp;gt; &amp;amp;lt;pre&amp;amp;gt;public class StudentTest_plus { public static void main(String[] args) { //声明Student类型的数组 Student_plus[] stus = new Student_plus[20]; for (int i = 0; i < stus.length; i++) { stus[i] = new Student_plus(); 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 + 1); } //遍历学生数组 StudentTest_plus test = new StudentTest_plus(); test.forStudent_plus(stus); System.out.println("***************************"); //打印3年级学生的信息 test.searchState(stus,3); System.out.println("***************************"); //使用冒泡排序按学生成绩排序,并遍历所有学生信息 test.sort(stus); test.forStudent_plus(stus);//遍历学生数组 } //遍历学生数组 public void forStudent_plus(Student_plus[] stus){ for (int i = 0; i < stus.length; i++) { System.out.println(stus[i].Info()); } } //打印指定年级学生的信息 public void searchState(Student_plus[] stus,int state){ for (int i = 0; i < stus.length; i++) { if (stus[i].state == state) { System.out.println(stus[i].Info()); } } } public void sort(Student_plus[] 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对象!!! Student_plus temp = stus[j]; stus[j] = stus[j + 1]; stus[j + 1] = temp; } } } } } class Student_plus { int number;//学号 int state;//年级 int score;//成绩 public String Info() { return "学号:" + number + " 年级:" + state + " 成绩:" + score; } }
4-5 类的成员之二:方法(method)
public class ArrayUtilTest { public static void main(String[] args) { ArrayUtil util = new ArrayUtil(); int[] arr = new int[]{-6,55,68,32,0,12,-99,-54,40,78}; System.out.println("数组是:" ); util.print(arr); //数组的最大值 int max = util.getMax(arr); System.out.println("数组的最大值为:" + max); //数组的最小值 int min = util.minValue(arr); System.out.println("数组的最小值为:" + min); //数组的总和 int sum = util.arrSum(arr); System.out.println("数组的总和为:" + sum); //数组的平均值 System.out.println("数组的平均值为:" + util.arrAvg(arr)); //反转数组 util.reverse(arr); util.print(arr); //复制数组 int[] copy = util.copy(arr); util.print(copy); //数组排序 System.out.println("排序前"); util.print(arr); util.sort(arr); //遍历数组 System.out.println("排序前"); util.print(arr); //查找 int index = util.getIndex(arr,-6); if (index >= 0) { System.out.println("找到了,Index为:" + index); }else { System.out.println("没找到"); } } } public class ArrayUtil { //求数组的最大值 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 minValue(int[] arr) { int minvalue = arr[0]; for (int i = 0; i &amp;amp;lt; arr.length; i++) { if (minvalue &amp;amp;gt; arr[i]) { minvalue = arr[i]; } } return minvalue; } //求数组的总和 public int arrSum(int[] arr) { int sum = arr[0]; for (int i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; } //求数组的平均值 public int arrAvg(int[] arr) { return arrSum(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 int[] copy(int[] arr) { int[] arr1 = new int[arr.length]; for (int i = 0; i < arr.length; i++) { arr1[i] = arr[i]; } return arr1; } //数组排序,冒泡排序 public void sort(int[] arr) { for (int i = 0; i < arr.length; i++) { for (int j = 0; j < arr.length - 1 - i; j++) { int temp = arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } //遍历数组 public void print(int[] arr) { System.out.print("["); 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;//返回一个负数 ,表示没有找到 } }
4-6 再谈方法
4.6.1 方法的重载
- 重载的概念:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
- 重载的特点:与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个娄或参数类型)。调用时,根据方法参数列表的不同来区别。
- 重载示例:
- //返回两个整数的和
- int add(int x,int y){return x+y;}
- //返回三个整数的和
- int add(int x,int y,int z){return x+y+z;}
- //返回两个小数的和
- double add(double x double y){return x+y;}
4.6.2 可变形参的方法
4.6.3 方法参数的值传递机制
4.6.4 递归方法
/* * 方法重载(overload)loading...... * 1、定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。 * "两同一不同":同一个类、相同方法名 * 参数列表不同:参数个数不同,参数类型不同 * 2、举例: * Arrays类中重载的sort() / binarySearch() * 3、判断是否是重载: * 跟方法的权限修饰、返回值类型、形参变量名、方法体都没有关系! * 4、在通过对象调用方法时,如何确定某一个指定的方法: * 1)方法名-----&amp;amp;gt;参数列表 * */ public class OverLoadTest { public static void main(String[] args) { OverLoadTest test = new OverLoadTest(); test.getSum(4,6); } //以下4个方法构成重载 public void getSum(int i, int j) { System.out.println(i + j); } public void getSum(double d1, double d2) { } public void getSum(int i, String s) { } public void getSum(String s, int i) { } //以下方法不构成重载,方法名相同,参数列表相同 // public void getSum(int m, int n) { // return o; // } }
练习 4
1、判断:
与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
2、编写程序,定义三个重载方法并调用。方法名为mOL。
- 三个方法分别接收一个int参数、两个int参数、一个字符串参数。分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。
- 在主类的main()方法中分别用参数区别调用三个方法。
3、定义三个重载方法max(),第一个方法求两个int值中的最大值,第二个方法求两个double值中的最大值,第三个方法求三个double值中的最大值,并分别调用三个方法。
public class OverLoadTest1 { public static void main(String[] args) { OverLoadTest1_1 test = new OverLoadTest1_1(); int pingfang = test.mOL(10); System.out.println(pingfang); int chengji = test.mOL(5, 5); System.out.println(chengji); test.mOL("Hello OverLoad"); test.max(100,100); test.maxValue(1,1); test.max(25.3,-55.1); test.max(-60,-60,-60); test.maxValue(1,1,1); } } public class OverLoadTest1_1 { public int mOL(int a) { a = a * a; return a; } public int mOL(int b, int c) { int resutl = b * c; return resutl; } public void mOL(String cha) { System.out.println(cha); } //返回最大值,方法一 public void max(int x, int y) { if (x > y) { System.out.println("最大值为:" + x); } else if (x < y) { System.out.println("最大值为:" + y); } else { System.out.println("两个值一样大!"); } } //返回两个数的最大值,方法二 public int maxValue(int x, int y) { return (x > y) ? x : y; } public void max(double db1, double db2) { if (db1 > db2) { System.out.println("最大值为:" + db1); } else if (db1 < db2) { System.out.println("最大值为:" + db2); } else { System.out.println("两个值一样大!"); } } //返回三个数的最大值,方法一 public void max(double db1, double db2, double db3) { if (db1 >= db2) { if (db1 >= db3) { System.out.println("最大值为:" + db1); } else if (db3 <= db1) { System.out.println("最大值为:" + db3); } } else if (db2 >= db1) { if (db2 >= db3) { System.out.println("最大值为:" + db2); } else if (db3 >= db2) { System.out.println("最大值为:" + db3); } } } //返回三个数的最大值,方法二 public double maxValue(double db1, double db2, double db3) { double max = (db1 > db2)?db1:db2; return (max > db3)?max:db3; } }
4.6 再谈方法2:可变个数的形参
JavaSE 5.0 中提供了Varargs(varibale number of arguments)机制,允许直接定义能和多个实例相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。
//JDK 5.0 以前:采用数组形参来定义方法,传入多个同一类型变量
public static void test(int a,String[] books);
//JDK 5.0:采用可变个数形参来定义方法,传入多个同一类型变量
public static void test(int a,String…books);
/* * 可变个数形参的方法 * 1、JDK 5.0 新增的方法 * 2、具体使用: * 2.1 可变个数形参的格式:数据类型 ... 变量名 * 2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个....或多个 * 2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载 * 2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。二者不能共存 * 2.5 可变个数形参在方法的形参中,必须声明在末尾 * 2.6 可变个数形参在予以否认形参中,最多只能声明一个可变形参 * */ public class MethodArgsTest { public static void main(String[] args) { MethodArgsTest test = new MethodArgsTest(); test.show(1); test.show("hello"); test.show("a","b","c"); test.show(); } //方法重载 public void show(int i) { } public void show(String s) { System.out.println(s); } //可变个数形参 public void show(String... strs) { for (int i = 0; i > strs.length; i++) { System.out.print(strs[i]); } } //可变个数形参在方法的形参中,必须声明在末尾 // public void shows(String... strs1,int i) { // // } public void shows(int i,String... strs1) { } }
说明:
- 声明stake:方法名(参数的类型名 … 参数名)
- 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个,或多个
- 可变个数形参的方法与同名的方法之间,彼此构成重载
- 可变参数方法的使用与方法参数部分使用数组是一致的
- 方法的参数部分有可变形参,需要放在形参声明的最后
- 在一个方法的形参位置,最多只能声明一个可变个数形参
4.6 再谈方法3:方法参数的值传递机制
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
形参:方法声明时的参数
实参:方法调用时实际传给形参的参数值
Java的实参值如何传入方法呢?
Java里方法的参数传递方式只有一种:值传递。即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
形参是基本数据类型:将实参基本数据类型变量的”数据值“传递给形参。
形参是引用数据类型:将实参引用数据类型变量的”地址值“传递给形参。
/* * 关于变量赋值 * 如果变量是基本数据类型,此时赋值的是变量所保存的数值。 * 如果变量是引用数据类型,此时赋值的是变量保存的数据的地址值。 * */ public class ValueTransferTest { public static void main(String[] args) { System.out.println("-----------基本数据类型-----------"); int m = 10; int n = m; System.out.println("m = " + m + ", n = " + n); n = 20; System.out.println("m = " + m + ", n = " + n); System.out.println("-----------引用数据类型-----------"); OrdeId o1 = new OrdeId(); o1.ordeid = 1001; OrdeId o2 = o1;//赋值以后,o1和o2的地址值相同,都指向堆空间中的同一个对象实体。 System.out.println("o1.ordeid = "+ o1.ordeid + ", o2.ordeid = " + o2.ordeid); o2.ordeid = 1002; System.out.println("o1.ordeid = "+ o1.ordeid + ", o2.ordeid = " + o2.ordeid); } static class OrdeId{ int ordeid; } } /* -----------基本数据类型----------- m = 10, n = 10 m = 10, n = 20 -----------引用数据类型----------- o1.ordeid = 1001, o2.ordeid = 1001 o1.ordeid = 1002, o2.ordeid = 1002 * */
/* * 微软: * 定义一个int型的数组:int[]{12,3,34,56,77,432} * 让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值遍历数组 * */ public class ArrayTest { public static void main(String[] args) { int[] arr = new int[]{12,3,3,34,56,77,432}; //方法一(推荐): for (int i = arr.length-1; i >=0; i--) { arr[i]=arr[i]/arr[0]; } for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + "\t"); } System.out.println(); //方法二: int temp = arr[0]; for (int i = 0; i < arr.length; i++) { arr[i]=arr[i]/temp; } for (int i = 0; i &lt; arr.length; i++) { System.out.print(arr[i] + "\t"); } } }
/* * public class Test { * public static void main(String[] args) { int a = 10; int b = 10; method(a,b);//需要在method方法被调用之后,仅打印出a=100,b=200,请写出method方法的代码 System.out.println("a="+a); System.out.println("b="+b); } } * */ import java.io.PrintStream; public class ValueTest { public static void main(String[] args) { int a = 10; int b = 10; // method(a,b);//需要在method方法被调用之后,仅打印出a=100,b=200,请写出method方法的代码 //方法一: a = a * 10; b = b * 20; System.out.println("a="+a); System.out.println("b="+b); System.exit(0); System.out.println("a="+a); System.out.println("b="+b); } //方法二: // public static void method(int a, int b) { // PrintStream ps = new PrintStream(System.out); // @Override // public void println(String x){ // if ("a=10".equals(x)) { // x = "a=100"; // } else if ("b=10".equals(x)) { // x= "b=200"; // } // super.println(x); // } // System.out.println("a="+a); // System.out.println("b="+b); // } }
/* 定义一个Circle类,包含一个double型的radius属性代表圆的半径 */ public class Circle { double radius; //求圆的面积 public double findArea(){ return Math.PI * radius*radius; } } /* 考查参数的值传递 *定义一个类PassObject,在类中定义一个方法printAreas(), * 该方法的定义如下:public void printAreas(Circle c, int time) * 在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。 * 例如:time为5,则输出半径1,2,3,4,5,以及对应的圆面积。 *在main方法中调用printAreas()方法,调用完毕后输出当前半径值。程序远行如果如图所示。 * */ public class PassObject { public static void main(String[] args) { PassObject p = new PassObject(); Circle c = new Circle(); p.printAreas(c,8); System.out.println("now radius is :" + c.radius); } public void printAreas(Circle c, int time) { System.out.println("radius" + "\t\t" + "Area"); //设置圆的半径 for (int i = 1; i <= time; i++) { c.radius =i; System.out.println(c.radius + "\t\t" + c.findArea()); } c.radius = time + 1; } }
4.6 再谈方法4: 递归(recursion)方法
- 递归方法:一个方法体内调用它自身。
- 方法递归包含了一种隐式的循环。它会重复执行某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似死循环。
/* *例1:计算1-100之间所有自然数的和 * */ public class RecursionTest { public static void main(String[] args) { //例1: //方式一: int sum = 0; for (int i = 0; i <= 100; i++) { sum += i; } System.out.println("1-100自然数的和为:" + sum); //方式二: RecursionTest recSum = new RecursionTest(); int sum1 = recSum.getSum(100); System.out.println("1-100自然数的和为:" + sum1); //例2:计算1-100之间所有自然数的积,n! 递归方法 System.out.println("自然数的积n!为:" + recSum.getSum1(10)); //例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2) = 2*f(n+1) + f(n) int f = recSum.f(10); System.out.println("f(n) = " + f); //例4:已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1) + f(n), // 其中,n是大于0的整数,求f(10)的值。 int f1 = (recSum.f1(10)); System.out.println("f(m) = " + f1); //例5:输入一个数据n,计算斐波那契数列(Fibonacci)的第n个值 int n = 45; int fibon = recSum.Fibonacci(n); System.out.println(fibon); //将数列放入数组中 int[] fibonArray = new int[n]; for (int i = 0; i < n; i++) { fibonArray[i] = recSum.Fibonacci(i + 1); } //排序并输出 System.out.println(n + "位的斐波那契数列为:" + Arrays.toString(fibonArray)); } //例1:计算1-100之间所有自然数的和递归方法 public int getSum(int n) { if (n == 1) { return 1; } else { return n + getSum(n - 1); } } //例2:计算1-100之间所有自然数的积,n! 递归方法 public long getSum1(long 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); } } //例4:已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1) + f(n), //其中,n是大于0的整数,求f(10)的值。 public int f1(int m) { if (m == 20) { return 1; } else if (m == 21) { return 4; } else if (m < 20) { return f1(m + 2) - 2 * f1(m + 1); } else { return 2 * f1(m - 1) + f1(m - 2); } } //例5:输入一个数据n,计算斐波那契数列(Fibonacci)的第n个值 // 1 1 2 3 5 8 13 21 34 55 //规律:一个数等于前两个数之和 //要求:计算斐波那契数列(Fibonacci)的第n个值,并将整个数列打印出来 public int Fibonacci(int n) { if (n == 1 || n == 0) { return n; } else { return Fibonacci(n - 1) + Fibonacci(n - 2); } } }
/* 例6:汉诺塔问题 */ public class HaniotaTest { public static void main(String[] args) { int n = 4;//需要移到的盘子 char a = 'A', b = 'B', c = 'C';//盘子移动需要的柱子,起始A,借助B,目标C hanio(n, a, b, c); } public static void hanio(int n, char a, char b, char c) { //只有一个盘子,直接从A移动到目标C柱子 if (n == 1) { move(n, a, c); } else { //1.把 n-1 个盘子看成一个整体,借助 C 从 A 移动到 B hanio(n - 1, a, c, b); //2.把第 n 个盘子从 A 移动到 C move(n, a, c); //3.再把 n-1 盘子整体,借助 A 从 B 移动到 C hanio(n - 1, b, a, c); } } public static void move(int n, char a, char b) { System.out.println("把第" + n + "个盘子从" + a + "移到" + b); } }