Java递归、数组、排序、面向对象和构造方法

本文详细介绍了Java中的递归概念及其应用场景,数组的声明、操作和异常处理,以及面向对象的基础知识,包括类、对象、构造方法和封装。通过实例解释了如何使用递归、数组、构造方法以及面向对象特性来解决问题。
摘要由CSDN通过智能技术生成

递归

概述

            递归 : 就是在当前方法中, 调用自己
            基本思想 : 以此类推
            递归和迭代是等价的 , 而迭代就是循环 , 所以递归也是重复做某件事
            三要素 : 初始值 , 终止条件 , 步长
            如果循环能做到的 , 就不要使用递归 , 因为递归效率低 , 比较耗内存
            
            应用场景 : 
                一般树状结构 , 需要使用递归来完成
               比如菜单目录 , 每一层目录结构都是一个循环 , 两层就需要嵌套循环 , 那么当不知道有多少层目录的时候 循环就不行了

常见异常

public static void main(String[] args){
    m1();
}
pubic static void m1(){
    //没有终止条件
    m1();
}

数组

概述

            数组 : 是引用数据类型 (类 , 接口 , 数组)
            数组是底层的数据结构 , 几乎任何语言都有 , 数组被分为 索引数组 和 关联数组

数据结构

            数据结构是计算机储存 、组织数据的方式 .数据结构是指相互之间存在一种或多种特定关系的数据元素的集合
            数组
            栈
            链表
            散列
            二叉树 / 红黑树

应用场景

            数组用来存储多个数据 , 比如单个成绩可以用一个变量存储 ,多个的话写多个变量就不合适
            可以使用数组 , 来存储多个数据 , 这样一个变量就可以代替多个变量 , 方便统一操作 , 但是数组中的元素  数据类型必须一致
            int i = 2;
            int[] is = {1,3,5,4,789,456};

数组特性

            可以看做是一个多个相同数据的一个存储容器 , 可以对这些数据进行统一管理
            是一种引用数据类型
                   意味着 数组占用两块空间 , 栈内存  变量保存     堆内存 对象的引用
            是一种线性数据结构 , 内存空间是连续的 , 类似于单元楼
            数据可以保存任意数据的元素, 但是每一维的元素类型必须一致
            数组的长度不能直接更改 , 也就意味着数组一旦确定就不能添加或减少
                   除非新建一个新的数组, 然后把原数组中的元素复制进去 ,在复制的过程中进行 添加和删除
            数组中有一个 length 属性 , 保存的是数组的长度
            并且数组中元素都有一个独一无二的编号(下标)
            要查找数组中的某个元素的时候 , 只需要使用对应的索引下标即可 , 在数组中 0 是第一个元素的下标 , 1则是第二个元素的下标 , 以此类推
                   这种通过内存地址直寻法  , 效率极高
 

            操作 : 增删改查
                结合数组特性, 数组 查找和更改效率高  ,  添加和删除  效率相对较低
            
            与数组相比 , 链表的  添加和删除的效率高  ,  查找和更改效率低

数组声明

            静态声明 : 在知道数组每个元素的值的时候 , 使用静态声明
                   数据类型[] 变量 = {值,值,值,......};
                   int i = 5;
                   int[] is = {1,23,4,5,6};
                   int[][] is2 = {{1,2,3,4,5};   {1,2,3,4,5};   {1,2,3,4,5};   {1,2,3,4,5};   ......};
            
            动态声明 : 在预先不知道每个元素值是多少的时候 , 使用动态声明 , 需要提前指定数组空间长度 ,  并使用默认值占位
                   整数 : 0
                   浮点 : 0.0
                   char : \u0000
                   boolean : false
                   引用类型 : null
            数据类型[] 变量 = new 数据类型[长度];
            int[] is = new int[10];


            数组传递 , 第三种声明方式  静态声明
            数据类型[] 变量 = new 数据类型[]{值,值,值,......};

public static void main(String[] args){
    int [] arr = {1,2,3};
    m1(arr);
    //数组字面量传递
    m1(new int[]{1,2,3});
}

public static void m1(int[] arr){
    for(int i = 0; i < arr.length; i++){
        System.out.println(arr[i]);
    }
}

            数据类型[] 变量   和    数据类型 变量[]
            int[] i = {1,2,3}             int i[] = {1,2,3}

数组的基本操作

获取数据(查)

//长度
System.out.println(is.length);
//首元素  索引/下标  index
//数组对象(数组变量) [下标]
System.out.println(is[0]);
//尾元素
System.out.println(is[is.length-1])

设置数据(改)

//更改操作
//数组[下标] = 值;
is[1] = 1;

遍历

int[] arr = new int[10];
arr[0] = 100;

for(int i = 0; i < arr.length; i++){
    System.out.println(arr[i]);
}

//增强for循环
//把arr数组中的元素 依次取出 并赋值给i
for(int i : arr){
    System.out.println(i);
}

常见异常

            1.  下标越界异常 java.lang.ArrayIndexOutofBoundsException
                 比如数组中就三个元素, 最后一个下标就是2 ,而要输出下标为3或直接负数     就不行

            2.  空指针异常 java.langNullPointerException
                 使用null值 , 访问属性 , 因为是null ,所以没有堆内存存数据空间
                 所以是找不到数据对象的 , 自然就没办法操作数组

                 null 什么都没有 , 堆内存对象也没有
                 null 和 长度为 0 是两个概念

public static void main(String[] args){
    int[] arr1 = {1,2};
    // java.lang.ArrayIndexOutofBoundsException: 2
    System.out.println(arr1[2]);

    int[] arr2 = null;
    // java.langNullPointerException
    System.out.println(arr2[0]);
}

数组传递

            传值 和 传引用
                传值 : 基本类型 传递  传递的是值
                引用 : 引用类型 传递  传递的是地址

int i = 10;
m1(i);
System.out.println(i);
System.out.println("--------------");

int[] arr = { 1, 2, 3, 4, 5};
m2(arr);
System.out.println("--------------");
for(int j = 0; j < arr.length; j++){
    System.out.println(arr[j]);
}

public static void m1(int i){
    i = 20;
    System.out.println(i);
}

public static void m2(int[] i){
    i[0] = 20;
    for(int j = 0; j < arr.length; j++){
        System.out.println(i[j]);
    }
}

数组复制

实现

/**
*需求 : 把a数组中的某些数据 复制到 b数组中,并替换指定数据
*a = {1,2,3,4,5,6};
*b = {11,12,13,14,15,16};
*
*复制操作
*b = {11,2,3,4,15,16}
*
*a,1b,1,3
*数组替换式复制
*
*@param src
*       源数组
*@param srcPos
*       源数组起始位置(包含)
*@param dest
*       目标数组
*@param destPos
*       目标数组起始位置(包含)
*@param length
*       复制个数
*
*因为传引用, 并且也没有更改dest的长度 , 所以不需要返回值
*/
public static void arrayCopy(int[] src, int srcPos, int[] dest, int destPos, int length){
    for(int i = 0; i < length; i++){
        dest[destPos++] = src[srcPos++];
    }
}

int[] src = {1,2,3,4,5,6};
int[] dest = {11,12,13,14,15,16};
arrayCopy(src, 1, dest, 2, 3);
for(int i = 0; i < dest.length; i++){
    System.out.println(dest[i]);
}

APL

            并不是什么功能都要自己去编写和实现
            很多常用的功能 , 都已经写好了直接调用即可      就比如说刚才编写的数组替换复制

//源数组,起始索引(包含),目标数组,起始索引(包含),复制个数
System.arraycopy(sec, 1, dest, 2, 3);

插入式复制

            插入式复制 , 肯定需要更改长度大小 , 所以要新建数组
            所以要把新数组返回
            所以需要把新数组返回
             
            1  新数组长度
            2  复制逻辑
                   1  目标数组  起始位置和之前的数据 先复制到新数组中
                   2  把源数组起始位置开始 复制length个 到新数组中
                   3  目标数组 起始位置之后的数据复制到新数组中
            3  返回新数组

二维数组

声明方式

// 静态声明二维数组
int[][] arr = {
    {1,2,3},
    {11,12,13,14},
    {0},
    {1,11,13,25,769,9,9,9,45}
};

            二维数组的动态声明 : 
                   int[][] arr = new int[5][3];
                   二维数组中 有5个一维数组 , 并且每个一维数组中有3个元素

public static void main(String[] args){
    int[][] arr = new int[5][3];
    arr[2][2] = 1;
    for(int i = 0; i < arr.length; i++){
        System.out.print(arr[i][j]+"  ");
    }
    System.out.println();
}

            int[][] arr = new int[5][];
            二维数组中有5个一维数组 , 且每个一维数组都是空的
            需要单独对每个一维数组进行设置

public static void main(String[] args){
    int[][] arr1 = new int[5][];
    //初始化一维数组
    for(int i = 0; i < arr1.length; i++){
        arr1[i] = new int[i+1];
    }
    for(int i = 0; i < arr1.length; i++){
        for(int j = 0; j < arr1[i].length; j++){
            System.out.print(arr1[i][j]+"  ");
        }
        System.out.println();
    }
}

使用方式

//获取第一个一维数组
int[] arr0 = arr[0];
int arr00 = arr0[0];
System.out.println(arr00);
//第一个数组中的第一个元素
System.out.println(arr[0][0]);
//最后一个数组中的最后一个元素
System.out.println(arr[3][4]);

int[] arr3 = arr[arr.length-1];
int arr34 = arr3[arr3.length-1];
System.out.println(arr[arr.length-1][arr[arr.length-1].length-1]);

//遍历二维数组
for(int i = 0; i < arr.length; i++){
    //int[] arri = arr[i];
    for(int j = 0; j < arr[i].length; j++){
        System.out.print(arr[i][j]+"  ");
    }
    System.out.println();
}

Scanner

//接收用户输入
Scanner s = new Scanner(System.in);

//程序执行到这里,就会进入等待状态,等待用户输入
//并把输入的数据 返回 并赋值给变量suerInput
//多个数据以空格隔开
String userInput = s.next();
System.out.println(userInput+“-----------”);

//接受一行数据,不需要分隔符
String userInput = s.nextLine();
Syetem.out.println(userInput);

//接收整型,必须是纯数字,小数点也不行 java.util.InputMismatchException
int userInput = s.nextInt();
Syetem.out.println(userInput);

//接收小数,可以有一个小数点
double userInput = s.nextDouble();
System.out.println(userInput);

排序

交换变量的值

// 1 中间变量(开发常用)
int x = 10;
int y = 20;
int temp = x;
x = y;
y = temp;
System.out.println(x+":"+y);

// 2 位移运算(面试常用)
//转换为对应的二进制,然后每位进行疑惑,相同为0,不同为1
//0010
//0011
x = 2;
y = 3;
x = x ^ y;
//0001
//0011
y = x ^ y;
//0001
//0010
x = x ^ y;
//0011
//0010
System.out.println(x+":"+y);

// 3 加减运算
x = 10;
y = 20;
x = x + y;
y = x - y;
x = x - y;
System.out.println(x+":"+y);

冒泡排序

            1  比较相邻的两个元素 , 如果第一个比第二个大,就交换位置
            2  对每一对相邻的元素做相同的比较工作 , 这样比较完一轮之后 , 最后一个元素一定是最大的
            3  再重复执行上面的步骤, 除了最后一个元素(比较次数依次递减)
            4  一直到没有任何一对元素 , 终止
        
            嵌套循环
                1  外层循环决定比较多少轮
                2  内层循环决定每轮比较的次数

public static void main(String[] args){
    int[] arr = {1,2,3,4,5,7};
    bubbleSort(arr);
    for(int i = 0; i < arr.length; i++){
        System.out.println(arr[i]);
    }
}

public static void bubbleSort(int[] arr){
    for(int i = 0; i < arr.length-1; i++){
        for(int j = 1; j < arr[i].length-1-i; j++){
            if(arr[j] < arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

选择排序

            每次都把其中最小的元素放到左边

public static void selectSort(int[] arr){
    for(int i = 0; i < arr.length; i++){
        //min是最小的元素下标,默认假设i就是最小的
        int min = i;
        for(int j = i+1; j < arr.length; j++){
            //有比min还小的数的时候,就把该数的下标赋值给min
            if(arr[min > arr[j]){
                min = j;
            }
        }
    }
    
    //判断i是否是最小的
    //只要min不等于i说明 有比i小的
    if(min != i){
        int temp = arr[min];
        arr[min] = arr[i];
        arr[i] = temp;
    }
}

API

int[] arr = {1,5,4,2,3};
Arrays.sort(arr);
for(int i = 0; i < arr.length; i++)
    System.out.println(arr[i]);

类、对象、构造器、封装

面向对象

            概述 : 
                面向对象是软件开发方法,一种编程范式. 面向对象是一种对现实世界理解和抽象的方法 , 是计算机编程技术发展到一定阶段后的产物
                面向对象是相对于面向过程来讲的 , 面向对象方法 , 吧相关的数据和方法组织为一个整体来看待 , 从更高的层次来进行建模,更贴近事物的自然运行模式

面向过程

            侧重分步骤 , 类似于公司的扁平化管理
            比如  五子棋
            面向过程的设计思想就是首先分析问题 : 
                   1 开始游戏
                   2 黑子先走
                   3 绘制画面
                   4 判断输赢
                   5 白子走
                   6 绘制画面
                   7 判断输赢
                   8 重复进行 , 依次类推

面向对象

            侧重分模块 , 类似于公司的层级管理
            比如五子棋
            用面向对象的思维来思考
                五子棋可分为 :
                   1 白黑双方 , 行为规范一直 , 形成棋子系统
                   2 棋盘系统 绘制画面
                   3 规则系统  比如判断输赢 是否违规等操作
            面向对象是以功能划分的 而不是步骤划分    类似于炒饭和盖饭,盖饭就等于 是面向对象,饭菜分离,可以任意组合,耦合度降低
            优点 : 维护简单 , 可扩展性 , 可重用性

类和对象

     对象 :
            代码角度 : new的实例化某一个类的实例 , 封装特有的数据
            数据角度 : 封装数据和逻辑的一种方式
            人类认知角度 : 对象就是具体的个体 , 一切皆对象
            设计角度 : 从一个实际的实体抽象某些属性的一种实体表示


            概念/ 定义 : 使我们在思想上对某一个东西 , 或者某一类东西的唯一性标识
            描述了这一类事物的特性
            是我们对客观事物描述的一个标准和模板


            类定义标准和模板 , 而对象就是符合这个表示这个标准的个体


            我们抽离某个概念 , 就能建立相关事物的类 , 一定通过类中的属性来形成这个概念 , 然后通过这些个属性来形成类 , 通过不同的属性值来形成不同的个体(对象)
            通过不同的属性 , 划分不同的类, 通过不同的属性值 , 划分不同的个体
            从类到对象的过程 , 可以理解为对成员变量赋值的过程
  

    堆内存 :
            每个对象空间分为3块
                1 数据区域 : 成员变量
                2 头部 : hash值
                3 类型 : 静态区类文件的空间引用

什么时候使用静态变量 , 什么时候使用成员变量

            静态变量是类级别的 , 对象无关 , 静态变量的属性和值 , 是所有对象都一致
            成员变量是对象级别的 , 它们拥有相同的属性 , 但值可以相同也可以不同

对象的使用和特征

JVM特性

            跨平台   多线程   自动垃圾回收   面向对象
            垃圾 : 没有更多引用指向这个对象(谁也找不到) , 该对象被视为垃圾数据 等待被回收
            从类到对象的过程 , 可以理解为对成员变量赋值的过程

面向对象特性

            继承性  封装性  多态性  抽象

对象使用

//创建对象
Star star = new Star();
//调用成员变量
System.out.println(star.age);
//没有name变量,所以不可以调用
//System.out.println(star.name);
star.test();
//所以引用数据类型都可以赋值为null
star = null;
//使用null 访问成员属性 会报错 空指针异常
System.out.println(star.age);

常见异常

            空指针是运行时异常 , 编译时不报错,一般因为粗心导致
           
            空指针 , 只要是空指针 , 说明使用null 调用了成员属性

JavaBean

            1 公共类
            2 私有属性
            3 getter/setter 方法
            4 构造方法

private int age;
String addr;
String sex;

public void setAge(int age1){
    if(age1 <= 0)
        age = 1;
    else
        age = age1;
}

public int getAge(){}

传引用

        传值和传引用
            传值 : 传递基本数据类型
            传引用 : 传递引用数据类型

public static void main(String[] args){
    int i = 10;
    m1(i);
    System.out.println(i);
    System.out.println("-----------");
    Animal a = new Animal();
    a.age = 10;
    m2(a);
    System.out.println(a.age);
}

public static void m1(int i){
    i++;
    System.out.println(i);
}

public static void m2(Animal a){
    // a = new Animal();
    a.age++;
    System.out.println(a.age);
}

构造方法

            编译器功能 :  
                 1 把java文件编译成class文件
                 2 检查语法结构是否合法
                 3 帮我们把不规范的代码,补齐
                        比如 静态变量,需要类名调用,但是一般我们调用当前类中的静态变量的时候,不会加类名
                        此时 编译器 就会自动帮我们加上(如果我们不加类名访问,编译器自动帮我们加上当前类的类名)
                        另外就是构造方法,如果类中没有显示声明构造方法的话,则编译器会自动帮我们创建一个公共的无参构造
 
            构造方法 :    创建当前类的实例化对象,并初始化成员属性
 
             语法 :    [权限修饰]  类名(参数列表){ 方法体 }        public,private这些

              如果我们不定义构造方法,则默认有一个公共的无参构造( public 类名(){} )

              一旦我们指定了构造方法,则默认的无参构造就没有了    所以 一般我们需要指定构造方法的时候,要考虑再写一个无参构造
 
             构造方法重载 : 可以根据需求,编写多个构造方法,方法名相同,参数列表不同(个数,类型)

class Student{
    Sting name;
    int age;
    /// 需求 : 学生必须有name属性的值, age可以有,可以没有
    public Student(String name1){
        name = name1;
    }
    public Student(String name1,int age1){
        name = name1;
        age = age1;
    }
}

构造方法和成员方法

public class Constructor_02{
    public void Constructor_02(int i){}

    public Constructor_02(){}
}

public static void main(String[] arge){
    new Constructor_02();
    // 构造方法可以和成员方法同名
    // 就看返回值即可 , 因为构造方法没有返回值,脸void都没有
    // new COnstructor_02(10);
}

This

This是什么

     this关键字 :
            this 是每个对象中 , 保存自身内存地址的一个引用类型的成员变量
            this 就表示这个对象 , this 的类型就是当前类的类型
               当前类: this所在的类 , 就是当前类
            只能出现在成员方法和构造方法中 , 不能出现在静态方法中
                   谁调用的这个成员方法 , this就是谁

            

能干什么

     功能 :
            1 用在成员方法/构造方法中 , 用来区别同名的成员变量和局部变量   this.xxxxx
            2 用在构造方法中 , 重载调用当前类的其它构造方法
                       this(参数); 必须写在构造方法的第一行
            3 return this ; 可以返回当前对象的内存地址 , 以此做到链式调用

This怎么用

区分局部变量和成员变量

class MyDate{
    int year;
    int month;
    int day;
    public void setDay(int day){
        this.day = day;
    }
    
    public MyDate(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }
}

            如何区分同名的局部变量和静态变量?       类名.静态变量名
            如何区分同名的局部变量和成员变量?       this.成员变量名

重载调用其他构造方法

public MyDate(){
    //this.year = 1970;
    //this.month = 1;
    //this.day = 1;
    //重载调用下面的有参构造,必须在构造方法的第一行
    this(1970,1,1)
}

public MyDate(int year, int month, int day){
    this.year = year;
    this.month = month;
    this.day = day;
}

链式调用

public static void main(String[] args){
    This_03 t = new This_03();
    t.m1();
    t.m2();
    // 因为m1返回值是This_03类型,所以须使用This_03来接收
    This_03 t2 = t.m1();
    t2.m2();
    // 返回this可以链式调用当前类中的成员方法
    t.m1().m2();

    // 返回其他类的对象 , 就可以链式调用其他类中的方法
    t.m3().cahrAt(1);
}

public String m3(){
    return "giuhnfkjsnjifhi211125";
}

public This_03 m1(){
    System.out.println(1);
    return this;
}

public This_03 m2(){
    System.out.println(2);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值