Java基础学习笔记:第四章(二)面向对象编程

    技术2024-07-24  11

    知识点1:递归方法

    递归方法的使用 * * 1. 递归方法:一个方法体内调用它自身。 * 2. 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。 * 3. 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。 * 死循环是我们开发中要避免出现的。进而递归方法也必须满足执行的有限性。否则的话,会报StackOverflowError 代码演示 public class RecursionTest { public static void main(String[] args) { RecursionTest test = new RecursionTest(); int sum = test.sum1(100); System.out.println("总和为:" + sum); int result = test.f(10); System.out.println("结果为:" + result); } //计算1-num所有自然数的和 public int sum(int num){ int sum = 0; for (int i = 1; i <= num; i++) { sum += i; } return sum; } //递归实现:1-100所有自然数的和 public int sum1(int num){ if(num == 1){ return 1; }else{ return sum1(num - 1) + num; } } //递归实现1:计算n! public int multiply(int num){ if(num == 1){ return 1; }else{ return multiply(num - 1) * num; } } //递归实现2:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n), // 其中n是大于0的整数,求f(10)的值。 public int f(int num){ if(num == 0){ return 1; }else if(num == 1){ return 4; }else{ //错误的 // return f(num + 2) - 2 * f(num + 1); //正确的 return 2 * f(num - 1) + f(num - 2); } } //递归实现3:已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n), //其中n是大于0的整数,求f(10)的值。 public int func(int num){ if(num == 20){ return 1; }else if(num == 21){ return 4; }else{ return func(num + 2) - 2 * func(num + 1); } } //递归实现4:斐波那契数列: 1 1 2 3 5 8 13 21 34 55 //f(1) = 1;f(2) = 1;f(n + 2) = f(n + 1) + f(n) //递归实现5:汉诺塔 //递归实现6:IO流时File类的使用:遍历指定文件目录下的所有文件名 public void printFileName(File file){ if(file.isDirectory()){ File[] files = file.listFiles(); for(int i = 0;i < files.length;i++){ printFileName(files[i]); } }else{ System.out.println(file.getAbsolutePath()); } } //递归实现7:快排 }

    知识点2:面向对象的特征一:封装与隐藏

    1. 封装性的体现之一:

    1. 问题的引入 * 我们在创建一个类的对象之后,可以通过“对象.属性”的方式给属性赋值。默认情况下,赋的值需要满足指定的 * 数据类型和变量的存储值的范围。但是,在实际情况中,此属性的赋值,需要满足实际情况的一些限制条件。(比如: * legs必须是正数、且是偶数)。又由于我们不能直接在属性的声明位置加上此限制语句,则必须通过方法的 * 方法的方式给属性赋值,在方法内设置限制条件。则我们设计一个SetXxx()的方法。将此方法暴露出去(设置为public) * 同时,不允许在类的外部再直接修改此属性。则将此属性隐藏起来(设置为private)即可。 * * 1.1 为了出了类之后,能调用此属性的值,我们还需要提供一个getXxx()的方法。此方法声明为public的即可。 * * 2. 小结:设计类时,可以考虑把类中的属性私有化(private),同时提供公共(public)的get和set方法,进行获取和设置此属性的操作。 代码演示 public class AnimalTest { public static void main(String[] args) { Animal ani = new Animal(); ani.name = "佩奇"; // ani.age = 1; // ani.legs = -4; ani.setLegs(14); // ani.legs = -14;//非法访问 ani.info(); // System.out.println(ani.legs); System.out.println(ani.getLegs()); } } class Animal { String name; private int age; private int legs;//腿的个数 //获取属性值的方法 public int getLegs(){ return legs; } //设置属性值的方法 //设计一个方法,通过方法给legs属性赋值 public void setLegs(int l){ if(l >= 0 && l % 2 == 0 && l <= 30){ legs = l; }else{ System.out.println("传入的数据非法!"); } } //提供age属性的get和set方法 public int getAge(){ return age; } public void setAge(int a){ age = a; } public void info() { System.out.println("name = " + name + ", age = " + age + ",legs = " + legs); } }

    2. 封装性的体现之二:

    在类中声明方法时,可以将此方法声明为private。表明此方法只能在类内部使用。 代码演示 public void sort(Student[] stus,String sortMethod){ if("ascend".equals(sortMethod)){ 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){ swap(stus,j,j + 1); } } } }else if("descend".equals(sortMethod)){ 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){ swap(stus,j,j + 1); } } } }else{ System.out.println("排序方式有误!"); } } private void swap(Student[] stus,int i,int j){ Student temp = stus[i]; stus[i] = stus[j]; stus[j] = temp; }

    3. 4种权限修饰符

    3. 封装与隐藏,体现了设计java类及java类的内部结构时,其可被访问的权限的大小。 * java规定的4种访问权限修饰符:(从小到大的顺序) * private < 缺省 < protected < public 4. 我们可以使用4种权限修饰符修饰类及类的内部结构 * > 可以使用4种权限修饰符修饰:属性、方法、构造器、内部类 * > 可以使用缺省或public修饰符修饰:类。 (不能使用private\protected修饰类)

    知识点3:类的成员之三:构造器

    类的成员之三:构造器的使用 * * 1. Constructor = 构造器 = 构造方法 = 构造函数 * construct : 构建、构造 * * 2.构造器的作用: * ① 创建类的对象 (或 类的实例化) * ② 可以初始化对象的信息(比如:属性的初始化) * * 3. 说明: * ① 任何一个类,如果没有显式提供构造器的话,系统都会默认提供一个空参的构造器 * ② 自定义构造器的格式: 权限修饰符 类名(形参列表){ } * ③ 类中可以声明多个构造器,彼此构成重载 * ④ 一旦显式的定义了类的构造器,则系统不再提供默认的空参的构造器。 代码演示 public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); p1.name = "吴辉"; p1.age = 25; p1.eat(); p1.sleep(6); System.out.println("####################"); Person p2 = new Person("石磊"); System.out.println(p2.name);//石磊 } } class Person{ //属性 String name; int age; //构造器 public Person(){ System.out.println("hello,Person()"); } public Person(String n){ name = n; } public Person(int a){ if(a >= 0 && a <= 130){ age = a; } } //方法 public void eat(){ System.out.println("人每天需要吃饭"); } public void sleep(int hour){ System.out.println("人每天需要保证" + hour + "小时的睡眠"); } }

    知识点4:类中属性赋值的位置及先后顺序

    /** * 小结:类中属性赋值的位置及执行先后顺序测试 * * 1. 类中的属性都可以在哪些位置赋值? * ① 默认初始化 * ② 显式初始化 * ③ 构造器中初始化 * * ④ 在创建了对象之后,使用"对象.方法" 或 "对象.属性"的方式赋值 * * * 2. 赋值的先后顺序: * ① - ② - ③ - ④ * * 3. 上述的 ①、②、③过程,在对象实例化过程中,只能执行一次! * * @author shkstart * @create 2020-07-03 14:40 */ public class UserTest { public static void main(String[] args) { User u1 = new User(); System.out.println(u1.name); User u2 = new User(10); System.out.println(u2.age); } } class User{ String name = "Tom"; int age = 1; public User(){} public User(int a){ age = a; } }

    知识点5:this关键字的使用

    1. this可以调用属性、方法、构造器

    1. this调用属性、方法

    2. this调用属性、方法: * this可以理解为:当前对象 或 当前正在创建的对象 * * 2.1 在类的方法内或构造器内执行操作时,如果方法的形参或构造器的形参与类的属性名相同,则 * 必须显式的通过"this."的方式,表明调用的当前类的属性。如果省略了"this.",则认为调用的是形参。 * 2.2 在类的方法内或构造器内执行操作时,如果方法的形参或构造器的形参与类的属性名不相同时, * 则调用类的属性时,前面修饰的"this."可以省略。 * * 2.3 在类的方法中,我们可以通过"this."的方式调用本类中的其他方法。只是大多数情况下,我们都 * 省略了"this."。 代码演示 class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return name; } public int getAge(){ return age; } public void eat(){ System.out.println("人:吃饭"); this.sleep(); } public void sleep(){ System.out.println("人:睡觉"); } }

    2. this调用构造器

    3. this调用构造器: * ① this调用构造器的格式:this(形参列表) * ② 在类的构造器中,我们可以显示的使用"this(形参列表)"的方式,调用本类中的其他构造器。 * ③ “this(形参列表)”必须声明在类的构造器的首行! * ④ 在类的一个构造器中,只能最多声明一个“this(形参列表)” * ⑤ 如果一个类中声明了n个构造器,则最多有n - 1 个构造器中使用了“this(形参列表)” 代码演示 class Person{ private String name; private int age; public Person(){ // this("吴瀚"); System.out.println("我是一个人。我刚出生,需要洗澡!"); } public Person(String name){ this(); this.name = name; } public Person(String name,int age){ this(name); this.age = age; // this.eat(); } }

    知识点6:其他

    1. javaBean

    /** * 满足如下条件的类,可以称为是一个javabean: * >类是公共的 * >有一个无参的公共的构造器 * >有属性,且有对应的get、set方法 * * @author shkstart * @create 2020-07-03 15:12 */ public class Student { private int number;//学号 private int state;//年级 private int score;//成绩 public int getNumber() { return number; } public void setNumber(int n) { number = n; } public int getState() { return state; } public void setState(int s) { state = s; } public int getScore() { return score; } public void setScore(int s) { score = s; } }

    2.UML类图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-73W9e7xL-1593780974694)(assets/1593766536723.png)]

    练习

    数据类:Student类 //数据 class Student{ int number;//学号 int state;//年级 int score;//成绩 public void info(){ System.out.println("number : " + number + ", state : " + state + ", score : " + score); } } 操作数据的工具类:StudentUtil //操作数据的工具类 class StudentUtil{ /** * 根据指定的条件,创建相应的学生数组,并给数组元素赋值 * @param length 指定学生数组的长度 * @param lowState 指定学生对象的年级的下边界 * @param highState 指定学生对象的年级的上边界 * @param lowScore 指定学生对象的成绩的下边界 * @param highScore 指定学生对象的成绩的上边界 * @return 返回满足指定条件的数组 */ public Student[] getStudentArray(int length,int lowState,int highState,int lowScore,int highScore){ Student[] stus = new Student[length];//虚位以待 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() * (highState - lowState + 1) + lowState); //成绩:0-100 stus[i].score = (int)(Math.random() * (highScore - lowScore + 1) + lowScore); } return stus; } /** * 遍历学生数组,打印出指定年级学生的信息 * @param stus 待遍历的数组 * @param state 指定的学生年级 */ public void printStudentState(Student[] stus,int state){ for (int i = 0; i < stus.length; i++) { if (stus[i].state == state) { stus[i].info(); } } } /** * 排序Student数组:使用冒泡排序 * @param stus * @param sortMethod */ public void sort(Student[] stus,String sortMethod){ if("ascend".equals(sortMethod)){ 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){ swap(stus,j,j + 1); } } } }else if("descend".equals(sortMethod)){ 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){ swap(stus,j,j + 1); } } } }else{ System.out.println("排序方式有误!"); } } private void swap(Student[] stus,int i,int j){ Student temp = stus[i]; stus[i] = stus[j]; stus[j] = temp; } /** * 遍历Student数组 * @param stus */ public void print(Student[] stus){ for (int i = 0; i < stus.length; i++) { stus[i].info(); } } } 测试类 //测试类 public class Exer3 { public static void main(String[] args) { StudentUtil util = new StudentUtil(); // 创建20个学生对象 Student[] stus = util.getStudentArray(20, 1, 6, 0, 100); //问题一:打印出3年级(state值为3)的学生信息。 util.printStudentState(stus,3); //问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息 // util.sort(stus,"descend"); //遍历操作 // util.print(stus); } }
    Processed: 0.017, SQL: 9