知识点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);
}
}