小白学习笔记(面向对象(基础篇))

学习面向对象内容的三条主线:

Java类及类的成员:属性,方法,构造器(前三个是重点);代码块,内部类

面向对象的特征:封装,继承,多态,(抽象)(如果除三个之外还要补充一个就还有抽象)

其他关键字的使用: this,super,package,import,static,final,interface,abstact等

1.面向对象编程概述(了解):

1.1程序设计的思路:

面向对象,是软件开发中的一种编程风格,除了面向对象,还有面向过程,指令式编程和函数式编程。

1.面向过程的程序设计思想,简称pop

关注的焦点是过程:过程就是操作数据的步骤,如果某个过程的实现代码反复出现,那么就可以把这个过程抽取为一个函数,这样就可以简化代码。

代表:C语言

是一种执行者思维,适合解决简单问题,扩展能力差,后期维护难度大

2.面向对象的程序设计思想,简称OOP

关注的焦点是类:在计算机程序设计过程中,参照现实中事物,将事物的属性特征,行为特征抽象出来,用类来表示

代表:Java,c#, C++等

代码结构:以类为组织,每种事物都具备自己的属性和行为/功能

是一种设计者思维,适合解决复杂问题,代码扩展性强,可维护性高

千万不要把面向对象和面向过程对立,他俩是相辅相成的

2.Java语言的基本元素:类和对象

类和对象概述:

类:具有相同特征的事物的抽象描述,是抽象的,概念上的定义

对象:实际存在的该类事物的每个个体,是具体的,因而也称为实例

可以理解为:类==>抽象概念上的人。对象==>实实在在的某个人

类的成员的概述:

面向对象程序设计的重点是“类的设计”,类的设计就是类的成员的设计

现实世界的生物体都是由最基本的细胞构成的,同理,Java代码世界是由诸多不同功能的类构成的

现实生物世界中的细胞是由细胞核,细胞质等构成。Java中的用类class来描述事物也是如此

类,是一组相关属性和行为的集合,这也是类最基本的两个成员

属性:该类事物的状态信息,对应类中的成员变量

成员变量<==>属性<==>Field

行为:该类事物要做什么操作,或者是基于事物的状态能做什么。对应类中的成员方法

(成员)方法<==>函数<==>Method

类的定义:

定义一个Phone类:

//类的定义
public class Phone {
    //属性(就是变量)
    String brand;//品牌
    double price;//价格


    //方法(能做的行为)
    public void call(){
        System.out.println("手机能打电话");
    }

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

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

}

调用这个类:

public class PhoneTest {//Phone类的测试
    public static void main(String[] args) {
        //创建phone的对象
        Phone p1 = new Phone();
        //通过phone的对象,调用其内部的属性
        p1.brand = "huawei";
        p1.price = 3999;

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

    }

}

类的实例化(创建类的对象):

格式:类的类型 对象名 = new 创建的实体()

举例:

Phone p1 = new Phone();

Scanner scan = new Scanner(System.in);

面向对象完成具体功能的操作的三步流程:

步骤1:创建类,并设计这个类的内部成员(属性,方法)

方法2:创建类的对象,比如:Phone p1 = new Phone();

方法3:通过这个对象,调用其内部声明的属性或方法,完成相关的功能

练习:

创建的类:

public class Person {
      //属性
      String name;
      int age;
      char gender;
      int high;

     //方法
      public void eat(){
       System.out.println("吃饭");
      }
      public void sleep(int hour){
       System.out.println("人至少保证每天" + hour + "个小时的睡眠");
      }
      public void habbit(String habbit){
       System.out.println("我的爱好是 " + habbit);
      }

}

创建的对象:

public class PersonTest {
    public static void main(String[] args) {
        //创建一个对象
        Person per = new Person();
        //通过对象,调用属性
        per.name = "妄汐霜";
        per.age = 19;
        per.gender =  '男';

        //调用行为
        per.eat();
        per.habbit("学习,阅读,当纯小子");
        per.sleep(15);
        System.out.println(per.name);
        System.out.println(per.gender);
        System.out.println(per.age);



        //再创建Person类的另一个对象
        Person per2 = new Person();
        //调用属性
        per2.name = "夏攸";
        per2.age = 21;
        per2.gender = '女';
        per2.high = 179;
        //调用方法(属性)
        per2.eat();
        per2.sleep(16);
        per2.habbit("打电动");
        System.out.println(per2.name);
        System.out.println(per2.age);




    }
}

对象在内存中的分配涉及到的内存结构:

栈(stack):方法内定义的变量(比如上面例子里main方法中的per,per2)

堆(heap):new 出来的结构(数组的实体,对象的实体),包括对象中的属性

方法区(method area):存放类的模板。比如:上面例子中的Person类的模板(即整个Person这个类)

类中对象的内存解析:

创建类的一个对象:

创建类的多个对象:

强调:

Person p1 = new Person();

Person p2 = new Person();

创建了两个对象。

说明:创建类的多个对象时,每个对象在对空间中有一个对象实体,每个对象实体中保存着一分类的属性,如果修改某一个对象的某个属性值时,不会影响其他对象此属性的值

强调2:

Person p1 = new Person();

Person p3 = p1;

说明:此时p1,p3两个变量指向了堆空间中的同一个对象实体,如果通过其中某一个对象变量修改对象的属性时,会影响另一个对象,因为他俩是同一个。

再次强调面向对象完成具体功能的操作的三步流程(非常重要):

步骤1:创建类,并设计这个类的内部成员(属性,方法)

方法2:创建类的对象,比如:Phone p1 = new Phone();

方法3:通过这个对象,调用其内部声明的属性或方法,完成相关的功能

类的成员之一:属性(就是变量)

1.变量的分类:

角度一:按照数据类型来分:基本数据类型,引用数据类型(数组,类,接口,枚举,注解,记录)

角度二:按照变量在类中声明的位置不同:成员变量(或属性),局部变量(方法内,方法形参,构造器

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

举例:

public class FileTest {
    public static void main(String[] args) {

    }
}




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

    //上面的这些都是属性(或成员变量)

    //方法
    public void eat(){
        String food = "宫保鸡丁";//这里的food就是局部变量
        System.out.println("我喜欢吃" + food);
    }
    public void sleep(int hour){
        System.out.println("一天要睡" + hour + "小时");
    }



}

区分成员变量和局部变量:

相同点:

变量声明格式相同:数据类型 变量名 = 变量值;

只要是变量,都有其作用域。除了作用域就失效了

变量都必须先声明再使用。

不同点:

类中声明的位置不同: 属性:声明在类内,方法外的变量

局部变量:声明在方法内内部的变量

在内存中分配的位置不同: 属性:随着对象的创建,存储在堆空间中

局部变量:定义在方法之内的变量,存储在栈空间中

生命周期: 属性:随着对象的创建而创建,随着对象的消亡而消亡

局部变量:随着方法对应的栈帧入栈,局部变量会在栈中分配,随着方法对应的栈帧出栈,局部 变量消亡

作用域: 属性:在整个类的内部都是有效的

局部变量:仅限于声明此局部变量所在的方法中

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

属性:是可以使用权限修饰符进行修饰

局部变量:不可以使用权限修饰符进行修饰

是否有默认值(重点):

属性:都有默认值

如果没有给属性进行显式赋值,就会赋默认值

局部变量:都没有默认值

注意:对于方法的形参而言,在调用方法时,给此形参赋值即可

练习:

创建的两个类:

public class Employee {
    //定义属性
    int id;//编号
    String name;
    int age;
    int salary;
    MyDate birthday;

}
public class MyDate {
    int year;
    int month;
    int day;
}

应用这个类:

public class EmployeeTest {
    public static void main(String[] args) {
//声明员工类Employee:包含属性:编号id。姓名name,年龄age,薪资:salary
//在main方法中创建两个对象,并为其属性赋值,并打印两个员工的信息
    //创建两个对象
    Employee emp1 = new Employee();
    Employee emp2 = new Employee();

    //为其属性赋值
    emp1.id = 1;
    emp2.id = 2;
    emp1.name = "妄汐霜";
    emp2.name = "夏攸";
    emp1.age = 19;
    emp2.age = 18;
    emp1.salary = 10000;
    emp2.salary = 7500;

    //打印员工幸喜
        System.out.println(emp1.id);
        System.out.println(emp2.id);
        System.out.println(emp1.name);
        System.out.println(emp2.name);
        System.out.println(emp1.age);
        System.out.println(emp2.age);
        System.out.println(emp1.salary);
        System.out.println(emp2.salary);


        //创建两个员工,并为他们的生日赋值
        Employee emp3 = new Employee();
        Employee emp4 = new Employee();

        emp3.birthday = new MyDate();//这个不是基础数据类型,要和创建类的对象一样,通过new的方式新建
        emp3.birthday.year = 2006;
        emp3.birthday.month = 4;
        emp3.birthday.day = 8;
        //打印员工信息
        System.out.println(emp3.birthday.year);

    }
}

内存结构分析:

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

1.使用方法的好处

方法是类或行为特征的抽象·,用来完成某个功能操作,在某些语言中也称为函数或过程

将功能封装为方法的目的是,可以实现代码复用,减少冗余,简化代码

Java里的方法不能独立存在,所有的方法必须声明在类里面

2.使用举例

Math.random()的random()方法

Math.sqrt(x)的sqrt(x)方法

Arrays类中的binarySearch()方法,sort()方法,equals()方法等等

3.声明举例

//方法
public void eat(){
    System.out.println("人会吃饭");
}
public void sleep(int hour){
    System.out.println("人每天至少睡" + hour + "小时");
}
public String interests(String habbit){
    String info = "我的爱好是" + habbit;
    return info;
}
public int getAge(){
    return age;
}

4.方法声明的格式(重要):

权限修饰符 返回值类型 方法名(形参列表){

//方法体

}

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

5.1权限修饰符:private / 缺省 / protected / public

5.2 返回值类型:描述当调用完此方法时,是否需要返回一个结果

分类:

无返回值类型:void

有具体的返回值类型:需要指明返回的数据的类型。可以是基本数据类型,也可以是引用 数据类型

需要配合return关键字;

5.3方法名:属于标识符,需要满足表示符命名的规定和规范,要见名知意

5.4 形参列表:形参,属于局部变量,且可以声明多个

格式:(形参类型1 形参1,形参类型2 形参2)

(如果有不确定的值要传进来,就用形参;没有的话,就不用。和C语言的函数差不多)

6.注意点:

Java所有的方法都不能独立存在,必须定义在类里。

必须先声明后使用。

Java中的方法不调用不执行,每调用一次,执行一次。

方法内可以调用本类中的方法或属性。

方法内不能定义方法。

7.return的使用:

7.1 return的作用

作用1:结束一个方法

作用2:结束一个方法的同时,可以返回数据给方法的调用者

注意点:return后面不能再声明语句

练习:

创建方法:

public class Employee {
    //定义属性
    int id;//编号
    String name;
    int age;
    int salary;
    MyDate birthday;
    //定义方法,显示员工信息
    public void show(){
        System.out.println(" id = " + id + " name = " + name + " age = " + age + " salary = " + salary);
    }
}

调用方法:

public class EmployeeTest {
    public static void main(String[] args) {
//声明员工类Employee:包含属性:编号id。姓名name,年龄age,薪资:salary
//在main方法中创建两个对象,并为其属性赋值,并打印两个员工的信息
    //创建两个对象
    Employee emp1 = new Employee();
    Employee emp2 = new Employee();

    //为其属性赋值
    emp1.id = 1;
    emp2.id = 2;
    emp1.name = "妄汐霜";
    emp2.name = "夏攸";
    emp1.age = 19;
    emp2.age = 18;
    emp1.salary = 10000;
    emp2.salary = 7500;

    //打印员工幸喜
        System.out.println(emp1.id);
        System.out.println(emp2.id);
        System.out.println(emp1.name);
        System.out.println(emp2.name);
        System.out.println(emp1.age);
        System.out.println(emp2.age);
        System.out.println(emp1.salary);
        System.out.println(emp2.salary);


        //创建两个员工,并为他们的生日赋值
        Employee emp3 = new Employee();
        Employee emp4 = new Employee();

//        emp3.birthday = new MyDate();//这个不是基础数据类型,要和创建类的对象一样,通过new的方式新建
//        emp3.birthday.year = 2006;
//        emp3.birthday.month = 4;
//        emp3.birthday.day = 8;
//        //打印员工信息
//        System.out.println(emp3.birthday.year);


        //不用再手打,调用show方法,直接打印。
        emp1.show();
        emp2.show();


    }
}

8.方法调用的内存解析:

形参:方法在声明时,一对()内声明的一个或多个形式参数,简称为形参

实参:方法在被调用时,实际传递给形参的变量或常量,称为实际参数,简称实参

方法用完之后就会弹出栈

属性和方法的练习:

练习1:

创建的类:

public class Person3 {
    //定义属性
    String name;//姓名
    int age;//年龄
    char gender;//性别


    // 定义方法,注意要定义在类里
    public void study(){
        System.out.println("studying");
    }
    public int showAge(){
        return age;
    }
    public int addAge(int num){
        age += num;
        return age;
    }
}

调用:

public class MethodExer2 {
    public static void main(String[] args) {
//案例:创建Person类的对象,设置该对象的name,age和gender属性
//调用study方法,输出字符串“studying”
//调用showAge()方法,返回age值
//调用addAge(int addAge)方法给对象的age属性值增加addAge岁。

        //创建属性,并给属性赋值
        Person3 p1 = new Person3();
        p1.name = "妄汐霜";
        p1.age = 19;
        p1.gender = '男';

        //调用方法
        p1.study();
        System.out.println(p1.showAge());
        System.out.println(p1.addAge(5));
    }
}

练习2:

new对象的时候,要注意最前面和最后面的要和类名是一致的,而不是和对象所在的文件名一致

创建的类:

public class Method {
    //声明方法
    public void method1(int i,int j){
     for( i = 1;i <= 10;i++){
      for( j = 1;j <= 8;j++){
       System.out.print("*");
      }
      System.out.println();
     }
    }


    public int method2(int x,int y){
     method1(x,y);
     int area;
     area = x*y;
     return area;
    }

    public int method3(int m,int n){
     for(int i = 1;i <= m;i++){
         for(int j = 1;j <= n;j++){
             System.out.print("*");
         }
         System.out.println();
     }
     return m*n;
    }
}

创建对象并调用:

public class MethodExer3 {
    public static void main(String[] args) {
//1.编写程序,声明一个method1方法,在方法中打印一个10*8的矩形,在main方法中调用此方法
//2。编写程序:声明一个method2方法,除打印一个10*8的矩形之外,再计算该矩形的面积,将其作为方法的结果返回,在main方法中调用此方法,并接受返回的面积
//3.编写程序,声明一个method3方法,再method3方法提供m和n两个参数,方法中打印一个m*n的矩形,并计算该矩形的面积,将其作为返回值返回,在main方法中调用该方法,接收返回的面积并打印

        //先new一个类中的对象
        Method obj = new Method();
        //通过new的对象,调用方法
        obj.method1(10,8);
        System.out.println();
        System.out.println(obj.method2(10, 8));
        System.out.println();
        System.out.println(obj.method3(5, 8));

    }
}

练习3:

创建的类:

public class Circle {
    //设计方法
    public double Circle(int radius) {
     double PI = 3.14;
     double area =   PI*radius * radius;
     return area;
    }
}

创建对象并调用:

public class MethodExer4 {
 public static void main(String[] args) {
  //利用Java,设计类Circle计算圆的面积

  //先new一个对象
  Circle c1 = new Circle();

  //通过对象调用方法
  System.out.println(c1.Circle(3));


 }
}

练习4:

创建的类:

public class ArrayAndMethod {
    /**
     * 获取int[]数组的最大值
     *
     * @param arr 获取最大值的数组
     * @return 数组的最大值
     */

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


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


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


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

    /**
     * 遍历数组
     *
     * @param arr 要遍历的数组
     */
    public void printArray(int[] arr) {
        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("]");
    }


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

    /**
     * 数组的反转
     *
     * @param arr 要反转的数组
     */
    public void reverseArray(int[] arr) {
        for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }


    /**
     * 数组的排序
     *
     * @param arr 要排序的数组
     */
    public void sortArray(int[] arr) {

        //使用冒泡排序
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    /**
     * 使用线性查找,查找数组
     *
     * @param arr 要查找的数组
     * @return 返回要查找的数,若未找到,返回-1
     * @target 要查找的数
     */
    public int searchArray(int[] arr, int target) {
        int i = 0;
        for (; i < arr.length; i++) {
            if (arr[i] == target) {
                System.out.println("找到了" + target + ", 对应的位置是 " + i);
                return 1;
            }

        }
        if (i == arr.length - 1) {
            System.out.println("没找到" + target);
        }
        return -1;
    }
    }

创建的对象并调用方法:

public class MethodExer5 {
    public static void main(String[] args) {
//根据上一章数组中的常用算法类型:自定义一个操作int[]的工具类
//涉及到的方法有:求最大值,最小值,总和,平均数,遍历数组,复制数组,数组反转
        //new一个对象
        ArrayAndMethod arr = new ArrayAndMethod();
         int [] arr1 = {12,3,432,53,14,43,12,5,24,56,45,42,53};

        //通过对象,调用方法
        System.out.println(arr.max(arr1));//找出最大值
        System.out.println(arr.average(arr1));//平均值
        arr.printArray(arr1);//遍历数组
        int num = arr.searchArray(arr1,432);
        if(num == -1){
            System.out.println("未找到");
        }
        arr.sortArray(arr1);
        arr.printArray(arr1);
    }
}

对象数组的使用及内存解析:

对象数组:数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用数据类型中的类( 类(class),数组(array),接口(interface),枚举(enum),注解(annotation), 记录(record))时,我们称为对象数组

举例:String[], Student[], Customer[]等

练习:

创建的类:

public class Student {
    //定义属性
    int number;
    int state;
    int score;
}

创建的对象数组并调用方法:

public class MethodExer6 {
    public static void main(String[] args) {
//案例:定义类Student,包含三个属性:学号number(int),年纪state(int),成绩score(int)
//创建20个学生对象,学号为1到20,成绩和年纪都由随机数确定
//问题一:打印3年纪的学生信息
//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息

//提示:生成随机数:Math.random(),返回值的类型为double
//四舍五入取整:Math.round(double d),返回值类型long
//年纪[1,6]:(int)(Math.random() * 6 +1)
//分数[0,100]:(int)(Math.random() * 101)

       //创建对象数组
         Student[] students = new Student[20];

           //给属性赋值
        for(int i = 0; i < students.length; i++ ) {
            //创建对象
            students[i] = new Student();//初始化每个对象

            students[i].number = i + 1;
            students[i].score = (int) (Math.random() * 101);//给成绩赋值
            students[i].state = (int) (Math.random() * 6 + 1);//给年级赋值
            // 打印3年纪学生信息
            if (students[i].state == 3) {
                System.out.print("该学生的学号是" +students[i].number + "\t");

                System.out.println("该学生的成绩是" + students[i].score + "\t");
            }
        }
        System.out.println();
           //使用冒泡排序按学生成绩排序,并遍历所有学生信息
        for(int i = 0; i < students.length - 1; i++ ) {
            for (int j = 0; j < students.length - 1 - i; j++) {
                if (students[j].score > students[j + 1].score) {
                    Student temp;//交换整个,而不只是交换成绩
                    temp = students[j];
                    students[j] = students[j + 1];
                    students[j + 1] = temp;
                }
            }
        }
        System.out.println();

        for(int i = 0; i < students.length ; i++ ) {
            System.out.print("学生的成绩是" + students[i].score + "\t");
            System.out.print("学生的学号是" + students[i].number + "\t");
            System.out.println("学生的年纪是" + students[i].state + "\t");

        }

    }
}

内存解析:

方法应用1:方法的重载

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

总结为:两同一不同

两同:同一个类;相同的方法名

一不同:参数列表不同:1:参数个数不同。2:参数类型不同

重载的特点:与修饰符,返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类

型)。调用时,根据方法参数列表的不同来区分

重载方法调用:jvm通过方法的参数列表,调用匹配的方法(先找个数,类型最匹配的;再找个数和类型可以兼容的,如果同时多个方法兼容将会报错)

举例:

public class OverLoadTest {
    public void add(int i, int j){
        
    }

    public void add(int i,int j,int k){
    
    }
    
    public void add(String i, String j){
        
    }
    
    public void add(int i ,String j){
        
    }
    
    //public void add(int m,int i){
        
    //}这个方法就不行,因为参数列表和第一个一样了
    
    
}

如何判断两个方法相同?

方法名相同,且形参列表也相同(形参列表相同指的是参数个数和参数类型都相同,与参数名无关)

返回值类型不看

练习:

1.

public class OverLoadExer {
 //案例:编写程序:定义三个重载方法并调用,方法名为mOL
 //三个方法分别接收一个int参数,两个int参数,一个字符串参数
 //分别执行:平方运算并计算结果,相乘并输出结果,输出字符串信息
    public void  mOL(int n){
     System.out.println(n * n);
    }
    public void mOL(int m,int n){
     System.out.println(m * n);
    }

    public void mOL(String s){
     System.out.println(s);
    }


}

2.

public class OverLoadExer2 {
 //定义三个重载方法max()
 //第一个方法求两个int值中的最大值
 //第二个方法求两个double值中的最大值
 //第三个方法求三个double值中的最大值,并分别调用三个方法
    public int max(int x,int y){
     int max = (x > y)?x:y;
     return max;
    }
    public void max(double x,double y){
     double max = (x > y)?x:y;
     System.out.println(max);
    }
   public void max(int x,int y,double z){
     double max = (x > y)?x:y;
     double trueMax = (max > z)?max:z;
     System.out.println(trueMax);
   }

}

面试题:

public class OverLoadExer3 {
    public static void main(String[] args) {

     int[] arr = new int[]{1,2,3};
     System.out.println(arr);//[I@4eec7777

     char[] arr1 = new char[]{'z','b','c'};
     System.out.println(arr1);//zbc

     boolean[] arr2 = new boolean[]{true,false,true};
     System.out.println(arr2);//[Z@3b07d329
    }

}

方法应用2:可变个数形参的方法

1.使用场景:

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

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

比如:

public class ArgsTest {
 
    public void print(int ... nums){
         
    }
}

3.说明:

1.可变个数形参的方法在调用时,针对于可变的形参赋的实参个数可以为:0个,1个或多个

2.可变个数形参的方法与同一个类中,同名的多个方法之间可以构成重载

特例:

public void print(int ... nums){

}
public void print(int[] nums){
 
}//这俩不能构成重载,本质上是一样的

4.可变个数的形参,必须声明在形参列表的最后

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

5.可变个数的形参,最多在一个方法的形参列表中出现一次

可变参数练习:

public class StringConCatTest {
 public static void main(String[] args) {

  //新建一个对象
    StringConCatTest test = new StringConCatTest();
    String info = test.concat("-","hello","world");
    System.out.println(info);


 }
 public String concat(String operator,String ... strs){
    String result = "";
    for(int i = 0; i < strs.length; i++){
     if(i == 0){
      result += strs[i];
     }else{
       result += (operator + strs[i] );
     }
    }
    return result;
 }

}

方法引用3:方法值传递机制的剖析(重点):

1.(复习)对于方法内声明的局部变量来说:

public class ValueTransfer {
    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.引用数据类型的局部变量(类(class)//数组(array)//接口(interface)//枚举(enum)//注解(annotation)//记录(record))
        //2.1数组类型
        int[] arr1 = new int[]{1,2,3,4,5};
        int[] arr2 =arr1;//没有new,传递的是地址值

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

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

        Order order2 = order1;
        order2.oderId = 1002;

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

    }
}


class Order{
    //定义属性
    int oderId;
}

1.1如果是基本数据类型的变量,则将此变量保存的数据值传递出去(可以理解成C语言里的值传递)

1.2如果是引用数据类型的变量,则将此变量保存的地址值传递出去(可以理解成C语言里的址传递)

2.方法的参数的传递机制:值传递机制(存的什么就传递什么,存的数据值就传递数据,存的地址值就传递地址)

2.2规则:实参给形参赋值的过程

2.2.1如果形参是基本数据类型的变量,则将实参保存的数据值赋给形参

2.2.2如果是引用数据类型的变量,则将实参保存的地址值赋给形参

3.面试题:Java中的参数的传递机制是什么?

值传递(不是引用传递)

练习:

public class ValueTransferTest2{
    public static void main(String[] args){
        ValueTransferTest2 vt2 = new ValueTransferTest2();
        int m = 10,n = 20;
        System.out.println("m = " + m + ", n = " + n);
        //交换两个变量的值
        vt2.swap(m,n);
        System.out.println("m = " + m + ", n = " + n);
    }
    public void swap(int m,int n){
        int temp = m;
        m = n;
        n = temp;
    }
}

m,n的值最后输出不会交换,因为是在swap里交换的,交换的是swap里定义的局部变量m,n,出了swap后就没用了

练习2:

public class ValueTransferTest3{
     public static void main(String[] args) {
      ValueTransferTest3 obj = new ValueTransferTest3();
      Data1 data = new Data1();
      data.m = 10;
      data.n = 20;
      System.out.println("m = " + data.m + ", n = " + data.n);

      obj.swap1(data);

     }
     public  void swap1(Data1 data){
      int temp = data.m;
      data.m = data.n;
      data.n = temp;
      System.out.println("m = " + data.m + ", n = " + data.n);
     }

   }
class Data1{
     int m;
     int n;
}

m,n的值最后会交换,因为swap1里的形参是地址值,指向了data,所以可以交换

练习:

public class ValueTransferTest4{
     public static void main(String[] args) {
      //1.定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积
      //
      //
      //2.定义一个类PassObject,在类中定义一个方法printAreas(),该方法的定义如下:
      //public void printAreas(Cirsle2 c,int time)
      //
      //3.在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。
      //
      //4.在main方法中调用printAreas()方法,调用完毕后输出当前半径值

      PassObject c1 = new PassObject();
      Circle2 c2 = new Circle2();
      c1.printAreas(c2,5);

     }


    }
class PassObject {
    public void printAreas(Circle2 c,int time){
        for(int i = 1;i <= time;i++){
            c.radius = i;
            System.out.println(c.radius);
            System.out.println(c.findArea());
        }
    }
}
 class Circle2 {
    //1.定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积
    //
    //
    //2.定义一个Circle类,在类中,定义一个方法,printAreas()。该方法的定义如下:
    //public void printAreas(Circle c ,int time)
    //
    //3.在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。
    //
    //4.在main方法中调用printAreas()方法,调用完毕后输出当前半径值


    //定义属性
    double radius;
    //定义方法
    public double findArea() {

        return  Math.PI * radius * radius;
    }

}

方法应用4:递归

递归方法调用:方法自己调用自己

方法的分类:直接递归,间接递归(a调用b,b调用c,c调用a)

说明:

递归包含了一种隐式的循环

递归方法会重复执行某段代码,但这种重复执行无需循环控制

递归一定要向已知方向递归,否则这种递归就变成了无穷递归,最终会栈内存溢出

举例:

public class RecursionTest {
    public static void main(String[] args) {
        //获取1-100内自然数的总和
        RecursionTest test = new RecursionTest();
        System.out.println(test.getSum(100));
        System.out.println(test.getMul(5));
        System.out.println(test.getDiv(10));
    }


    public int getSum(int num){
        int sum = 0;
        if(num == 1){
        return 1;
        }else{
        return getSum(num-1) + num;}
    }

    public int getMul(int n){
        if(n == 1){
            return 1;
        }else{
            return getMul(n-1) * n;
        }
    }


    //斐波那契数列
    public int getDiv(int n){
        if(n == 1){
            return 1;
        }else if(n == 2){
            return 1;
        }else{
            return getDiv(n-1) + getDiv(n-2) ;
        }
    }
}

注意:

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

2.在要求高性能的情况下尽量避免使用递归

练习:

public class RecusionExer01{
    //已知数列:f(20) = 1,f(21) = 4,f(n + 2) = 2 * f(n+1)+ f(n)
    //其中n是大于0的整数,求f(10)的值
    public static void main(String[] args) {
        RecusionExer01 rec = new RecusionExer01();
        System.out.println(rec.f(14));

    }

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

package关键字的使用:
说明:
package:包,用于指明该文件中定义的类,接口等结构所在的包

语法格式:package 顶层包名.子包名;

说明:
1.一个源文件只能有一个声明包的package语句
2.package语句作为Java源文件的第一条语句出现,如果省略该语句,则指定为无名包
3.包名,属于标识符,满足标识符命名的规则和规范(全部小写)(看到这回去复习一下),见名知意
4.包通常使用所在公司域名的倒置
5.大家取包名的时候不要使用“Java.xx”包
6.包对应文件系统的目录,package语句中使用“.”来指明包(目录)的层次,每.一次就代表一层文件目录
7.同一个包名下可以声明多个结构(类,语句),但是不能定义同名的结构(类,接口),不同的包下可以定义同名的结构(类,接口)

包的作用:
1.包可以包含类和子包,划分“项目层次”,便于管理
2.帮助“管理大型软件”系统:将功能相近的类划分到同一个包中,
3.解决“类命名冲突”的问题
4.控制访问权限

jdk中主要的包:
java.lang
java.net
java.io
java.util
java.spl
java.awt

import关键字的使用:

为了使用定义在其他包中的Java类,需用import语句来显示引用指定包下所需要的类,相当于import语句告诉编译器到哪里去找这个类。

语句格式;

import 包名.类名;

注意事项:

1.import语句,声明在包的声明和类的声明之间

2.如果需要导入多个类或接口,那么久并列显示多个import语句即可

3,如果使用a.*导入结构,表示可以导入a包下的所有的结构。举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口

4。如果导入的类或接口是java.lang包下的,或者是当前包下的,就可以省略import语句

5.如果已经导入Java.a包下的类,那么如果需要使用a包的子包下的类的话,任然需要导入

6.如果在代码中使用不同包下的同名的类,那么就需要使用类的全类名的方式指明调用的是哪个类

7.(了解)import static组合的使用,调用指定类或接口下的静态的属性或方法

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

1,为什么需要封装性:

理论上:随着项目越来越复杂,类越来越多,那么类之间的访问边界必须把控好,面向对象的开发原则要遵守“高内聚,低耦合”

高内聚:类的内部数据操作细节由自己完成,不允许外界干涉

低耦合:仅暴露少量方法给外部使用,尽量方便外部调用

2.何为封装性:

所谓封装,就是把客观事物封装成抽象类的概念,并且类可以把自己的数据和方法只向可信的类或对象开放,向没必要开放的类或者对象隐藏信息。

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

3.如何实现数据封装

3.1权限修饰符:

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

3.2作用:

可是使用四种权限修饰符修饰类及类的内部成员,当这些成员被调用时,体现可见性的大小

3.3实例说明

package AniMalTest;

/**
 * ClassName:AniMalTest
 * Package:AniMalTest
 * Description:
 *
 * @Author 妄汐霜
 * @Create 2025/11/3 21:19
 * @Version 1.0
  */
    public class AniMalTest {
     public static void main(String[] args) {
      AniMal animal1 = new AniMal();
      animal1.name = "长颈鹿";
      animal1.legs = 3;
      //此时的legs就不能再调用了,因为AniMal方法中的legs已经私有化,不能再调用了
      //只能通过调用方法来调用legs   
      animal1.setLegs(animal1.legs );
         System.out.println("name = " + animal1.name + ",legs = " + animal1.legs);
      animal1.eat();


 }





}
    class AniMal{
    //属性
     String name;
     private int  legs;
     //方法
     public void eat(){
      System.out.println("动物觅食");
     }


     public void setLegs(int l){
     if(l >= 0 && l % 2 == 0){
         l = legs;
     }else{
         System.out.println("输入的数据有误");
     }
     }
}

另外再定义一个方法后就可以调用legs了

public int getLegs(){
    return legs;
}

在题目中,我们给Animal的对象的legs属性赋值。在实际的常识中,我们知道legs不能赋值为负数的,但是如果直接调用legs,是不能加入判断语句的,那该怎么办:

1.将legs属性私有化(private),再另外设置另一个方法用来调用或者给legs属性赋值,在这个方法中加入判断语句

3.4 4种 权限具体使用情况

类,只能用public ,缺省修饰

类的内部成员,就可以用四种权限修饰符进行修饰

练习:

创建的类:

public class Person {
    private int age;
    public void setAge(int a) {
        if(a >= 0 && a <= 130 ){
            age = a;
        }else{
            System.out.println("输入非法");
        }
    }
    public int getAge() {
        return age;
    }
}

对象:

public class PersonTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(20);
        System.out.println(person.getAge());
    }
}

练习2:

创建的类:

public class Book {
    //定义属性
    private String title;//标题
    private String author;//作者
    private int price;//价格

    //定义方法来获取
    public String getTitle() {
        return title;
    }
    public String getAuthor() {
        return author;
    }
    public int getPrice() {
        return price;
    }


    public void setTitle(String title) {
        this.title =title;
    }
    public void setAuthor(String author) {
        this.author =author;
    }
    public void setPrice(int price) {
        this.price =price;
    }

}

创建的对象:

public class BookTest {
    public static void main(String[] args) {
        Book book = new Book();
        book.setAuthor("妄汐霜");
        book.setPrice(9999);
        book.setTitle("颠虚自守");

        System.out.println(book.getAuthor());
        System.out.println(book.getPrice());
        System.out.println(book.getTitle());

    }
}

练习3:

创建的类;

public class Employee {
    //定义属性
    private String name;
    private char gender;
    private int age;
    private String phoneNumber;

    public void setName(String name) {
        this.name = name;
    }
    public void setGender(char gender) {
        this.gender = gender;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
    public String getName() {
        return name;
    }
    public char getGender() {
        return gender;
    }
    public int getAge() {
        return age;
    }
    public String getPhoneNumber() {
        return phoneNumber;
    }


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


}

对象:

public class EmployeeTest {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        Employee[] emp = new Employee[2];

        for(int i = 0; i < emp.length; i++){
            emp[i] = new Employee();
            System.out.println("添加第" + (i + 1)+ "个员工的信息");
            System.out.println("姓名");
            String name = sc.next();
            System.out.println("性别");
            char gender = sc.next().charAt(0);
            System.out.println("年龄");
            int age = sc.nextInt();
            System.out.println("电话");
            String phoneNumber = sc.next();

            //给数组元素赋值
            emp[i].setName(name);
            emp[i].setGender(gender);
            emp[i].setAge(age);
            emp[i].setPhoneNumber(phoneNumber);
        }
        //遍历输出数组的元素
        for(int i = 0; i < emp.length; i++){
            System.out.println(emp[i].getInfo());
        }
    }
}

类的成员之三:构造器(constructor):

1.构造器的理解

凡是类都有构造器

2.构造器的作用:

作用1:搭配new关键字,创建类的对象

举例:Person person = new Person();

末尾带()的就是构造器

作用2:在创建对象的同时,可以给对象的相关属性赋值

3.构造器的使用:

格式:

权限修饰符 类名(形参列表){}

比如::

}

说明:

1.创建类以后,在没有显示提供任何构造器,系统会提供一个空参的构造器,且构造器的权限和类声明的权限相同。

2.一旦类中显示显示声明了构造器,则系统不在提供默认的空参的构造器

3.一个类中可以声明多个构造器,这就是构造器重载

实例变量赋值过程:

1.在类的属性中,可以有哪些位置给属性赋值:

1.默认赋值

2.显式赋值:

3.构造器中赋值

4.通过“对象.方法”的方式赋值。

5.通过“对象.属性”的方式赋值

2.这些位置执行的先后顺序:

1 ->2->3->4/5

3.以上操作在对象创建过程中可以执行的次数如何?

1.2.3只能执行一次

4.5能多次赋值

JavaBean:
Javabean是一种java语言写成的可重用组件

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

类是公共的

有一个无参的公共的构造器

有属性,有对应的get,set方法

举例:

public class Customer1 {
    //公共的空参构造器
    public Customer1(){
        
    }
    //属性
    private int id;
    private String name;
    
    //属性对应的set,get方法
    public void setID(int i){
        id = i;
    }
    public int getID(){
        return id;
    }
    public void setName(String n){
        name = n;
    }
    public String getName(){
        return name;
    }
    
}

读懂UML类图:

UM(统一建模语言),用来描述软件模型和架构的图形化语言

在软件开发中,使用UML类图可以更加直观地描述类内部结构(类的属性和方法)以及类之间的关系

本节梗概:

/*
1.面向过程和面向对象
不管是面向过程还是面向对象,都是程序设计的思路
面向过程:以函数为基本单位,适合简单问题
面向对象:以类为基本单位,适合解决复杂问题


2.类,对象
类:抽象的概念
对象:具体的类的实例

关于对象的内存解析:
创建类的一个对象
创建类的多个对象

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


面向对象的编程步骤:
1.创建类
2.创建类的对象
3.通过对象调用方法


3.类的成员之一:属性(成员变量)
属性和局部变量的对比:
声明的位置不同
内存中存放的位置不同
作用域不同
权限修饰符不同
初始化值
生命周期不同


属性也称成员变量,字段,域等


4.类的成员之二:方法
方法声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
重点:返回值类型,形参列表

return关键字的使用

5.再谈方法:
5.1方法的重载
方法重载的要求:两同一不同:类和方法名相同,形参列表不同

调用方法时,如何确定调用的是指定的方法?
1.方法名2.形参列表


5.2可变个数形参的方法
格式:(int ... args)

5.3方法的参数传递机制
值传递:如果形参是基本数据类型变量,则将实参中保存的数据值传给形参
      如果形参是引用数据类型变量,则将实参中保存的地址值传给形参  


5.4递归方法
方法自己调用自己,构成隐式的循环,内存占用偏高


6.对象数组的使用
String[] Customer[]



7.package,import关键字的使用
package:指明声明的类所属的包
import:当前类中如果使用其他包内的类,就要导包

8.面向对象的特征之一:封装性
Java中规定了四种权限修饰符,可以用4种权限修饰符来修饰类及类中的内部成员。当这些内部成员被调用时,体现可见性大小
比如: 私有化属性,提供公共的方法get,set方法,对此属性进行修改或获取

封装性体现了高内聚,低耦合的程序设计的原则


9.类的成员之三:构造器
格式:权限修饰符 类名(形参列表){
}

搭配new用来创建对象,初始化对象的成员变量


10。三个小知识
10.1  类的实例变量的赋值过程
       
10.2JavaBean

10.3UML图

企业真题:

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

堆空间。

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

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

构造方法(构造器)和普通方法的区别?

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

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

构造器是否可以被重载?

可以。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值