Bootstrap

第06章:随堂复习与企业真题(面向对象-基础)

目录

一、随堂复习

1. (了解)面向过程 vs 面向对象

基本语法的知识点

基本语法的代码

2. 类、对象

基本语法的知识点

01-创建类的一个对象

02-创建类的多个对象1

02-创建类的多个对象2

基本语法的代码

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

基本语法的知识点

基本语法的代码1

基本语法的代码2

案例1

案例1的代码1

案例2的代码2

案例2

案例2的代码1

案例2的代码2

案例2的代码3

4. 类的成员之二:方法

基本语法的知识点

基本语法的代码1

基本语法的代码2

案例1

案例1的代码1

案例1的代码2

 案例2

案例2的代码1

案例2的代码2

 案例3

案例3的代码1

案例3的代码2

 案例4

案例4的代码1

案例4的代码2

 案例5

案例5的代码1

案例5的代码2

 案例6的代码1

案例6的代码2

案例6的代码3

5. 再谈方法

5.1 方法的重载(overload)

基本语法的知识点

基本语法的代码1

基本语法的代码2

案例1

案例1的代码

5.2 可变个数形参的方法

基本语法的知识点

案例1

案例1的代码

5.3 方法的参数传递机制:值传递(重点、难点)

基本语法的知识点

基本语法的代码1

基本语法的代码2

基本语法的代码3

基本语法的代码4

案例1

案例1的代码1

案例1的代码2

案例2

案例2的代码1

案例2的代码2

案例3

案例3的代码

5.4 递归方法

基本语法的知识点

基本语法的代码

案例1

案例1的代码

案例2

案例2的代码

6. 对象数组

案例1

案例1的代码1

案例1的代码2

7. package、import关键字的使用

基本语法的知识点

基本语法的代码1

基本语法的代码2

8. oop的特征之一:封装性

基本语法的知识点

基本语法的代码

案例1

案例1的代码1

案例1的代码2

案例2

案例2的代码1

案例2的代码2

案例3

案例3的代码1

案例3的代码2

案例4

案例4的代码1

案例4的代码2

案例4的代码3

9. 类的成员之三:构造器

基本语法的知识点

基本语法的代码1

基本语法的代码2

案例1

案例1的代码1

案例1的代码2

案例2

案例2的代码1

案例2的代码2

案例3

案例3的代码1

案例3的代码2

案例3的代码3

10. 三个小知识

10.1 类的实例变量的赋值过程(重要)

10.2 JavaBean

10.3 UML类图

基本语法的代码1

基本语法的代码2

二、企业真题

2.1 类与对象

1. 面向对象,面向过程的理解?

2. Java 的引用类型有哪几种

3. 类和对象的区别

4. 面向对象,你解释一下,项目中哪些地方用到面向对象?

2.2 Java内存结构

1. Java虚拟机中内存划分为哪些区域,详细介绍一下

2. 对象存在Java内存的哪块区域里面?

2.3 权限修饰符(封装性)

1. private 、缺省、protected、public的表格化作用区域

2. main方法的public能不能换成private?为什么?

2.4 构造器

1. 构造方法和普通方法的区别

2. 构造器Constructor是否可被overload?

3. 无参构造器和有参构造器的的作用和应用

2.5 属性及属性赋值顺序

1. 成员变量与局部变量的区别

2. 变量赋值和构造方法加载的优先级问题


一、随堂复习

1. (了解)面向过程 vs 面向对象

  • 不管是面向过程、面向对象,都是程序设计的思路。
  • 面向过程:以函数为基本单位,适合解决简单问题。比如:开车
  • 面向对象:以类为基本单位,适合解决复杂问题。比如:造车
基本语法的知识点


1. 面向对象内容的三条主线:
- Java类及类的成员:(重点)属性、方法、构造器;(熟悉)代码块、内部类
- 面向对象的特征:封装、继承、多态、(抽象)
- 其他关键字的使用:this、super、package、import、static、final、interface、abstract等

2. 面向过程编程(POP)  vs  面向对象编程(OOP)
2.1 简单的语言描述二者的区别
> 面向过程:
        - 以`函数`为组织单位。
        - 是一种“`执行者思维`”,适合解决简单问题。扩展能力差、后期维护难度较大。

> 面向对象:
        - 以`类`为组织单位。每种事物都具备自己的`属性`和`行为/功能`。
        - 是一种“`设计者思维`”,适合解决复杂问题。代码扩展性强、可维护性高。

2.2 二者关系:
我们千万不要把面向过程和面向对象对立起来。他们是相辅相成的。面向对象离不开面向过程!

3.
> 面向对象编程的两个核心概念:类(Class)、对象(Object)
> 谈谈对这两个概念的理解?
        类:具有相同特征的事物的抽象描述,是`抽象的`、概念上的定义。
        对象:实际存在的该类事物的`每个个体`,是`具体的`,因而也称为`实例(instance)`。




4. 类的声明与使用
4.1 体会:设计类,其实就是设计类的成员
class Person{

}

4.2 类的内部成员一、二:

成员之一:属性、成员变量、field(字段、域)
成员之二:(成员)方法、函数、method


4.3 类的实例化
等价描述:类的实例化 <=> 创建类的对象  <=> 创建类的实例
格式:类的类型 对象名 = 通过new创建的对象实体
举例:
Phone p1 = new Phone();
Scanner input = new Scanner();
String str = new String();



5. 面向对象完成具体功能的操作的三步流程(非常重要)
步骤1:创建类,并设计类的内部成员(属性、方法)
步骤2:创建类的对象。比如:Phone p1 = new phone();
步骤3:通过对象,调用其内部声明的属性或方法,完成相关的功能





基本语法的代码
package com.atguigu01.oop;

/**
 * ClassName: Phone
 * Package: com.atguigu01.oop
 * Description: 创建类,并设计类的内部成员(属性、方法)
 *
 * @Author 随心油条
 * @Create 2024/1/29 15:40
 * @Version 1.0
 */
public class Phone {

    //属性
    String name;//手机品牌
    double prince;//手机价格

    //方法
    public void call(){
        System.out.println("手机能够拨打电话");
    }

    public  void sendMassage(String message){
        System.out.println("发送信息: " + message);
    }

    public void playGame(){
        System.out.println("手机可以玩游戏");
    }

}
package com.atguigu01.oop;

/**
 * ClassName: PhoneTest
 * Package: com.atguigu01.oop
 * Description: 创建类的对象,通过对象,调用其内部声明的属性或方法,完成相关的功能
 *
 * @Author 随心油条
 * @Create 2024/1/29 15:41
 * @Version 1.0
 */
public class PhoneTest {
    public static void main(String[] args) {

        //复习:数据类型 变量名 = 变量值
        //Scanner input = new Scanner(System.in);

        //创建Phone的对象
        Phone p1 = new Phone();

        //通过Phone的对象,调用其内部声明的属性或方法
        //格式:"对象.属性" 或 "对象.方法"
        p1.name = "huaweimate50";
        p1.prince = 6999;
        System.out.println("name = " + p1.name + "; price = " + p1.prince);

        //调用方法
        p1.call();
        p1.sendMassage("有内鬼,终止交易");
        p1.playGame();
    }
}

2. 类、对象

  • 类:抽象的,概念上的定义
  • 对象:具体的,类的一个一个的实例。
  • 面向对象完成具体功能的操作的三步流程(非常重要)
步骤1:创建类,并设计类的内部成员(属性、方法)
步骤2:创建类的对象。比如:Phone p1 = new Phone();
步骤3:通过对象,调用其内部声明的属性或方法,完成相关的功能
  • 对象的内存解析
  1. 创建类的一个对象;创建类的多个对象;方法的调用的内存解析
  • Java中内存结构的划分
  1. Java中内存结构划分为:虚拟机栈、堆、方法区;程序计数器、本地方法栈
  2. 虚拟机栈:以栈帧为基本单位,有入栈和出栈操作;每个栈帧入栈操作对应一个方法的执行;方法内的局部变量会存储在栈帧中。
  3. 堆空间:new 出来的结构(数组、对象):① 数组,数组的元素在堆中 ② 对象的成员变量在堆中。
  4. 方法区:加载的类的模板结构。
基本语法的知识点


1. 对象在内存中的分配涉及到的内存结构(理论)
- 栈(stack):方法内定义的变量,存储在栈中。
- 堆(heap) :new 出来的结构(比如:数组实体、对象的实体)。包括对象中的属性
- 方法区(method area) :存放类的模板。比如:Person类的模板


2. 类中对象的内存解析
2.1 创建类的一个对象
见《01-创建类的一个对象.png》


2.2 创建类的多个对象
见《02-创建类的多个对象1.png》、《02-创建类的多个对象2.png》

强调1:创建了Person类的两个对象
Person p1 = new Person();
Person p2 = new Person();

说明:创建类的多个对象时,每个对象在堆空间中有一个对象实体。每个对象实体中保存着一份类的属性。
如果修改某一个对象的某属性时,不会影响其他对象此属性的值
p1.age = 10;
p2.age = 20;

p1.age = 30;
System.out.println(p2.age);//20

强调2:声明类的两个变量
Person p1 = new Person();
Person p3 = p1;

说明:此时的p1,p3两个变量指向了堆空间中的同一个对象实体。(或p1,p3保存的地址值相同)
如果通过其中某一个对象变量修改对象的属性时,会影响另一个对象变量此属性的值。

p1.age = 10;
p3.age = 20;
System.out.println(p1.age);//20


2.3 对象调用方法的过程(在"03-类的成员之二:方法"中讲解)




01-创建类的一个对象

02-创建类的多个对象1

02-创建类的多个对象2

基本语法的代码
package com.atguigu02.memory;

/**
 * ClassName: person
 * Package: com.atguigu02.memory
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/1/29 16:15
 * @Version 1.0
 */
public class Person {
    //属性
    String name;//姓名
    int age;//年龄
    char gender;//性别

    //方法
    public void eat(){
        System.out.println("我都要吃8碗饭!");
    }

    public void sleep(int hours){
        System.out.println("我每天需要睡" + hours + "小时!");
    }

    public void interest(String hobby){
        System.out.println("我的爱好是:" + hobby);
    }
}
package com.atguigu02.memory;

/**
 * ClassName: PersonTest
 * Package: com.atguigu02.memory
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/1/29 16:16
 * @Version 1.0
 */
public class PersonTest {
    public static void main(String[] args) {
        //创建对象、类的实例化
        Person p1 = new Person();

        //通过对象调用属性或方法
        p1.name = "Jack";
        p1.age = 23;
        p1.gender = '男';

        System.out.println("name = " + p1.name + ", age = " + p1.age + ", gender = " + p1.gender);

        //调用方法
        p1.eat();
        p1.sleep(8);
        p1.interest("打牌");

        //再创建Person类的一个实例
        Person p2 = new Person();

        //调用属性
        p2.name = "Rose";
        p2.age = 18;
        p2.gender = '女';
        //调用方法
        p2.eat();
        p2.sleep(8);
        p2.interest("聚会");
        System.out.println("name = " + p2.name + ", age = " + p2.age + ", gender = " + p2.gender);
        System.out.println("name = " + p1.name + ", age = " + p1.age + ", gender = " + p1.gender);

    }
}

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

  • 属性 vs 局部变量
  1. 声明的位置
  2. 内存中存放的位置
  3. 作用域
  4. 权限修饰符
  5. 初始化值
  6. 生命周期
  • 属性 <=> 成员变量 <=>field <=> 字段、域
基本语法的知识点

类的成员之一:属性

1.变量的分类:
- 角度一:按照数据类型来分:基本数据类型(8种)、引用数据类型(数组、类、接口、枚举、注解、记录)
- 角度二:按照变量在类中声明的位置的不同:成员变量(或属性)、局部变量(方法内、方法形参、构造器内、构造器形参、代码块内等)

2. 属性的几个称谓:成员变量、属性、field(字段、域)


3. 区分成员变量   vs 局部变量
3.1 相同点:
> 变量声明的格式相同:数据类型 变量名 = 变量值
> 变量都有其有效的作用域。出了作用域,就失效了。
> 变量必须先声明,后赋值,再使用。

3.2 不同点:
① 类中声明的位置的不同:
    属性:声明在类内,方法外的变量
    局部变量:声明方法、构造器内部的变量

② 在内存中分配的位置不同:
    属性:随着对象的创建,存储在堆空间中。
    局部变量:存储在栈空间中

③ 生命周期:
    属性:随着对象的创建而创建,随着对象的消亡而消亡。
    局部变量:随着方法对应的栈帧入栈,局部变量会在栈中分配;随着方法对应的栈帧出栈,局部变量消亡。

④ 作用域:
    属性:在整个类的内部都是有效的
    局部变量:仅限于声明此局部变量所在的方法(或构造器、代码块)中

⑤ 是否可以有权限修饰符进行修饰:(难)
    都是哪些权限修饰符:public、protected、缺省、private。(用于表示所修饰的结构可调用的范围的大小)

    属性,是可以使用权限修饰符进行修饰的。暂时还未讲封装性,所以大家先不用写任何权限符。
    而局部变量,不能使用任何权限修饰符进行修饰的。

⑥ 是否有默认值:
    属性:都有默认初始化值
        意味着,如果没有给属性进行显示初始化赋值,则会有默认初始化值。

    局部变量:都没有默认初始化值。
        意味着,在使用局部变量之前,必须要显式的赋值,否则报错。

        注意,对于方法的形参而言,在调用方法时,给此形参赋值即可。
基本语法的代码1
package com.atguigu03.field_method.field;

/**
 * ClassName: FieldTest
 * Package: com.atguigu03.field_method.field
 * Description: 属性测试
 *
 * @Author 随心油条
 * @Create 2024/2/3 21:38
 * @Version 1.0
 */
public class FieldTest {
    public static void main(String[] args) {

        //创造对象
        Person p1 = new Person();

        //调属性
        System.out.println("name = " + p1.name + ", age = " + p1.age);

        //调方法
        p1.eat();
        p1.sleep(8);

    }
}

class Person {

    //属性(或成员变量)
    String name;
    int age;
    char gender;

    //方法
    public void eat(){
        String food = "宫保鸡丁";//局部变量
        System.out.println("我们要吃" + food);
    }

    public void sleep(int hours){//形参:属于局部变量
        System.out.println("我们要睡" + hours + "小时的睡眠");

        //编译不通过,因为超出了food变量的作用域
        //System.out.println("我喜欢吃" + food);

        //编译通过
        System.out.println("name = " + name);
    }

}
基本语法的代码2
package com.atguigu03.field_method.field;

/**
 * ClassName: FieldTest
 * Package: com.atguigu03.field_method.field
 * Description: 属性测试
 *
 * @Author 随心油条
 * @Create 2024/2/3 21:38
 * @Version 1.0
 */
public class FieldTest {
    public static void main(String[] args) {

        //创造对象
        Person p1 = new Person();

        //调属性
        System.out.println("name = " + p1.name + ", age = " + p1.age);

        //调方法
        p1.eat();
        p1.sleep(8);

    }
}

class Person {

    //属性(或成员变量)
    String name;
    int age;
    char gender;

    //方法
    public void eat(){
        String food = "宫保鸡丁";//局部变量
        System.out.println("我们要吃" + food);
    }

    public void sleep(int hours){//形参:属于局部变量
        System.out.println("我们要睡" + hours + "小时的睡眠");

        //编译不通过,因为超出了food变量的作用域
        //System.out.println("我喜欢吃" + food);

        //编译通过
        System.out.println("name = " + name);
    }

}
案例1


案例:

声明员工类Employee,包含属性:编号id、姓名name、年龄age、薪资salary。

声明EmployeeTest测试类,并在main方法中,创建2个员工对象,并为属性赋值,并打印两个员工的信息。

案例1的代码1
package com.atguigu03.field_method.field.exer1;

/**
 * ClassName: Employee
 * Package: com.atguigu03.field_method.field.exer1
 * Description: 声明员工类Employee,包含属性:编号id、姓名name、年龄age、薪资salary。
 *
 * @Author 随心油条
 * @Create 2024/2/3 22:36
 * @Version 1.0
 */
public class Employee {

    //属性(或成员变量)
    int id;//编号
    String name;//姓名
    int age;//年龄
    double salary;//薪资
}
案例2的代码2
package com.atguigu03.field_method.field.exer1;

/**
 * ClassName: EmployeeTest
 * Package: com.atguigu03.field_method.field.exer1
 * Description: 声明EmployeeTest测试类,并在main方法中,创建2个员工对象,并为属性赋值,并打印两个员工的信息。
 *
 * @Author 随心油条
 * @Create 2024/2/3 22:37
 * @Version 1.0
 */
public class EmployeeTest {
    public static void main(String[] args) {

        //创建类的实例(或创建类的对象、类的实例化)
        Employee empl1 = new Employee();
        empl1.id = 1001;
        empl1.name = "Tom";
        empl1.age = 18;
        empl1.salary = 7800.0;

        System.out.println("id = " + empl1.id + ", name = " + empl1.name +
                ", age = " + empl1.age + ", salary = " + empl1.salary);
//        输出结果为 id = 1001, name = Tom, age = 18, salary = 7800.0

        //创建Employee的第2个对象
        Employee empl3 = empl1;//错误写法,这样是将empl1的地址给了empl3,凡是引用数据类型存的都是地址值。

        Employee empl2 = new Employee();
        System.out.println("id = " + empl2.id + ", name = " + empl2.name +
                ", age = " + empl2.age + ", salary = " + empl2.salary);
//        输出结果为 id = 0, name = null, age = 0, salary = 0.0
    }
}
案例2


案例:

(1)声明一个MyDate类型,有属性:年year,月month,日day

(2)声明一个Employee类型,包含属性:编号、姓名、年龄、薪资、生日(MyDate类型)

(3)在EmployeeTest测试类中的main()中,创建两个员工对象,并为他们的姓名和生日赋值,并显示
案例2的代码1
package com.atguigu03.field_method.field.exer2;

/**
 * ClassName: Employee
 * Package: com.atguigu03.field_method.field.exer2
 * Description: (2)声明一个Employee类型,包含属性:编号、姓名、年龄、薪资、生日(MyDate类型)
 *
 * @Author 随心油条
 * @Create 2024/2/3 23:04
 * @Version 1.0
 */
public class Employee {

    int id;//编号
    String name;//姓名
    int age;//年龄
    double salary;//薪资
    MyDate birthday;//生日

}
案例2的代码2
package com.atguigu03.field_method.field.exer2;

/**
 * ClassName: EmployeeTest
 * Package: com.atguigu03.field_method.field.exer2
 * Description: (3)在EmployeeTest测试类中的main()中,创建两个员工对象,并为他们的姓名和生日赋值,并显示
 *
 * @Author 随心油条
 * @Create 2024/2/3 23:05
 * @Version 1.0
 */
public class EmployeeTest {
    public static void main(String[] args) {
        Employee emp1 = new Employee();//创建对象,对象实例化
        emp1.id = 1001;
        emp1.name = "Jack";
        emp1.age = 24;
        emp1.birthday = new MyDate();
        emp1.birthday.year = 1998;
        emp1.birthday.month = 2;
        emp1.birthday.day = 29;
        System.out.println("id = " + emp1.id + ", name = " + emp1.name +
                ", age " + emp1.age + ", birthday = [" + emp1.birthday.year +
                "年" + emp1.birthday.month + "月" + emp1.birthday.day + "日]");

        Employee emp2 = new Employee();//创建对象,对象实例化
        emp2.id = 1002;
        emp2.name = "rose";
        emp2.age = 18;
        emp2.birthday = new MyDate();
        emp2.birthday.year = 2004;
        emp2.birthday.month = 2;
        emp2.birthday.day = 29;
        System.out.println("id = " + emp2.id + ", name = " + emp2.name +
                ", age " + emp2.age + ", birthday = [" + emp2.birthday.year +
                "年" + emp2.birthday.month + "月" + emp2.birthday.day + "日]");
    }
}
案例2的代码3
package com.atguigu03.field_method.field.exer2;

/**
 * ClassName: MyDate
 * Package: com.atguigu03.field_method.field.exer2
 * Description: (1)声明一个MyDate类型,有属性:年year,月month,日day
 *
 * @Author 随心油条
 * @Create 2024/2/3 23:05
 * @Version 1.0
 */
public class MyDate {

    int year;//年
    int month;//月
    int day;//日

}

4. 类的成员之二:方法

  • 方法的声明:权限修饰符 返回值类型 方法名(形参列表){ // 方法体}
  1. 重点:返回值类型、形参列表
  • return关键字的使用
基本语法的知识点


类的成员之二:方法(method)

1. 使用方法的好处

方法的理解:方法是类或对象行为特征的抽象,用来完成某个功能操作。
方法的好处:实现代码重用,减少冗余,简化代码

2. 使用举例

- Math.random()的random()方法
- Math.sqrt(x)的sqrt(x)方法
- System.out.println(x)的println(x)方法
- new Scanner(System.in).nextInt()的nextInt()方法
- Arrays类中的binarySearch()方法、sort()方法、equals()方法

3. 声明举例
public void eat()
public void sleep(int hours)
public String  interests(String hobby)
public void printNumber(int targetNumber)


4. 方法声明的格式

权限修饰符 [其他修饰符] 返回值类型 方法名(形参列表) [throws 异常类型]{//方法头、方法的声明
    //方法体
}

注:[]中的内部不是必须的,以后再讲

5. 具体的方法声明的细节

5.1 权限修饰符
    ①Java规定了哪些权限修饰符呢? 有四种:private \ 缺省 \ protect \ public (放到封装性讲)
      暂时大家声明方法时,可以先都写成pubilc的。

5.2 返回值类型:描述当调用完此方法时,是否需要返回一个结果。
       分类:
       > 无返回值类型:使用void表示即可。比如:System.out.println(x)的println(x)方法、Arrays的sort()
       > 有具体的返回值类型:需要指明返回的数据的类型。可以是基本数据类型,也可以是引用数据类型
            > 需要在方法内部配合使用"return + 返回值类型的变量或常量"
            比如:Math.random()、new Scanner(System.in).nextInt()等
       [经验]我们在声明方法时,要不要提供返回值类型呢?
        > 根据方法具体实现的功能来决定。换句话说,具体问题具体分析
        > 根据题目要求

5.3 方法名:属于标识符。需要满足标识符的规定和规范。"见名知意"

5.4 形参列表:形参,属于局部变量,且可以声明多个。
    格式:(形参类型1 形参1,形参类型2 形参2,...)
    分类:无形参列表 、 有形参列表
        > 无形参列表:不能省略一对()。比如:Math.random()、new Scanner(System.in).nextInt()
        > 有形参列表:根据方法调用时,需要的不确定的变量的类型和个数,确定形参的类型和个数。
            比如:Arrays类中的binarySearch()方法、sort()方法、equals()方法
    [经验]我们在声明方法时,是否需要形参列表呢?
    > 根据方法具体实现的功能来决定。换句话说,具体问题具体分析
    > 根据题目要求

5.5 方法体: 当我们调用一个方法时,真正执行的代码。体现了此方法的功能。

6. 注意点

> Java里的方法`不能独立存在`,所有的方法必须定义在类里。
> Java中的方法不调用,不执行。每调用一次,就执行一次。
> 方法内可以调用本类中的(其他)方法或属性
> 方法内不能定义方法。

7.关键字:return
7.1 return的作用
    - 作用1:结束一个方法
    - 作用2:结束一个方法的同时,可以返回数据给方法的调用者(方法声明中如果有返回值类型,则方法内需要搭配return使用)

7.2 使用注意点:
    return后面不能声明执行语句。

8. 方法调用的内存解析:
- 形参:方法在声明时,一对()内声明的一个或多个形式参数,简称为形参。
- 实参:方法在被调用时,实际传递给形参的变量或常量,就称为实际参数,简称实参。

过程概述:



基本语法的代码1
package com.atguigu03.field_method;

/**
 * ClassName: MethodTest
 * Package: com.atguigu03.field_method
 * Description: 类成员之二:方法
 *
 * @Author 随心油条
 * @Create 2024/2/5 22:56
 * @Version 1.0
 */
public class MethodTest {
    public static void main(String[] args) {

        Person p1 = new Person();
        p1.eat();//方法调用一次执行一次,调用一次执行一次
        p1.eat();

        p1.info1();

        p1.getAge(8);

        p1.sleep(8);

        String info = p1.interests("编程");
        System.out.println(info);

    }
}
class Person{

    //属性
    String name;
    int age;
    char gender;

    //方法
    public void eat(){
        System.out.println("人吃饭");

    }

    public void sleep(int hours){
        System.out.println("人必须睡满" + hours + "小时");
    }

    public String  interests(String hobby){
        String info = "我的爱好是" + hobby;
        System.out.println(info);
        return info;
        //无法访问的语句,return后面不能声明执行语句
        //return "abc";
    }

    public void info1(){
        System.out.println("Person info()");

//        info();
        //方法内不能定义方法!非法的表达式开始
//        public void show(){}
    }

    public void getAge(int getAge){//10
        for (int i = 1; i <= getAge; i++){

            if (i == 4){
                return;//用于结束方法

            }

            System.out.println(i);
        }

    }
}
基本语法的代码2
package com.atguigu03.field_method;

/**
 * ClassName: MethodTest
 * Package: com.atguigu03.field_method
 * Description: 类成员之二:方法
 *
 * @Author 随心油条
 * @Create 2024/2/5 22:56
 * @Version 1.0
 */
public class MethodTest {
    public static void main(String[] args) {

        Person p1 = new Person();
        p1.eat();//方法调用一次执行一次,调用一次执行一次
        p1.eat();

        p1.info1();

        p1.getAge(8);

        p1.sleep(8);

        String info = p1.interests("编程");
        System.out.println(info);

    }
}
class Person{

    //属性
    String name;
    int age;
    char gender;

    //方法
    public void eat(){
        System.out.println("人吃饭");

    }

    public void sleep(int hours){
        System.out.println("人必须睡满" + hours + "小时");
    }

    public String  interests(String hobby){
        String info = "我的爱好是" + hobby;
        System.out.println(info);
        return info;
        //无法访问的语句,return后面不能声明执行语句
        //return "abc";
    }

    public void info1(){
        System.out.println("Person info()");

//        info();
        //方法内不能定义方法!非法的表达式开始
//        public void show(){}
    }

    public void getAge(int getAge){//10
        for (int i = 1; i <= getAge; i++){

            if (i == 4){
                return;//用于结束方法

            }

            System.out.println(i);
        }

    }
}
案例1


案例:将属性测试的exer1中关于员工信息的输出内容放到方法中。通过调用方法显示。

案例1的代码1
package com.atguigu03.field_method.method.exer;

/**
 * ClassName: Employee
 * Package: com.atguigu03.field_method.field.exer1
 * Description: 声明员工类Employee,包含属性:编号id、姓名name、年龄age、薪资salary。
 *
 * @Author 随心油条
 * @Create 2024/2/3 22:36
 * @Version 1.0
 */
public class Employee {

    //属性(或成员变量)
    int id;//编号
    String name;//姓名
    int age;//年龄
    double salary;//薪资

    //定义一个方法,用于显示员工的属性信息
    public void show(){
        System.out.println("id = " + id + ", name = " + name +
                ", age = " + age + ", salary = " + salary);
    }

    public String show1(){
        return "id = " + id + ", name = " + name +
                ", age = " + age + ", salary = " + salary;
    }
}
案例1的代码2
package com.atguigu03.field_method.method.exer;

/**
 * ClassName: EmployeeTest
 * Package: com.atguigu03.field_method.field.exer1
 * Description: 声明EmployeeTest测试类,并在main方法中,创建2个员工对象,并为属性赋值,并打印两个员工的信息。
 *
 * @Author 随心油条
 * @Create 2024/2/3 22:37
 * @Version 1.0
 */
public class EmployeeTest {
    public static void main(String[] args) {

        //创建类的实例(或创建类的对象、类的实例化)
        Employee empl1 = new Employee();
        empl1.id = 1001;
        empl1.name = "Tom";
        empl1.age = 18;
        empl1.salary = 7800.0;

//        System.out.println("id = " + empl1.id + ", name = " + empl1.name +
//                ", age = " + empl1.age + ", salary = " + empl1.salary);
//        输出结果为 id = 1001, name = Tom, age = 18, salary = 7800.0


//        System.out.println(empl1.show());报错了,此处不允许使用 '空' 类型

        System.out.println(empl1.show1());//编译通过
        //替换为:
        empl1.show();
        //创建Employee的第2个对象
        Employee empl3 = empl1;//错误写法,这样是将empl1的地址给了empl3,凡是引用数据类型存的都是地址值。

        Employee empl2 = new Employee();
//        System.out.println("id = " + empl2.id + ", name = " + empl2.name +
//                ", age = " + empl2.age + ", salary = " + empl2.salary);
//        输出结果为 id = 0, name = null, age = 0, salary = 0.0

        //替换为:
        empl2.show();

        empl3.show1();//没有显示,因为没有接收

        System.out.println(empl3.show1());
    }
}
 案例2

案例:

(1)创建Person类的对象,设置该对象的name、age和gender属性,
调用study方法,输出字符串“studying”;
调用showAge()方法,返回age值;
调用addAge(int addAge)方法给对象的age属性值增加addAge岁。比如:2岁。

(2)创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系。
案例2的代码1
package com.atguigu04.example.exer1;

/**
 * ClassName: Person
 * Package: com.atguigu04.example.exer1
 * Description:  (1)创建Person类的对象,设置该对象的name、age和gender属性,
 *                  调用study方法,输出字符串“studying”;
 *                  调用showAge()方法,返回age值;
 *                  调用addAge(int addAge)方法给对象的age属性值增加addAge岁。比如:2岁。
 *
 * @Author 随心油条
 * @Create 2024/2/6 12:43
 * @Version 1.0
 */
public class Person {
    //属性,成员变量

    String name;
    int age;
    char gender;

    //方法
    public void study(){
        System.out.println("studying");
    }

    public int showAge(){
        return age;
    }

    public int addAge(int addAge){
        return  age += addAge;
    }
}
案例2的代码2
package com.atguigu04.example.exer1;

/**
 * ClassName: PersonTest
 * Package: com.atguigu04.example.exer1
 * Description: 创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系。
 *
 * @Author 随心油条
 * @Create 2024/2/6 12:43
 * @Version 1.0
 */
public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person();

        //调用属性
        p1.name = "Tom";
        p1.age = 24;
        p1.gender = '男';
        //调用方法

        System.out.println("age = " + p1.showAge());//24

        p1.study();
        System.out.println("age = " + p1.addAge(2));//24 --> 26

        Person p2 = new Person();

        p2.name = "Rose";
        p2.gender = '女';
        p2.study();
        System.out.println("age = " + p2.showAge());//0

        System.out.println("age = " + p2.addAge(10));//0 --> 10
    }
}
 案例3


案例:

1. 编写程序,声明一个method1方法,在方法中打印一个10*8 的*型矩形,在main方法中调用该方法。

2. 编写程序,声明一个method2方法,除打印一个10*8的*型矩形外,
再计算该矩形的面积,并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。

3. 编写程序,声明一个method3方法,在method3方法提供m和n两个参数,方法中打印一个m*n的*型矩形,
并计算该矩形的面积,将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
案例3的代码1
package com.atguigu04.example.exer2;

/**
 * ClassName: Exer02
 * Package: com.atguigu04.example.exer2
 * Description:
 *
 * 1. 编写程序,声明一个method1方法,在方法中打印一个10*8 的*型矩形,在main方法中调用该方法。
 *
 * 2. 编写程序,声明一个method2方法,除打印一个10*8的*型矩形外,
 * 再计算该矩形的面积,并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
 *
 * 3. 编写程序,声明一个method3方法,在method3方法提供m和n两个参数,方法中打印一个m*n的*型矩形,
 * 并计算该矩形的面积,将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:03
 * @Version 1.0
 */
public class Exer02 {

    //1. 编写程序,声明一个method1方法,在方法中打印一个10*8 的*型矩形,在main方法中调用该方法。
    public void method1(){
        for (int i = 0; i < 10; i++) {//列数
            for (int j = 0; j < 8; j++) {//行数
                System.out.print('*');
            }
            System.out.println();//换行
        }
    }
    //2. 编写程序,声明一个method2方法,除打印一个10*8的*型矩形外,
    //   再计算该矩形的面积,并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
    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. 编写程序,声明一个method3方法,在method3方法提供m和n两个参数,方法中打印一个m*n的*型矩形,
    //   并计算该矩形的面积,将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
    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;
    }
}
案例3的代码2
package com.atguigu04.example.exer2;

/**
 * ClassName: Exer02Test
 * Package: com.atguigu04.example.exer2
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:03
 * @Version 1.0
 */
public class Exer02Test {
    public static void main(String[] args) {

        //创建Exer02的对象
        Exer02 exer = new Exer02();
        exer.method1();
        int area = exer.method2();
        System.out.println("面积为 = " + area);

        int area1 = exer.method3(3,8);
        System.out.println("面积为 = " + area1);
    }
}
 案例4

案例:

利用面向对象的编程方法,设计类Circle计算圆的面积。

案例4的代码1
package com.atguigu04.example.exer3;

/**
 * ClassName: Circle
 * Package: com.atguigu04.example.exer3
 * Description: 利用面向对象的编程方法,设计类Circle计算圆的面积。
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:19
 * @Version 1.0
 */
public class Circle {
    //属性
    double radius = 2.3;//半径

    //方法
    //方法1
    public void findArea(){
        System.out.println("面积为 = " + 3.14 * radius *radius);
    }

    //方法2(这里也行,就是半径的作用域太小,半径为局部变量,没有属性成员变量的作用域大)
    public void findArea1(double r){
        System.out.println("面积为 = " + 3.14 * r * r);
    }

    //方法3(没有限制返回值,可以用有返回值来写)
    public double findArea2(){
        return 3.14 * radius * radius;
    }
}
案例4的代码2
package com.atguigu04.example.exer3;

/**
 * ClassName: CircleTest
 * Package: com.atguigu04.example.exer3
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:19
 * @Version 1.0
 */
public class CircleTest {
    public static void main(String[] args) {
        Circle cir = new Circle();
        cir.findArea();
        cir.findArea1(2.3);
        double area = cir.findArea2();
        System.out.println("面积为 = " + area);
    }
}
 案例5

案例:

根据上一章数组中的常用算法操作,自定义一个操作int[]的工具类。
涉及到的方法有:求最大值、最小值、总和、平均数、遍历数组、复制数组、
             数组反转、数组排序(默认从小到大排序)、查找等
案例5的代码1
package com.atguigu04.example.exer4;

/**
 * ClassName: MyArrays
 * Package: com.atguigu04.example.exer4
 * Description:
 *
 * 根据上一章数组中的常用算法操作,自定义一个操作int[]的工具类。
 * 涉及到的方法有:求最大值、最小值、总和、平均数、遍历数组、复制数组、
 *              数组反转、数组排序(默认从小到大排序)、查找等
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:56
 * @Version 1.0
 */
public class MyArrays {

    /**
     * 获取int[]数组的最大值
     * @param arr 要获取最大值的数组
     * @return 数组的最大值
     */

    public int getMax(int[] arr){
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max){
                max = arr[i];
            }
        }
        return max;
    }

    /**
     * 获取int[]数组的最小值
     * @param arr 要获取最小值的数组
     * @return 数组的最小值
     */
    public int getMix(int[] arr){
        int mix = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] < mix){
                mix = arr[i];
            }
        }
        return mix;
    }

    /**
     * 获取int[]数组的总和
     * @param arr 要获取数组的总和
     * @return 数组的总和
     */
    public int getSum(int[] arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum;
    }

    /**
     * 获取int[]数组的平均值
     * @param arr 要获取数组的平均值
     * @return 数组的平均值
     */
    public int getAvg(int[] arr){
        return getSum(arr) / arr.length;
    }

    /**
     * 遍历int[]数组
     * @param arr 要遍历数组
     * @return 遍历数组
     */
    public void print(int[] arr){ {//[12,231,34]
        System.out.print("[");
        for (int i = 0; i < arr.length; i++)
            if (i == 0){
                System.out.print(arr[i]);
            }else {
                System.out.print("," + arr[i]);
            }

        System.out.println("]");
        }
    }

    /**
     * 复制int[]数组
     * @param arr 要复制数组
     * @return 复制数组
     */
    public int[] copy(int[] arr){
        int[] newArr = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            newArr[i] = arr[i];
        }
        return newArr;
    }

    /**
     * 反转int[]数组
     * @param arr 要反转数组
     * @return 反转数组
     */
    public int[] reverse(int[] arr){
        for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
            //交互arr[i]和arr[j]位置的元素
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        return arr;
    }

    /**
     * 对int[]数组进行从小到大排序
     * @param arr 要对int[]数组进行从小到大排序
     * @return 排序数组
     */
    public int[] sort(int[] arr){
        for (int j = 0; j < arr.length; j++) {
            for (int i = 1; i < arr.length - 1 - j; i++) {
                if (arr[i] > arr[i + 1]){
                    //交互arr[i] 和 arr[i + 1]
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                }
            }
        }
        return arr;
    }

    /**
     * 对int[]数组进行从小到大排序
     * @param arr 要对int[]数组进行从小到大排序
     * @param target 要查找的元素
     * @return 排序数组
     */
    public int linearSearch(int[] arr, int target){
        for (int i = 0; i < arr.length; i++) {
            if (target == arr[i]){
                return i;
            }
        }

        //只要代码执行到此位置,一定是没找到
        return -1;
    }

}
案例5的代码2
package com.atguigu04.example.exer4;

/**
 * ClassName: MyArraysTest
 * Package: com.atguigu04.example.exer4
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:56
 * @Version 1.0
 */
public class MyArraysTest {
    public static void main(String[] args) {
        MyArrays arrs = new MyArrays();
        int[] arr = new int[]{34, 56, 223, 2, 56, 24, 56, 67, 778, 45};

        //求最大值
        System.out.println("最大值为 = " + arrs.getMax(arr));

        //求最小值
        System.out.println("最小值为 = " + arrs.getMix(arr));

        //平均值
        System.out.println("该数组的平均值为 = " + arrs.getAvg(arr));
        //遍历
        System.out.print("遍历数组的每个元素:" );
        arrs.print(arr);

        //查找
        int index = arrs.linearSearch(arr,12);
        if (index >= 0){
            System.out.println("找到了,位置为:" + index);
        }else {
            System.out.println("未找到");
        }

        //查找
        int index1 = arrs.linearSearch(arr,24);
        if (index1 >= 0){
            System.out.println("找到了,位置为:" + index1);
        }else {
            System.out.println("未找到");
        }

        //排序
        arrs.sort(arr);

        //遍历
        System.out.print("排序之后再遍历:" );
        arrs.print(arr);
    }
}
 案例6的代码1
package com.atguigu04.example.exer5_objarr1;

/**
 * ClassName: Student
 * Package: com.atguigu04.example.exer5_objarr
 * Description: 定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)
 *
 * @Author 随心油条
 * @Create 2024/2/6 21:33
 * @Version 1.0
 */
public class Student {
    //属性
    int number;
    int state;
    int score;

    //定义一个显示方法
    public String show(){
        return "number = " + number + ",state = " +
                state + ",score = " + score;
    }
}
案例6的代码2
package com.atguigu04.example.exer5_objarr1;

/**
 * ClassName: StudentUtil
 * Package: com.atguigu04.example.exer5_objarr1
 * Description: 将StudentTest的一些操作封装为方法
 *
 * @Author 随心油条
 * @Create 2024/2/6 22:58
 * @Version 1.0
 */
public class StudentUtil {

    /**
     * 打印出指定年级的学生信息
     */
    public void printStudentsWithState(Student[] students,int state){
        for (int i = 0; i < students.length; i++) {
            if (state == students[i].state){
                System.out.println(students[i].show());
            }
        }
    }


    /**
     * 遍历指定学生数组
     */
    public void printStudent(Student[] students){
        for (int j = 0; j < students.length; j++) {
            System.out.println(students[j].show());
        }
    }

    /**
     * 针对学生数组,安照score属性从低到高排列
     */
    public void sortStudents(Student[] students){
        for (int j = 0; j < students.length - 1; j++) {
            for (int k = 0; k < students.length - 1 - j; k++) {
                if (students[k + 1].score < students[k].score){
                    Student temp = students[k];
                    students[k] = students[k + 1];
                    students[k + 1] = temp;
                }
            }
        }
    }

}
案例6的代码3
package com.atguigu04.example.exer5_objarr1;

/**
 * ClassName: StudentTest
 * Package: com.atguigu04.example.exer5_objarr
 * Description:
 *
 * 1)定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
 * 2)创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
 * 问题一:打印出3年级(state值为3)的学生信息。
 * 问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
 * 提示:
 * 1) 生成随机数:Math.random(),返回值类型double;
 * 2) 四舍五入取整:Math.round(double d),返回值类型long。
 * 年级[1,6] : (int)(Math.random() * 6 + 1)
 * 分数[0,100] : (int)(Math.random() * 101)
 *
 * @Author 随心油条
 * @Create 2024/2/6 21:33
 * @Version 1.0
 */
public class StudentTest {
    public static void main(String[] args) {

        //创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
        Student[] students = new Student[20];

        //使用循环,给数组的元素赋值
        for (int i = 0; i < students.length; i++) {
            //创造二十个对象
            //Student stu1 = new Student();//错误的,没有将循环利用起来
            students[i] = new Student();

            //给每一个学生对象的number、state、score属性赋值。年级和成绩都是由随机数确定的
            students[i].number = i + 1;
            students[i].state = (int)(Math.random() *  6 + 1);
            students[i].score = (int) (Math.random() * 101);

            }

        //需求1:打印出3年级(state值为3)的学生信息
        StudentUtil util = new StudentUtil();
        util.printStudentsWithState(students,3);
        System.out.println("******************************");


        //排序前遍历
            util.printStudent(students);

            System.out.println("******************************");

            //使用冒泡排序按学生成绩排序,并遍历所有学生信息
            util.sortStudents(students);

            //排序后遍历
        util.printStudent(students);
        }



    }

5. 再谈方法

5.1 方法的重载(overload)

  • 方法的重载的要求:“两同一不同”,同一个类,方法名相同,形参不同。
  • 调用方法时,如何确定调用的是某个指定的方法呢?① 方法名 ② 形参列表
基本语法的知识点

再谈方法之1:方法的重载(overload)

1. 定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。
        满足这样的特征的多个方法,彼此之间构成方法的重载。


2. 总结为:
    两同:同一个类、相同的方法名
    一不同:参数列表不同。① 参数个数不同 ② 参数类型不同

    注意:方法的重载与形参的名、权限修饰符、返回值类型都没有关系。

3. 举例
Arrays类中sort(xxx[] arr)、binarySearch(xxx[] arr,xxx)、equals(xxx[],yyy[])


4. 如何判断两个方法是相同的呢?(换句话说,编译器是如何确定调用的某个具体的方法呢?)

如何判断两个方法是相同的呢?方法名相同,且形参列表相同。(形参列表相同是指的是参数个数和类型都相同,与形参名没关系)

要求:在一个类中,允许存在多个相同名字的方法,只要他们的参数列表不同即可。

编译器是如何确实调用的某个具体的方法呢?先通过方法名确定了一波重载的方法,进而通过不同的形参列表,确定具体的某一个方法。

5.在同一个类中不允许定义两个相同的方法。
基本语法的代码1
package com.atguigu05.method_more._01overload;

/**
 * ClassName: InterviewTest
 * Package: com.atguigu05.method_more._01overload.exer
 * Description: 重载关于char数组的特殊性,会遍历一次
 *
 * @Author 随心油条
 * @Create 2024/2/7 8:56
 * @Version 1.0
 */

//面试题
public class InterviewTest {
    public static void main(String[] args) {

        int[] arr = new int[]{1,2,3};
        System.out.println(arr);//地址值

        char[] arr1 = new char[]{'a','b','c','d','e'};
        System.out.println(arr1);//abc

        boolean[] arr2 = new boolean[]{false,true,true};
        System.out.println(arr2);//地址值

    }
}
基本语法的代码2
package com.atguigu05.method_more._01overload;

/**
 * ClassName: OverloadTest
 * Package: com.atguigu05.method_more._01overload.exer
 * Description: 方法的重载
 *
 * @Author 随心油条
 * @Create 2024/2/7 8:57
 * @Version 1.0
 */
public class OverloadTest {

    public void add(int i, int j){

    }

    public void add(double d1, double d2){

    }

    public void add(int i, int j, int k){

    }

    public void add(String i, String j){

    }

    public void add(int i, String s){

    }

    public void add(String s, int i){

    }

    //方法的重载与形参的名无关
    //public void add(int m,int n){
    //}

    //方法的重载与权限修饰符、返回值类型无关
    //public int add(int m, int n){
        //return m + n;
    //}
}
案例1

练习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参数、一个字符串参数。
分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。


练习3:
定义三个重载方法max():
第一个方法求两个int值中的最大值,
第二个方法求两个double值中的最大值,
第三个方法求三个double值中的最大值,并分别调用三个方法。
案例1的代码
package com.atguigu05.method_more._01overload.exer;

/**
 * ClassName: OverLoadExer
 * Package: com.atguigu05.method_more._01overload.exer
 * Description: 练习两个习题
 *
 * @Author 随心油条
 * @Create 2024/2/7 9:11
 * @Version 1.0
 */
public class OverLoadExer {
    /**
     * 练习2:
     * 编写程序,定义三个重载方法并调用。方法名为mOL。
     * 三个方法分别接收一个int参数、两个int参数、一个字符串参数。
     * 分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。
     */
    public void m0L(int m){
        System.out.println(m * m);
    }

    public void m0L(int m, int n){
        System.out.println(m * n);
    }

    public void m0L(String m){
        System.out.println(m);
    }

    /** 练习3:
     * 定义三个重载方法max():
     * 第一个方法求两个int值中的最大值,
     * 第二个方法求两个double值中的最大值,
     * 第三个方法求三个double值中的最大值,并分别调用三个方法。
     */
    public int max(int m, int n){
        return (m >= n)? m : n;
    }

    public double max(double m, double n){
        return (m >= n)? m : n;
    }

    public double max(double m, double n, double y){
        //方法1
        //double temp = max(m,n);
        //return max(temp,y);

        //方法2
        return (max(m,n) >= y)? max(m,n):y;
    }
}

5.2 可变个数形参的方法

  • 格式:(int ... args)
基本语法的知识点


再谈方法之2:可变个数形参的方法(jdk5.0)

1. 使用场景
在调用方法时,可能会出现方法形参的类型是确实的,但是参数的个数不确定。此时,我们就可以使用可变个数形参的方法

2. 格式:(参数类型 ... 参数名)


3. 说明:
① 可变个数形参的方法在调用时,针对于可变的形参赋的实参的个数可以为:0个、1个或多个
② 可变个数形参的方法与同一个类中,同名的多个方法之间可以构成重载
③ 特例:可变个数形参的方法与同一个类中方法名相同,且与可变个数形参的类型相同的数组参数不构成重载。
④ 可变个数的形参必须声明在形参列表的最后
⑤ 可变个数的形参最多在一个方法的形参列表中出现一次。
案例1


练习:可变形参的方法

n个字符串进行拼接,每一个字符串之间使用某字符进行分割,如果没有传入字符串,那么返回空字符串""
案例1的代码
package com.atguigu05.method_more._02args;

/**
 * ClassName: ArgsTest
 * Package: com.atguigu05.method_more._02args.exer
 * Description: 可变个数形参的方法
 *
 * @Author 随心油条
 * @Create 2024/2/7 9:38
 * @Version 1.0
 */
public class ArgsTest {
    public static void main(String[] args) {
        ArgsTest args1 = new ArgsTest();
        args1.print();
        args1.print(1);
        args1.print(1,2);
        args1.print(1,2,3);

        //下面两个效果完全一样
        args1.print(new int[]{1,2,3});
        args1.print(1,2,3);
    }

    public void print(int ... nums){
        System.out.println("1111");
        for (int i = 0; i < nums.length; i++) {
            System.out.println(nums[i]);
        }
    }

    //这个和上面的一样的功能
    //public void print(int[] nums){
        //for (int i = 0; i < nums.length; i++) {
            //System.out.println(nums[i]);
        //}
    //}

    //这样可以是可以,但编译器可能不能区分这个和上面那个
    //public void print(int i,int ... nums){

    //}

    //编译不通过
    //public void print(int ... nums,int i){

    //}

    public void print(int i){
        System.out.println("2222");
    }

    public void print(int i, int j){
        System.out.println("3333");
    }

    /**
     * 场景举例:
     * String sql = "update customers set name = ?,email = ? where id = ?";
     *
     * String sql1 = "update custonmers set name = ? where id = ?";
     *
     * public void update(String sql,Object ... objs);
     *
     */
}

5.3 方法的参数传递机制:值传递(重点、难点)

> 如果形参是基本数据类型的变量,则将实参保存的数据值赋给形参。
> 如果形参是引用数据类型的变量,则将实参保存的地址值赋给形参。
基本语法的知识点

再谈方法之3:方法的值传递机制


1. (复习)对于方法内声明的局部变量来说:
    > 如果是基本数据类型的变量,则将此变量保存的数据值传递出去。
    > 如果是引用数据类型的变量,则将此变量保存的地址值传递出去。

2. 方法的参数的传递机制:

2.1 概念(复习)
形参:在定义方法时,方法名后面括号()中声明的变量称为形式参数,简称形参。
实参:在调用方法时,方法名后面括号()中的使用的值/变量/表达式称为实际参数,简称实参。

2.2 规则
    > 如果形参是基本数据类型的变量,则将实参保存的数据值赋给形参。
    > 如果形参是引用数据类型的变量,则将实参保存的地址值赋给形参。



3. 面试题:Java中的参数传递机制是什么?值传递(不是引用传递)

基本语法的代码1
package com.atguigu05.method_more._03valuetransfer;

/**
 * ClassName: ValueTransferTest
 * Package: com.atguigu05.method_more._03valuetransfer
 * Description: 值传递测试
 *
 * @Author 随心油条
 * @Create 2024/2/7 12:54
 * @Version 1.0
 */
public class ValueTransferTest {
    public static void main(String[] args) {
        //1. 基本数据类型的局部变量
        int m = 10;
        int n = m;

        System.out.println("m = " + m + ", n = " + n);//m = 10, n = 10

        m++;

        System.out.println("m = " + m + ", n = " + n);//m = 11, n = 10

        //2. 引用数据类型的局部变量
        //2.1 数组类型
        int[] arr1 = new int[]{1,2,3,4,5};
        int[] arr2 = arr1;//传递的是地址值

        arr2[0] = 10;

        System.out.println(arr1[0]);//10

        //2.2 对象类型
        Order order1 = new Order();
        order1.orderId = 1001;

        Order order2 = order1;//传递地址值
        order2.orderId = 1002;

        System.out.println(order1.orderId);//1002

    }

    static class Order{
        int orderId;
    }
}
基本语法的代码2
package com.atguigu05.method_more._03valuetransfer;

/**
 * ClassName: ValueTransferTest1
 * Package: com.atguigu05.method_more._03valuetransfer
 * Description: 形参与实参的值传递
 *
 * @Author 随心油条
 * @Create 2024/2/7 13:33
 * @Version 1.0
 */
public class ValueTransferTest1 {
    public static void main(String[] args) {
        ValueTransferTest1 test = new ValueTransferTest1();

        //1.基本数据类型的变量来说
        int m = 10;
        test.merhod1(m);
        System.out.println(m);//输出10,画存储图,就是main中的m值没变,merhod1方法中的m变为11,然后出栈了,main中的m还是10

        //2,对于引用数据类型的变量来说
        Person p = new Person();
        p.age = 10;
        test.merhod2(p);

        System.out.println(p.age);//这里是11,画内存解析,main方法中有个p,然后p.age的地址赋给p。进来method2方法,该方法的形参为类,为引用数据类型,该方法中p存的是地址,然后执行p.age++,就是地址里面的变为11,然后该方法出栈,地址没变,但是里面的值变为11,所以System.out.println(p.age)输出是11.

    }

    public void merhod1(int m){
        m++;
    }
    public void merhod2(Person p){
        p.age++;
    }

}
class Person{
    int age;
}
基本语法的代码3
package com.atguigu05.method_more._03valuetransfer;

/**
 * ClassName: ValueTransferTest2
 * Package: com.atguigu05.method_more._03valuetransfer
 * Description: 基本数据类型和方法关于形参和实参值传递
 *
 * @Author 随心油条
 * @Create 2024/2/7 14:05
 * @Version 1.0
 */
public class ValueTransferTest2 {

    public static void main(String[] args) {
        ValueTransferTest2 test = new ValueTransferTest2();

        int m = 10;
        int n = 20;

        System.out.println("m = " + m + ", n = " + n);
//        //操作1,交换m,n的值
//        int temp = m;
//        m = n;
//        n = temp;
//
//        System.out.println("m = " + m + ", n = " + n);//这里交换成功

        test.swap(m,n);//方法里面的m,n值是交换成功的
        System.out.println("m = " + m + ", n = " + n);//这里没有交换成功
    }

    public void swap(int m, int n){
        int temp = m;
        m = n;
        n = temp;
    }
}
基本语法的代码4
package com.atguigu05.method_more._03valuetransfer;

/**
 * ClassName: ValueTranferTest3
 * Package: com.atguigu05.method_more._03valuetransfer
 * Description: 引用数据类型和方法关于形参和实参值传递
 *
 * @Author 随心油条
 * @Create 2024/2/7 14:06
 * @Version 1.0
 */
public class ValueTranferTest3 {
    public static void main(String[] args) {
        ValueTranferTest3 test = new ValueTranferTest3();

        Data data = new Data();
        data.m = 10;
        data.n = 20;

        System.out.println("m = " + data.m + ", n = " + data.n);

//        //操作1:
//        int temp = data.m;
//        data.m = data.n;
//        data.n = temp;
//        System.out.println("m = " + data.m + ", n = " + data.n);//这里交换成功了

        //操作2:
        test.swap(data);
        System.out.println("m = " + data.m + ", n = " + data.n);//这里也交换成功了


    }
    public void swap(Data data){
        int temp = data.m;
        data.m = data.n;
        data.n = temp;
    }
}

class Data{
    int m;
    int n;
}
案例1

1. 定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积。

2. 定义一个类PassObject,在类中定义一个方法printAreas(),该方法的定义如下:
     public void printAreas(Circle c, int time)。

3. 在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。
    例如,time为5,则输出半径1,2,3,4,5,以及对应的圆面积。

4. 在main方法中调用printAreas()方法,调用完毕后输出当前半径值。程序运行结果如图所示。

显示效果

案例1的代码1
package com.atguigu05.method_more._03valuetransfer.exer1;

/**
 * ClassName: Circle
 * Package: com.atguigu05.method_more._03valuetransfer.exer1
 * Description: 定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积。
 *
 * @Author 随心油条
 * @Create 2024/2/7 15:14
 * @Version 1.0
 */
public class Circle {
    double radius;
    public double findArea(){
        return Math.PI * radius * radius;
    }
}
案例1的代码2
package com.atguigu05.method_more._03valuetransfer.exer1;

/**
 * ClassName: PassObject
 * Package: com.atguigu05.method_more._03valuetransfer.exer1
 * Description:
 *
 *      定义一个类PassObject,在类中定义一个方法printAreas(),该方法的定义如下:
 *      public void printAreas(Circle c, int time)。
 *
 *      在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。
 *     例如,time为5,则输出半径1,2,3,4,5,以及对应的圆面积。
 *
 *      在main方法中调用printAreas()方法,调用完毕后输出当前半径值。程序运行结果如图所示。
 *
 * @Author 随心油条
 * @Create 2024/2/7 15:15
 * @Version 1.0
 */
public class PassObject {

    public static void main(String[] args) {
        Circle test = new Circle();
        PassObject test1 = new PassObject();
        test1.printAreas(test,5);
        System.out.println("now radius is:" + test.radius);
    }

    public void printAreas(Circle c, int time){
        System.out.println("Radius" + "\t\t" + "Area");
        int i = 1;
        for ( ; i <= time; i++) {
            c.radius = i;
            System.out.println(c.radius + "\t\t\t" + c.findArea());
        }
        c.radius = i;
    }
}

案例2


针对atguigui04.example.exer4中MyArrays类的如下方法进行改进:
数组排序,可以指明排序的方式(从小到大、从大到小)
案例2的代码1
package com.atguigu05.method_more._03valuetransfer.exer2;

/**
 * ClassName: MyArrays
 * Package: com.atguigu04.example.exer4
 * Description:
 *
 * 根据上一章数组中的常用算法操作,自定义一个操作int[]的工具类。
 * 涉及到的方法有:求最大值、最小值、总和、平均数、遍历数组、复制数组、
 *              数组反转、数组排序(默认从小到大排序)、查找等
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:56
 * @Version 1.0
 */
public class MyArrays {

    /**
     * 获取int[]数组的最大值
     * @param arr 要获取最大值的数组
     * @return 数组的最大值
     */

    public int getMax(int[] arr){
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max){
                max = arr[i];
            }
        }
        return max;
    }

    /**
     * 获取int[]数组的最小值
     * @param arr 要获取最小值的数组
     * @return 数组的最小值
     */
    public int getMix(int[] arr){
        int mix = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] < mix){
                mix = arr[i];
            }
        }
        return mix;
    }

    /**
     * 获取int[]数组的总和
     * @param arr 要获取数组的总和
     * @return 数组的总和
     */
    public int getSum(int[] arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum;
    }

    /**
     * 获取int[]数组的平均值
     * @param arr 要获取数组的平均值
     * @return 数组的平均值
     */
    public int getAvg(int[] arr){
        return getSum(arr) / arr.length;
    }

    /**
     * 遍历int[]数组
     * @param arr 要遍历数组
     * @return 遍历数组
     */
    public void print(int[] arr){ {//[12,231,34]
        System.out.print("[");
        for (int i = 0; i < arr.length; i++)
            if (i == 0){
                System.out.print(arr[i]);
            }else {
                System.out.print("," + arr[i]);
            }

        System.out.println("]");
        }
    }

    /**
     * 复制int[]数组
     * @param arr 要复制数组
     * @return 复制数组
     */
    public int[] copy(int[] arr){
        int[] newArr = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            newArr[i] = arr[i];
        }
        return newArr;
    }

    /**
     * 反转int[]数组
     * @param arr 要反转数组
     * @return 反转数组
     */
    public int[] reverse(int[] arr){
        for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
            //交互arr[i]和arr[j]位置的元素
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        return arr;
    }

    /**
     * 针对数组进行排序操作
     * @param arr 待排序的数组
     * @return sortMethod  asc:升序  desc:降序
     */
    public int[] sort(int[] arr,String sortMethod){
        if("asc".equals(sortMethod)){//if(sortMethod.equals("asc")){//ascend:升序
            for (int j = 0; j < arr.length - 1; j++) {
                for (int i = 0; i < arr.length - 1 - j; i++) {
                    if (arr[i] > arr[i + 1]){

//                        //方式1:
//                        //交互arr[i] 和 arr[i + 1]
//                        int temp = arr[i];
//                        arr[i] = arr[i + 1];
//                        arr[i + 1] = temp;

                        //方式2:
                        //错误的
//                        swap(arr,arr[i],arr[i + 1]);//这里应该给索引,而不是数组该索引的值

                        //正确的
                        swap(arr,i,i + 1);
                    }
                }
            }
        }else if("desc".equals(sortMethod)){
            for (int j = 0; j < arr.length - 1; j++) {
                for (int i = 0; i < arr.length - 1 - j; i++) {
                    if (arr[i] < arr[i + 1]){

//                        //方式1:
//                        //交互arr[i] 和 arr[i + 1]
//                        int temp = arr[i];
//                        arr[i] = arr[i + 1];
//                        arr[i + 1] = temp;

                        //方式2:
                        //错误的
//                        swap(arr,arr[i],arr[i + 1]);//这里应该给索引,而不是数组该索引的值

                        //正确的
                        swap(arr,i,i + 1);
                    }
                }
            }
        }else{
            System.out.println("你输入的排序方式有误");
        }

        return arr;
    }



    /**
     * 对int[]数组进行从小到大排序
     * @param arr 要对int[]数组进行从小到大排序
     * @param target 要查找的元素
     * @return 排序数组
     */
    public int linearSearch(int[] arr, int target){
        for (int i = 0; i < arr.length; i++) {
            if (target == arr[i]){
                return i;
            }
        }

        //只要代码执行到此位置,一定是没找到
        return -1;
    }

    public void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}
案例2的代码2
package com.atguigu05.method_more._03valuetransfer.exer2;

/**
 * ClassName: MyArraysTest
 * Package: com.atguigu04.example.exer4
 * Description: 将排序分为升序排序和降序排序,用字符串的equals方法来实现,将交换元素封装成一个方法
 *
 * @Author 随心油条
 * @Create 2024/2/6 13:56
 * @Version 1.0
 */
public class MyArraysTest {
    public static void main(String[] args) {
        MyArrays arrs = new MyArrays();
        int[] arr = new int[]{34, 56, 223, 2, 56, 24, 56, 67, 778, 45};

        //求最大值
        System.out.println("最大值为 = " + arrs.getMax(arr));

        //求最小值
        System.out.println("最小值为 = " + arrs.getMix(arr));

        //平均值
        System.out.println("该数组的平均值为 = " + arrs.getAvg(arr));
        //遍历
        System.out.print("遍历数组的每个元素:" );
        arrs.print(arr);

        //查找
        int index = arrs.linearSearch(arr,12);
        if (index >= 0){
            System.out.println("找到了,位置为:" + index);
        }else {
            System.out.println("未找到");
        }

        //查找
        int index1 = arrs.linearSearch(arr,24);
        if (index1 >= 0){
            System.out.println("找到了,位置为:" + index1);
        }else {
            System.out.println("未找到");
        }

        //排序
        arrs.sort(arr,"asc");

        //遍历
        System.out.print("排序之后再遍历:" );
        arrs.print(arr);
    }
}
案例3

案例3的代码
package com.atguigu05.method_more._03valuetransfer.interview;

import java.io.PrintStream;

/**
 * ClassName: Answer
 * Package: com.atguigu05.method_more._03valuetransfer.interview
 * Description: 图片例题的解析
 *
 * @Author 随心油条
 * @Create 2024/2/7 16:12
 * @Version 1.0
 */
public class Answer {
    //错误做法
    public static void merhod0(int a,int b){
        a *= 10;
        b *= 10;
    }

    //正确做法一:
    public static void method1(int a, int b){
        //在不改变原题目的前提下,如何写这个函数才能在main函数中输出a = 100, b = 200?

        a *= 10;
        b *= 20;
        System.out.println(a);
        System.out.println(b);
        System.exit(0);

    }
    //正确做法二:
    public static void method2(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.setOut(ps);
    }
}

5.4 递归方法

  • 递归方法构成了隐式的循环
  • 对比:相较于循环结构,递归方法效率稍低,内存占用偏高。
基本语法的知识点

再谈方法之4:递归方法

1. 何为递归方法?方法自己调用自己的现象就称为递归。

2. 递归方法分类:直接递归、间接递归


3. 使用说明:

- 递归方法包含了一种'隐式的循环'。
- 递归方法会'重复执行'某段代码,但这种重复执行无须循环控制。
- 递归一定要向'已知方向'递归,否则这种递归就变成了无穷递归,停不下来,类似于'死循环'。最终发生'栈内存溢出'。

注意:
1. 递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环'慢得多'。
   所以在使用递归时要慎重。

2. 在要求高性能的情况下尽量避免使用递归,递归调用既花时间又'耗内存'。考虑使用循环迭代。
基本语法的代码
package com.atguigu05.method_more._04recursion;

/**
 * ClassName: RecursionTest
 * Package: com.atguigu05.method_more._04recursion
 * Description: 递归的练习
 *
 * @Author 随心油条
 * @Create 2024/2/7 17:34
 * @Version 1.0
 */
public class RecursionTest {
    public static void main(String[] args) {
        RecursionTest test = new RecursionTest();

//        test.method1();
        System.out.println(test.getSum(100));//输出5050
        System.out.println(test.getSum1(100));//输出5050
        System.out.println(test.getMul(5));//输出120
    }
    /**
     * 举例1: 计算1-100内自然数的总和
     */

    //方法1:使用循环
    public int getSum(int num){
        int sum = 0;
        for (int i = 0; i <= num; i++) {
            sum += i;
        }
        return sum;
    }

    //方法2:使用递归
    public int getSum1(int num){
        if (num == 1){
            return 1;
        }else {
            return getSum(num - 1) + num;
        }
    }

    /**
     * 举例2:计算n!
     */
    public int getMul(int n){
        if (1 == n){
            return 1;
        }else {
            return getMul(n-1) * n;
        }
    }

    /**
     * 举例3:快速排序
     * 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小
     * 则分别对这两部分继续进行排序,直到整个序列有序。
     */

    /**
     * 举例4:汉诺塔游戏
     */

    /**
     * 举例5:斐波那契数列
     * 1 1 2 3 5 8 13 21 34 55  ...
     *
     * f(n) = f(n - 1) + f(n - 2)
     */

    public int f(int n){
        if (n == 1){
            return 1;
        }else if(n == 2){
            return 1;
        }else {
            return f(n - 1) + f(n - 2);
        }
    }

    /**
     * 举例6:
     * File类的对象表示一个文件目录。
     * 计算指定的文件目录的大小,遍历指定的文件目录中的所有的文件,删除指定的文件目录。
     */


    /**
     * 如下递归方法的调用,会导致StackOverflowError
     */
//    public void method1(){
//        System.out.println("method1 ...");
//        method1();
//    }
}
案例1


练习1:
已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),
其中n是大于0的整数,求f(10)的值。


练习2:
已知有一个数列:f(0) = 1,f(1) = 4,
f(n+2)=2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值。

案例1的代码
package com.atguigu05.method_more._04recursion.exer1;

/**
 * ClassName: RecusionExer01
 * Package: com.atguigu05.method_more._04recursion.exer1
 * Description:
 *
 * 练习1:
 * 已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),
 * 其中n是大于0的整数,求f(10)的值。
 *
 *
 * 练习2:
 * 已知有一个数列:f(0) = 1,f(1) = 4,
 * f(n+2)=2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值。
 *
 * @Author 随心油条
 * @Create 2024/2/7 18:33
 * @Version 1.0
 */
public class RecusionExer01 {

    //练习1
    public int f(int n){
        if(n == 20){
            return 1;
        }else if (n == 21){
            return 4;
        }else {
            //正确的,往着有目的的方向进行
            return f(n + 2) - 2 * f(n + 1);
        }
    }

    //练习2
    public int f1(int n){
        if(0 == n){
            return 1;
        }else if (1 == n){
            return 4;
        }else {
            //正确的,往着有目的的方向进行
            return 2 * f(n - 1) + f(n - 2);
        }
    }
}
案例2

案例:不死神兔
用递归实现不死神兔:故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契(Fibonacci)。
在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔,
再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,没有发生死亡,
问:现有一对刚出生的兔子2年后(24个月)会有多少对兔子?


拓展:走台阶问题
假如有10阶楼梯,小朋友每次只能向上走1阶或者2阶,请问一共有多少种不同的走法呢?




【奇妙的属性】随着数列的增加,斐波那契数列前一个数与后一个数的比值越来越逼近黄金分割的数值0.618。

图片显示

案例2的代码
package com.atguigu05.method_more._04recursion.exer2;

/**
 * ClassName: RabbitExer
 * Package: com.atguigu05.method_more._04recursion.exer2
 * Description: 不死神兔
 *
 * @Author 随心油条
 * @Create 2024/2/7 18:34
 * @Version 1.0
 */
public class RabbitExer {
    public static void main(String[] args) {
        RabbitExer test = new RabbitExer();
        System.out.println("两年后兔子的对数为: " + test.getRabbitNumber(24));

    }

    public int getRabbitNumber(int month){
        if (month == 1){
            return 1;
        }else if (month == 2){
            return 1;
        }else {
        return getRabbitNumber(month - 1) + getRabbitNumber(month - 2);
        }
    }
}

6. 对象数组

  • String[] ;Person[] ; Customer[]
案例1


对象数组

1. 何为对象数组?如何理解?

数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用类型中的类时,我们称为对象数组。

2. 举例:
String[],Person[],Student[],Customer[]等

3. 案例:
1)定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
2)创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
年级[1,6] : (int)(Math.random() * 6 + 1)
分数[0,100] : (int)(Math.random() * 101)


4. 内存解析:


5. 拓展:提供封装Student相关操作的工具类


案例1的代码1
package com.atguigu04.example.exer5_objarr;

/**
 * ClassName: Student
 * Package: com.atguigu04.example.exer5_objarr
 * Description: 定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)
 *
 * @Author 随心油条
 * @Create 2024/2/6 21:33
 * @Version 1.0
 */
public class Student {
    //属性
    int number;
    int state;
    int score;

    //定义一个显示方法
    public String show(){
        return "number = " + number + ",state = " +
                state + ",score = " + score;
    }
}
案例1的代码2
package com.atguigu04.example.exer5_objarr;

/**
 * ClassName: StudentTest
 * Package: com.atguigu04.example.exer5_objarr
 * Description:
 *
 * 1)定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
 * 2)创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
 * 问题一:打印出3年级(state值为3)的学生信息。
 * 问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
 * 提示:
 * 1) 生成随机数:Math.random(),返回值类型double;
 * 2) 四舍五入取整:Math.round(double d),返回值类型long。
 * 年级[1,6] : (int)(Math.random() * 6 + 1)
 * 分数[0,100] : (int)(Math.random() * 101)
 *
 * @Author 随心油条
 * @Create 2024/2/6 21:33
 * @Version 1.0
 */
public class StudentTest {
    public static void main(String[] args) {

        //创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
        Student[] students = new Student[20];

        //使用循环,给数组的元素赋值
        for (int i = 0; i < students.length; i++) {
            //创造二十个对象
            //Student stu1 = new Student();//错误的,没有将循环利用起来
            students[i] = new Student();

            //给每一个学生对象的number、state、score属性赋值。年级和成绩都是由随机数确定的
            students[i].number = i + 1;
            students[i].state = (int)(Math.random() *  6 + 1);
            students[i].score = (int) (Math.random() * 101);

            }
        for (int i = 0; i < students.length; i++) {
            if (3 == students[i].state){
                System.out.println(students[i].show());
            }
        }
        System.out.println("******************************");


        //排序前遍历
            for (int j = 0; j < students.length; j++) {
                System.out.println(students[j].show());
            }

            System.out.println("******************************");

            //使用冒泡排序按学生成绩排序,并遍历所有学生信息
            for (int j = 0; j < students.length - 1; j++) {
                for (int k = 0; k < students.length - 1 - j; k++) {
                    if (students[k + 1].score < students[k].score){
                        //这是错的,这是可以理解为二维数组,相当于人不变,分数变了
                        //int temp = stu[k + 1].score;
                        //stu[k + 1].score = stu[k].score;
                        //stu[k].score = temp;

                        //应该将人和分数一起换
                        Student temp = students[k];
                        students[k] = students[k + 1];
                        students[k + 1] = temp;
                    }
                }
            }

            //排序后遍历
            for (int j = 0; j < students.length; j++) {
                System.out.println(students[j].show());
            }
        }



    }

7. package、import关键字的使用

  • package:指明声明的类所属的包。
  • import:当前类中,如果使用其它包下的类(除java.lang包),原则上就需要导入。
基本语法的知识点

一、package关键字的使用

1. 说明
- package:包
- package用于指明该文件中定义的类、接口等结构所在的包
- 一个源文件只能有一个声明包的package语句
- package语句作为Java源文件的第一条语句出现。若缺省该语句,则指定为无名包。
- 包名,属于标识符,满足标识符命名的规则和规范(全部小写)、见名知意
  - 包通常使用所在公司域名的倒置:com.atguigu.xxx。
  - 大家取包名时不要使用"`java.xx`"包
- 包对应于文件系统的目录,package语句中用 “.” 来指明包(目录)的层次,每.一次就表示一层文件目录。
- 同一个包下可以声明多个结构(类、接口),但是不能定义同名的结构(类、接口)。不同的包下可以定义同名的结构(类、接口)

2. 包的作用
- 包可以包含类和子包,划分`项目层次`,便于管理
- 帮助`管理大型软件`系统:将功能相近的类划分到同一个包中。比如:MVC的设计模式
- 解决`类命名冲突`的问题
- 控制`访问权限`

3. JDK中主要的包
`java.lang`----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
`java.net`----包含执行与网络相关的操作的类和接口。
`java.io`   ----包含能提供多种输入/输出功能的类。
`java.util`----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
`java.text`----包含了一些java格式化相关的类
`java.sql`----包含了java进行JDBC数据库编程的相关类/接口
`java.awt`----包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。

二、import关键字的使用
- import : 导入
- import语句来显式引入指定包下所需要的类。相当于`import语句告诉编译器到哪里去寻找这个类`。
- import语句,声明在包的声明和类的声明之间。
- 如果需要导入多个类或接口,那么就并列显式多个import语句即可
- 如果使用`a.*`导入结构,表示可以导入a包下的所有的结构。举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。
- 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
- 如果已经导入java.a包下的类,那么如果需要使用a包的子包下的类的话,仍然需要导入。
- 如果在代码中使用不同包下的同名的类,那么就需要使用类的全类名的方式指明调用的是哪个类。
- (了解)`import static`组合的使用:调用指定类或接口下的静态的属性或方法
基本语法的代码1
package com.atguigu06.package_import;

import com.atguigu05.method_more._04recursion.RecursionTest;
import com.atguigu05.method_more._04recursion.exer2.RabbitExer;

import java.lang.reflect.Field;
import java.util.*;

import static java.lang.System.out;
import static java.lang.Math.PI;

/**
 * ClassName: Person
 * Package: com.atguigu06.package_import
 * Description: 测试导入包
 *
 * @Author 随心油条
 * @Create 2024/2/7 22:31
 * @Version 1.0
 */
public class Person {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        ArrayList list = new ArrayList();

        HashMap map = new HashMap();

        HashSet set = new HashSet();

        String str = "hello";

        System.out.println(str);

        Person p = new Person();

        Field field = null;

        RecursionTest test = null;

        RabbitExer exer = null;

        //Date 可以使用import的方式指明
        Date date = new Date();

        //使用全类名的方式
        java.sql.Date date1 = new java.sql.Date(121231231l);

        out.println(PI);
    }
}
基本语法的代码2
package com.atguigu06.package_import;

import com.atguigu05.method_more._04recursion.RecursionTest;
import com.atguigu05.method_more._04recursion.exer2.RabbitExer;

import java.lang.reflect.Field;
import java.util.*;

import static java.lang.Math.PI;
import static java.lang.System.out;

/**
 * ClassName: PackageImportTest
 * Package: com.atguigu06.package_import
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/7 22:31
 * @Version 1.0
 */
public class PackageImportTest {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        ArrayList list = new ArrayList();

        HashMap map = new HashMap();

        HashSet set = new HashSet();

        String str = "hello";
        out.println(str);

        Person p = new Person();

        Field field = null;

        RecursionTest test = null;

        RabbitExer exer = null;

        //Date可以使用import的方式指明
        Date date = new Date();

        //使用全类名的方式
        java.sql.Date date1 = new java.sql.Date(121231231L);

        out.println("Hello");

        out.println(PI);
    }
}

8. oop的特征之一:封装性

Java规定了4种权限修饰,分别是:private、缺省、protected、public。
我们可以使用4种权限修饰来修饰类及类的内部成员。当这些成员被调用时,体现可见性的大小。

举例:

> 场景1:私有化(private)类的属性,提供公共(public)的get和set方法,对此属性进行获取或修改
> 场景2:将类中不需要对外暴露的方法,设置为private
> 场景3:单例模式中构造器private的了,避免在类的外部创建实例。(放到static关键字后讲)

上理论:程序设计的原则之一

理论上:
  -`高内聚`:类的内部数据操作细节自己完成,不允许外部干涉;
    (Java程序通常以类的形态呈现,相关的功能封装到方法中。)
  -`低耦合`:仅暴露少量的方法给外部使用,尽量方便外部调用。
    (给相关的类、方法设置权限,把该隐藏的隐藏起来,该暴露的暴露出去)
基本语法的知识点

面向对象特征之一:封装性

1. 为什么需要封装性?
理论上:
  - `高内聚`:类的内部数据操作细节自己完成,不允许外部干涉;
  - `低耦合`:仅暴露少量的方法给外部使用,尽量方便外部调用。

通俗的说:把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。


2. 如何实现数据封装?

2.1 权限修饰符
    Java规定了4种权限修饰,分别是:private、缺省、protected、public

2.2 作用
    我们可以使用4种权限修饰来修饰类及类的内部成员。当这些成员被调用时,体现可见性的大小。

2.3 实际案例:
在题目中,我们给Animal的对象的legs属性赋值。在实际的常识中,我们知道legs不能赋值为负数的。但是如果
直接调用属性legs,是不能加入判断逻辑的。那怎么办呢?
> 将legs属性私有化(private),禁止在Animal类的外部直接调用此属性
> 提供给legs属性赋值的setLegs()方法,在此方法中加入legs赋值的判断逻辑if(legs >= 0 && legs % 2 ==0)
  将此方法暴露出去,使得在Animal类的外部调用此方法,对legs属性赋值。
> 提供给legs属性获取的getLegs()方法,此方法对外暴露。使得在Animal类的外部还可以调用此属性的值。


2.4 4种权限具体使用
《见课件》

> 类:只能使用public、缺省修饰
> 类的内部成员:可以使用4种权限修饰进行修饰。

2.5 开发中4种权限使用频率的情况:
   比较高:public、private
   比较低:缺省、protected

3. 封装性的体现

> 场景1:私有化(private)类的属性,提供公共(public)的get和set方法,对此属性进行获取或修改
> 场景2:将类中不需要对外暴露的方法,设置为private.
> 场景3:单例模式中构造器private的了,避免在类的外部创建实例。(放到static关键字后讲)



基本语法的代码
package com.atguigu07.encapsulation;

/**
 * ClassName: AnimalTest
 * Package: com.atguigu07.encapsulation
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 14:45
 * @Version 1.0
 */
public class AnimalTest {
    public static void main(String[] args) {
        Animal animal1 = new Animal();

        animal1.name = "金蟾";

        //因为legs声明为private,是私有的,出了Animal类之外就不能调用了。
        //animal1.legs = 4;
        //animal1.legs = -4;

        //只能通过setlegs(),间接的对legs属性进行赋值。
        animal1.setLegs(2);
        animal1.setLegs(-2);

        System.out.println("name = " + animal1.name + ",legs = " + animal1.getLegs());
        animal1.eat();
    }
}

class Animal{ // 动物
    //属性
    String name; //名字
    private int legs; //腿的个数

    //方法
    //设置legs的属性值
    public void setLegs(int l){
        if (l >= 0 && l % 2 == 0){
            legs = l;
        }else{
            System.out.println("你输入的数据非法");
        }

    }

    //获取legs的属性值
    public int getLegs(){
        return legs;
    }

    public void eat(){
        System.out.println("动物觅食");
    }
}

//private class AA{}
案例1

案例:
创建程序,在其中定义两个类:Person和PersonTest类。定义如下:

用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。

在PersonTest类中实例化Person类的对象b,调用setAge()和getAge()方法,体会Java的封装性。
案例1的代码1
package com.atguigu07.encapsulation.exer1;

/**
 * ClassName: Person
 * Package: com.atguigu07.encapsulation.exer1
 * Description:
 *
 * 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。
 *
 * 在PersonTest类中实例化Person类的对象b,调用setAge()和getAge()方法,体会Java的封装性。
 *
 * @Author 随心油条
 * @Create 2024/2/17 15:41
 * @Version 1.0
 */
public class Person {
    private int age;

    //方法
    //设置人的合法年龄(0-130)setAge()
    public void setAge(int a){
        if (a >= 0 && a <= 130){
            age = a;
        }else {
            System.out.println("您的输入非法");
        }
    }

    //用getAge()返回人的年龄
    public int getAge(){
        return age;
    }

    //错误的,增加耦合
    public int doAge(int a){
        if (a >= 0 && a <= 130){
            age = a;
            return a;
        }else {
            System.out.println("您的输入有误");
            return -1;
        }
    }
}
案例1的代码2
package com.atguigu07.encapsulation.exer1;

/**
 * ClassName: PersonTest
 * Package: com.atguigu07.encapsulation.exer1
 * Description:
 *
 * 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。
 *
 * 在PersonTest类中实例化Person类的对象b,调用setAge()和getAge()方法,体会Java的封装性。
 *
 * @Author 随心油条
 * @Create 2024/2/17 15:41
 * @Version 1.0
 */
public class PersonTest {
    public static void main(String[] args) {
        //创建Person实例1
        Person p = new Person();
        //p.age = 10; 编译不通过
        //System.out.println(p.age);

        //换种方式
        p.setAge(24);
        System.out.println(p.getAge());
    }
}
案例2


案例:自定义图书类

设定属性包括:
书名bookName,
作者author,
价格price;

方法包括:
相应属性的get/set方法,
图书信息介绍等。
案例2的代码1
package com.atguigu07.encapsulation.exer2;

/**
 * ClassName: Book
 * Package: com.atguigu07.encapsulation.exer2
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 15:57
 * @Version 1.0
 */
public class Book {

    //属性
    private String bookName;//书名
    private String author;//作者
    private double price;//价格

    //方法
    public String getBookName(){
        return bookName;
    }

    public void setBookName(String bn){
        bookName = bn;
    }

    public String getAuthor(){
        return bookName;
    }

    public void setAuthor(String a){
        author = a;
    }

    public double getPrice(){
        return price;
    }

    public void setPrice(double p){
        price = p;
    }

    //获取读书信息
    public String showInfo(){
        return "bookname : " + bookName + ", author :" + author +
                ", price :" + price;
    }
}
案例2的代码2
package com.atguigu07.encapsulation.exer2;

/**
 * ClassName: BookTest
 * Package: com.atguigu07.encapsulation.exer2
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 15:57
 * @Version 1.0
 */
public class BookTest {
    public static void main(String[] args) {

        Book book1 = new Book();

        book1.setBookName("剑指Java");
        book1.setAuthor("尚硅谷教育");
        book1.setPrice(180);

        System.out.println(book1.showInfo());
    }
}
案例3


案例:普通员工类

(1)声明员工类Employee,

- 包含属性:姓名、性别、年龄、电话,属性私有化

- 提供get/set方法

- 提供String getInfo()方法


(2)在测试类的main中创建员工数组,并从键盘输入员工对象信息,最后遍历输出

添加员工图示

员工列表图示

案例3的代码1
package com.atguigu07.encapsulation.exer3;

/**
 * ClassName: Employee
 * Package: com.atguigu07.encapsulation.exer3
 * Description:
 *
 * (1)声明员工类Employee,
 *
 * - 包含属性:姓名、性别、年龄、电话,属性私有化
 *
 * - 提供get/set方法
 *
 * - 提供String getInfo()方法
 *
 * @Author 随心油条
 * @Create 2024/2/17 16:30
 * @Version 1.0
 */
public class Employee {

    //属性
    private String name;
    private char gender;
    private int age;
    private String phoneNumber;

    //方法
    public String getName(){
        return name;
    }
    public void setName(String n){
        name = n;
    }

    public char getGender(){
        return gender;
    }
    public void setGender(char g){
        gender = g;
    }

    public int getAge(){
        return age;
    }
    public void setAge(int a){
        age = a;
    }

    public String getPhoneNumber(){
        return phoneNumber;
    }
    public void setPhoneNumber(String p){
        phoneNumber = p;
    }

    public String showInfo(){
        return name + "\t" + gender + "\t" + age + "\t" + phoneNumber;
    }

}
案例3的代码2
package com.atguigu07.encapsulation.exer3;

import java.util.Scanner;

/**
 * ClassName: EmployeeTest
 * Package: com.atguigu07.encapsulation.exer3
 * Description:
 *
 * (2)在测试类的main中创建员工数组,并从键盘输入员工对象信息,最后遍历输出
 *
 * @Author 随心油条
 * @Create 2024/2/17 16:31
 * @Version 1.0
 */
public class EmployeeTest {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        //创建Employee[]
        Employee[] emps = new Employee[2];
        for (int i = 0; i < emps.length; i++) {

            emps[i] = new Employee();
            System.out.println("----------添加第 " + (i + 1) + "个员工----------");
            System.out.print("姓名:");
            String name = input.next();
            System.out.print("性别:");
            char gender = input.next().charAt(0);
            System.out.print("年龄:");
            int age = input.nextInt();
            System.out.print("电话:");
            String phoneNumer = input.next();

            //给指定的employee对象的各属性赋值
            emps[i].setName(name);
            emps[i].setGender(gender);
            emps[i].setAge(age);
            emps[i].setPhoneNumber(phoneNumer);
        }

        System.out.println("----------员工列表----------");
        System.out.println("编号\t姓名\t性别\t年龄\t电话");
        for (int i = 0; i < emps.length; i++) {
            System.out.println(i+1 + "\t" + emps[i].showInfo());
        }
        System.out.println("----------员工列表完成----------");

    }
}
案例4

使用 com.atguigu07.encapsulation.exer4.test1 和 com.atguigu07.encapsulation.exer4.test2两个包
来测试几种常见的权限修饰符。
案例4的代码1
package com.atguigu07.encapsulation.exer4.test1;

/**
 * ClassName: Order
 * Package: com.atguigu07.encapsulation.exer4.test1
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 17:08
 * @Version 1.0
 */
public class Order {

    //属性
    private int orderPrivate;
    int orderDefault;
    public int orderPublic;

    //方法
    private void methodPrivate(){

    }

    void methodDefault(){

    }

    public void methodPublic(){

    }

    public void test(){

        //同一个类中调用属性
        orderPrivate = 1;
        orderDefault = 2;
        orderPublic = 3;

        //同一个类中调用方法
        methodPrivate();
        methodDefault();
        methodPublic();
    }
}
案例4的代码2
package com.atguigu07.encapsulation.exer4.test1;

/**
 * ClassName: OrderTest
 * Package: com.atguigu07.encapsulation.exer4.test1
 * Description:
 *
 * 来测试几种常见的权限修饰符。
 *
 * @Author 随心油条
 * @Create 2024/2/17 17:09
 * @Version 1.0
 */
public class OrderTest {
    public static void main(String[] args) {
        Order order = new Order();
        order.orderPublic = 1;
        order.orderDefault = 2;

        //不能运行
        //order.orderPrivate = 3;//因为是 private 访问控制

        order.methodPublic();
        order.methodDefault();

        //不能运行
        //order.methodPrivate();//因为是 private 访问控制
    }
}
案例4的代码3
package com.atguigu07.encapsulation.exer4.test2;

import com.atguigu07.encapsulation.exer4.test1.Order;

/**
 * ClassName: OrderTest
 * Package: com.atguigu07.encapsulation.exer4.test2
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 17:16
 * @Version 1.0
 */
public class OrderTest {
    public static void main(String[] args) {
        Order order = new Order();

        //调用属性
        order.orderPublic = 1;

        //不能运行
        //order.orderPrivate = 3;//是 private 访问控制
        //order.orderDefault = 2;//不是公共的

        //调用方法
        order.methodPublic();
        //不能运行
        //order.methodPrivate();//是 private 访问控制
        //order.methodDefault();//不是公共的
    }
}

9. 类的成员之三:构造器

  • 如何定义:权限修饰符 类名(形参列表){}
  • 构造器的作用:① 搭配上new,用来创建对象 ② 初始化对象的成员变量
基本语法的知识点

类的成员之三:构造器(constructor),构造方法(与方法无关)

1. 构造器的理解
constructor :n. 建设者、建造者
construct:v. 建设、建造、创造
construction: n. 建设、建造   CCB

2. 构造器的作用
作用1:搭配new关键字,创建类的对象
作用2:在创建对象的同时,可以给对象的相关属性赋值

3. 构造器的使用说明
> 构造器声明的格式:权限修饰符 类名(形参列表){}
> 创建类以后,在没有显示提供任何构造器的情况下,系统会默认提供一个空参的构造器,且构造器的权限
  与类声明的权限相同。
> 一旦类中显示声明了构造器,则系统不再提供默认的空参的构造器。
> 一个类中可以声明多个构造器,彼此之间构成重载。
基本语法的代码1
package com.atguigu08.constructor;

/**
 * ClassName: Person
 * Package: com.atguigu08.constructor
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 17:41
 * @Version 1.0
 */
public class Person {
    //属性
    String name;
    int age;

    //构造器

    public Person(){//默认构造器
        System.out.println("Person()...");
    }

    //声明其他构造器
    public Person(int a){
        age = a;
    }

    public Person(String n){
        name = n;
    }

    public Person(String n, int a){
        name = n;
        age = a;
    }

    //方法

    public void eat(){
        System.out.println("人吃饭");
    }

    public void sleep(int hours){
        System.out.println("每个人需要" + hours + "睡眠");
    }
}
基本语法的代码2
package com.atguigu08.constructor;

import java.util.Scanner;

/**
 * ClassName: PersonTest
 * Package: com.atguigu08.constructor
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 17:41
 * @Version 1.0
 */
public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person();//默认构造器

        p1.eat();

        Person p2 = new Person(1);
        System.out.println(p2.age);

        Scanner input = new Scanner(System.in);
    }
}
案例1

案例:
(1)定义Student类,有4个属性:
  String name;
  int age;
  String school;
  String major;

(2)定义Student类的3个构造器:

- 第一个构造器Student(String n, int a)设置类的name和age属性;
- 第二个构造器Student(String n, int a, String s)设置类的name, age 和school属性;
- 第三个构造器Student(String n, int a, String s, String m)设置类的name, age ,school和major属性;

(3)在main方法中分别调用不同的构造器创建的对象,并输出其属性值。
案例1的代码1
package com.atguigu08.constructor.exer1;

/**
 * ClassName: Student
 * Package: com.atguigu08.constructor.exer1
 * Description:
 *
 * (1)定义Student类,有4个属性:
 *   String name;
 *   int age;
 *   String school;
 *   String major;
 *
 * (2)定义Student类的3个构造器:
 *
 * - 第一个构造器Student(String n, int a)设置类的name和age属性;
 * - 第二个构造器Student(String n, int a, String s)设置类的name, age 和school属性;
 * - 第三个构造器Student(String n, int a, String s, String m)设置类的name, age ,school和major属性;
 *
 * @Author 随心油条
 * @Create 2024/2/17 17:55
 * @Version 1.0
 */
public class Student {

    //属性
    String name;
    int age;
    String school;
    String major;

    //定义Student类的3个构造器:
    public Student(String n, int a){
        name = n;
        age = a;
    }

    public Student(String n, int a, String s){
        name = n;
        age = a;
        school = s;
    }

    public Student(String n, int a, String s, String m){
        name = n;
        age = a;
        school = s;
        major = m;
    }

    public String showStudent(){
        return "name = " + name + ",age = " + age + ",school = " +
                school + ",major = " + major;
    }
}
案例1的代码2
package com.atguigu08.constructor.exer1;

/**
 * ClassName: StudentTest
 * Package: com.atguigu08.constructor.exer1
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/17 17:55
 * @Version 1.0
 */
public class StudentTest {
    public static void main(String[] args) {

        Student stu = new Student("刘强东",48,"中国人民大学","社会学");
        System.out.println(stu.showStudent());

        Student stu1 =new Student("奶茶妹妹",28,"清华大学");
        System.out.println(stu1.showStudent());
    }
}
案例2


案例:
编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,
同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
案例2的代码1
package com.atguigu08.constructor.exer2;

/**
 * ClassName: TriAngle
 * Package: com.atguigu08.constructor.exer2
 * Description:
 *
 * 声明私有的底边长base和高height,
 *
 * @Author 随心油条
 * @Create 2024/2/17 18:09
 * @Version 1.0
 */
public class TriAngle {
    private double base;//底边长
    private double height;//高

    public double getBase(){
        return base;
    }
    public void setBase(double b){
        base = b;
    }

    public double getHeight(){
        return height;
    }
    public void setHeight(double h){
        height = h;
    }
    public TriAngle(){

    }
    public TriAngle(double b, double h){
        base = b;
        height = h;
    }
    //...

    //求面积的方法
    public double findArea(){
        return height * base /2;
    }
}
案例2的代码2
package com.atguigu08.constructor.exer2;

/**
 * ClassName: TriAngleTest
 * Package: com.atguigu08.constructor.exer2
 * Description:
 *
 * 同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
 *
 * @Author 随心油条
 * @Create 2024/2/17 18:09
 * @Version 1.0
 */
public class TriAngleTest {
    public static void main(String[] args) {

        //创建TriAngle的实例1
        TriAngle tri = new TriAngle();

        tri.setBase(2.3);
        tri.setHeight(3.4);

        System.out.println("面积为:" + tri.findArea());

        //创建TriAngle的实例2
        TriAngle tri1 = new TriAngle(2.3,3.4);
        System.out.println("底边长 : " + tri.getBase());
        System.out.println("高为: " + tri1.getHeight());
        System.out.println("面积为:" + tri1.findArea());
    }
}
案例3

案例:

1、写一个名为Account的类模拟账户。该类的属性和方法如下图所示。
该类包括的属性:账号id,余额balance,年利率annualInterestRate;
包含的构造器:自定义
包含的方法:访问器方法(getter和setter方法),取款方法withdraw(),存款方法deposit()。

提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。


2、创建Customer类。
a. 声明三个私有对象属性:firstName、lastName和account。
b. 声明一个公有构造器,这个构造器带有两个代表对象属性的参数(f和l)
c. 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。
d. 声明setAccount 方法来对account属性赋值。
e. 声明getAccount 方法以获取account属性。

3、写一个测试程序。

(1)创建一个Customer ,名字叫 Jane Smith, 他有一个账号为1000,余额为2000元,年利率为 1.23% 的账户。
(2)对Jane Smith操作。
存入 100 元,再取出960元。再取出2000元。
打印出Jane Smith 的基本信息:

成功存入 :100.0
成功取出:960.0
余额不足,取款失败
Customer [Smith, Jane] has a account: id is 1000, annualInterestRate is 1.23%, balance is 1140.0


案例3的代码1
package com.atguigu08.constructor.exer3;

/**
 * ClassName: Account
 * Package: com.atguigu08.constructor.exer3
 * Description:
 *
 * 1、写一个名为Account的类模拟账户。该类的属性和方法如下图所示。
 * 该类包括的属性:账号id,余额balance,年利率annualInterestRate;
 * 包含的构造器:自定义
 * 包含的方法:访问器方法(getter和setter方法),取款方法withdraw(),存款方法deposit()。
 *
 * 提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。
 *
 * @Author 随心油条
 * @Create 2024/2/17 23:09
 * @Version 1.0
 */
public class Account {
    private int id;//账号
    private double balance;//余额
    private double annuallnterestRate;//年利率

    public Account(int i, double b, double a){
        id = i;
        balance = b;
        annuallnterestRate = a;
    }

    public int getId(){
        return id;
    }
    public void setId(int i){
        id = i;
    }

    public double getBalance(){
        return balance;
    }
    public void setBalance(double b){
        balance = b;
    }

    public double getAnnuallnterestRate(){
        return annuallnterestRate;
    }
    public void setAnnuallnterestRate(double b){
        balance = b;
    }

    //取款
    public void withdraw(double amount) {//取钱
        if (amount >= 0 && balance >= amount){
            balance -= amount;
            System.out.println("成功取出:" + amount);
        }else {
            System.out.println("余额不足,取款失败");
        }
    }

    //存款
    public void deposit(double amount){//存钱
        if (amount >= 0){
            balance += amount;
            System.out.println("成功存入:" + amount);
        }else {
            System.out.println("您输入的金额有误");
        }
    }
}

图片显示

案例3的代码2
package com.atguigu08.constructor.exer3;

/**
 * ClassName: Customer
 * Package: com.atguigu08.constructor.exer3
 * Description:
 *
 * 2、创建Customer类。
 * a. 声明三个私有对象属性:firstName、lastName和account。
 * b. 声明一个公有构造器,这个构造器带有两个代表对象属性的参数(f和l)
 * c. 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。
 * d. 声明setAccount 方法来对account属性赋值。
 * e. 声明getAccount 方法以获取account属性。
 *
 * @Author 随心油条
 * @Create 2024/2/17 23:10
 * @Version 1.0
 */
public class Customer {
    private String firstName;
    private String lastName;
    private Account account;

    public Customer (String f, String l){
        firstName = f;
        lastName = l;
    }

    public String getFirstName(){
        return firstName;
    }
    public void setFirstName(String fn){
        firstName = fn;
    }

    public String getLastName(){
        return lastName;
    }
    public void setLastName(String ln){
        lastName = ln;
    }

    public Account getAccount(){
        return account;
    }
    public void setAccount(Account a){
        account = a;
    }
}

图片显示

案例3的代码3
package com.atguigu08.constructor.exer3;

/**
 * ClassName: CustomerTest
 * Package: com.atguigu08.constructor.exer3
 * Description:
 *
 * (1)创建一个Customer ,名字叫 Jane Smith, 他有一个账号为1000,余额为2000元,年利率为 1.23% 的账户。
 * (2)对Jane Smith操作。
 * 存入 100 元,再取出960元。再取出2000元。
 * 打印出Jane Smith 的基本信息:
 *
 * 成功存入 :100.0
 * 成功取出:960.0
 * 余额不足,取款失败
 * Customer [Smith, Jane] has a account: id is 1000, annualInterestRate is 1.23%, balance is 1140.0
 *
 * @Author 随心油条
 * @Create 2024/2/17 23:10
 * @Version 1.0
 */
public class CustomerTest {
    public static void main(String[] args) {

        //创建Customer实例
        Customer customer = new Customer("Jane","Smith");

        //方法1:
        //Account account = new Account(1000,2000,0.0123);
        //customer.setAccount(account);
        //方法2:
        customer.setAccount(new Account(1000,2000,0.0123));

        //针对于客户的账号进行存钱、取钱相关操作
        customer.getAccount().deposit(100);
        customer.getAccount().withdraw(960);
        customer.getAccount().withdraw(2000);

        //输出客户信息
        System.out.println("Customer [" + customer.getFirstName() + "," + customer.getLastName()
                + "] has a account: id is " + customer.getAccount().getId() +
                ", annualInterestRate is " + customer.getAccount().getAnnuallnterestRate() * 100
                + "%, balance is " + customer.getAccount().getBalance());
        /**
         * 关于匿名对象
         *
         * 1.匿名对象往往只能被调用一次
         * 2.匿名对象常常作为实参传递给方法的形参。
         */

        new Account(1001,2000,0.0123).withdraw(1000);
        System.out.println(new Account(1001, 2000, 0.0123).getBalance());

        int num = 10;
    }

}

10. 三个小知识

10.1 类的实例变量的赋值过程(重要)

1. 在类的属性中,可以有哪些位置给属性赋值?
① 默认初始化;
② 显式初始化;
③ 构造器中初始化;
**********************************
④ 通过"对象.方法"的方式赋值;
⑤ 通过"对象.属性"的方式赋值;

2. 这些位置执行的先后顺序是怎样?
① - ② - ③ - ④/⑤

3. 以上操作在对象创建过程中可以执行的次数如何?
> 只能执行一次:①、②、③
> 可以多次执行:④、⑤

10.2 JavaBean

所谓JavaBean,是指符合如下标准的Java类:

- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法

10.3 UML类图

熟悉。

基本语法的代码1
package com.atguigu09.bean_uml;

/**
 * ClassName: Customer
 * Package: com.atguigu09.bean_uml
 * Description:
 *
 * @Author 随心油条
 * @Create 2024/2/18 9:56
 * @Version 1.0
 */
public class Customer {
    public Customer(){

    }

    private int id;
    private String name;

    public void setId(int i){
        id = i;
    }
    public int getId(){
        return id;
    }

    public void setName(String n){
        name = n;
    }
    public String getName(){
        return name;
    }
}
基本语法的代码2
package com.atguigu09.bean_uml;

/**
 * ClassName: UserTest
 * Package: com.atguigu09.bean_uml
 * Description:
 *
 * ① 默认初始化;
 * ② 显式初始化;
 * ③ 构造器中初始化;
 * **********************************
 * ④ 通过"对象.方法"的方式赋值;
 * ⑤ 通过"对象.属性"的方式赋值;
 *
 * @Author 随心油条
 * @Create 2024/2/18 9:56
 * @Version 1.0
 */
public class UserTest {
    public static void main(String[] args) {
        User user = new User();

        System.out.println(user.age);

        User user1 = new User(30);
        System.out.println(user1.age);

        user1.age = 40;
        user.age = 50;
    }
}

class User{
    //属性(或实例变量)

    String name;
    int age = 10;

    public User(){
        //age = 20;
    }

    public User(int a){
        age = a;
    }
}

二、企业真题

2.1 类与对象

1. 面向对象,面向过程的理解?

  • 不管是面向过程、面向对象,都是程序设计的思路。
  • 面向过程:以函数为基本单位,适合解决简单问题。比如:开车
  • 面向对象:以类为基本单位,适合解决复杂问题。比如:造车

2. Java 的引用类型有哪几种

类、数组、接口;枚举、注解、记录

3. 类和对象的区别

  • 类:抽象的,概念上的定义
  • 对象:具体的,类的一个一个的实例。
  • 面向对象完成具体功能的操作的三步流程(非常重要)

4. 面向对象,你解释一下,项目中哪些地方用到面向对象?

“万事万物皆对象”。

2.2 Java内存结构

1. Java虚拟机中内存划分为哪些区域,详细介绍一下

  1. Java中内存结构划分为:虚拟机栈、堆、方法区;程序计数器、本地方法栈
  2. 虚拟机栈:以栈帧为基本单位,有入栈和出栈操作;每个栈帧入栈操作对应一个方法的执行;方法内的局部变量会存储在栈帧中。
  3. 堆空间:new 出来的结构(数组、对象):① 数组,数组的元素在堆中 ② 对象的成员变量在堆中。
  4. 方法区:加载的类的模板结构。

2. 对象存在Java内存的哪块区域里面?

堆空间。

2.3 权限修饰符(封装性)

1. private 、缺省、protected、public的表格化作用区域

2. main方法的public能不能换成private?为什么?

能。但是改以后就不能作为程序的入口了,就只是一个普通的方法。

2.4 构造器

1. 构造方法和普通方法的区别

编写代码的角度:没有共同点。声明格式、作用都不同。

字节码文件的角度:构造器会以<init>()方法的形态呈现,用以初始化对象。

2. 构造器Constructor是否可被overload?

可以。

3. 无参构造器和有参构造器的的作用和应用

都用来初始化属性。

2.5 属性及属性赋值顺序

1. 成员变量与局部变量的区别

6个点。

2. 变量赋值和构造方法加载的优先级问题

变量显式赋值先于构造器中的赋值。

如何证明?我看的字节码文件。

;