全栈 -- backEnd学习笔记

1. 面向对象编程(基础部分)

1.1 入门 hello world

public class Main {
    public static void main(String[] args) {
        System.out.println("hello,world");
    }
}

1.2 转义字符

class changeChar {
    public static void main(String[] args) {
        // \t :一个制表位,实现对齐的功能
        // \n :换行符
        // \\ :一个\
        // \" :一个"
        // \' :一个' \r :一个回车
        System.out.println("书名\t 作者\t价格\t 销量\n三国\t 罗贯中 \t120\t 1000");
    }
}

1.3 数据类型

一、基本数据类型:

  1. 数值型
    1.1 整数类型:存放整数,( byte【1】;short【2】;int【4】;long【8】
    1.2 浮点(小数)类型:( float【4】;double【8】
  2. 字符型( char【2】),存放当个字符
  3. 布尔类型( boolean【1】),存放true , false

二、引用数据类型

  1. 类( class )
  2. 接口( interface )
  3. 数组( [] )
class dataType {
    public static void main(String[] args) {
        char num = 'a' + 1;  // a 对应的 UNICODE编码为 97
        System.out.println((int) num); // 98
        System.out.println(num); // 98 => 对应的字符为 b
    }
}

1.4 自动类型转换

  1. 自动类型转换:当java程序进行赋值或运算时,精度低的类型自动转换为精度高的数据类型
    (1) char => int => long => float => double
    (2) byte => short => int => long => float => double
  2. 注意事项:
    1)有多种类型的数据混合运算时,系统首先自动将所有数据转换成最高的那种数据类型,然后再进行运算
    2)当我们把精度(容量)高的数据类型赋值给精度(容量)低的数据类型时,就会报错,反之就会进行自动类型转换
    3)byte,short二者与 char 不存在相互自动转换
    4)byte,short,char三者可以计算,在计算时首先转换为 int类型
    5)boolean不参与转换
    6)自动提升原则:表达式结果的类型自动提升为 操作数中最高的数据类型

1.5 运算符

运算符的优先级
1. .  ()  {}  ;  ,
2. 单目运算符
3. 算数运算符
4. 位移运算符
5. 比较运算符
6. 逻辑运算符
7. 三元运算符
8. 赋值运算符

1.6 标识符的命名规范

  1. 包名:多单词组成时所有字母都小写:aaa.bbb.ccc
    比如 com.hsp.crm
  2. 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz [大驼峰]
    比如: TankShotGame
  3. 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz [小驼峰, 简称 驼峰法]
    比如: tankShotGame
  4. 常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ
    比如 :定义一个所得税率 TAX_RATE

1.7 键盘输入语句

import java.util.Scanner; // 1. 引入相应的java包,表示把 java.util 下的 Scanner类(简单文本扫描器) 导入

public class Lesson85_174 {
    public static void main(String[] args) {
        // 2.创建 Scanner对象,new 创建一个对象
        Scanner myScanner = new Scanner(System.in);
        // 3. 接收用户输入了, 使用 相关的方法
        System.out.println("请输入名字");
        // 当程序执行到 next 方法时,会等待用户输入~~~
        String name = myScanner.next(); // 接收用户输入字符串
        System.out.println("请输入年龄");
        int age = myScanner.nextInt(); // 接收用户输入 int
        System.out.println("请输入薪水");
        double sal = myScanner.nextDouble(); // 接收用户输入 double
        System.out.println("人的信息如下:");
        System.out.println("名字=" + name + " 年龄=" + age + " 薪水=" + sal);
    }
}

1.8 流程控制语句

在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句。

  1. 顺序控制
  2. 分支控制 2.1 if-else 2.2 switch-case
  3. 循环控制 3.1 for循环 ; 3.2 while循环 ; 3.3 do…while循环
// 2.1 分支控制 if-else
class ConditionDemo {
    public static void main(String[] args) {
        Scanner conditionScanner = new Scanner(System.in);
        System.out.println("请输入年龄");
        int age = conditionScanner.nextInt();
        if (age > 18) {
            System.out.println("您已成年");
        } else if (age == 18) {
            System.out.println("您刚满18岁,已成年");
        } else {
            System.out.println("未成年");
        }
    }
}

// 2.2 分支控制 switch-case
class ConditionDemo2 {
    public static void main(String[] args) {
        Scanner monthScanner = new Scanner(System.in);
        System.out.println("请输入月份");
        int month = monthScanner.nextInt();
        switch (month) {
            case 3:
            case 4:
            case 5:
                System.out.println("春季");
                break;
            case 6:
            case 7:
            case 8:
                System.out.println("夏季");
                break;
            case 9:
            case 10:
            case 11:
                System.out.println("秋季");
                break;
            case 12:
            case 1:
            case 2:
                System.out.println("冬季");
                break;
            default:
                System.out.println("输入有误");
        }
    }
}

1.9 流程控制语句附加

1) break 语句用于终止某个语句块的执行,一般使用在 switch 或者循环[for , while , do-while]中
2) continue 语句用于结束本次循环,继续执行下一次循环;
continue 语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这个和前面的标签的使用的规则一样。
3)return 使用在方法,表示跳出所在的方法

1.10 数组 {}

动态初始化:
数据类型 数组名[] = new 数据类型[大小]; ( 写法2:数据类型[] 数组名 = new 数据类型[大小]; )

静态初始化:
数据类型 数组名[] = { 元素1,元素2,… }

注意事项:

  1. 数组是多个相同类型数据的组合,实现对这些数据的统一管理; ( 同样遵守自动类型转换规则 )
  2. 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用;
  3. 数组创建后,如果没有赋值,有默认值
    int 0, short 0, byte 0, long 0, float 0.0, double 0.0, char \u0000, boolean false, String null 。
class ArrayDemo {
    public static void main(String[] args) {
        // double arrayList[] = new double[5]; // 动态初始化
        double arrayList[] = {1.0, 2.0, 3.0, 4.0, 27}; // 静态初始化
        int i = 0;
        for (; i < 5; i++) {
            System.out.println("数组的第" + i + "项" + arrayList[i]);
            // if (i == 3) {
            //    return; // break; / continue;
            // }
            // System.out.println("test~~");
        }
        System.out.println("go on...");
    }
}

1.11 数组的赋值机制

  1. 基本数据类型赋值,这个值就是具体的数据,而且相互不影响。
    int n1 = 2; int n2 = n1;
  2. 数组在默认情况下是引用传递,赋的值是地址,会相互影响。( 堆栈存储方式:栈中存放地址,值存放在堆中。 )
    int[] arr1 = {1,2,3}; int[] arr2 = arr1;

1.12 数组的拷贝

// 正确数组拷贝方式是通过数组遍历的方式来实现的。
class ArrAyCopy {
    public static void main(String[] args) {
        int arrayList[] = {1, 2, 3};
        int arrayList2[] = new int[arrayList.length];

        // 要求:拷贝一份 arrayList 给 arrayList2,二者数据不会相互影响
        // arrayList2 = arrayList; // 错误方式,直接赋值,赋值的是栈中的地址,指向共同的存放数据的堆

        for (int i = 0; i < arrayList.length; i++) {
            arrayList2[i] = arrayList[i];
        }

        for (int i = 0; i < arrayList.length; i++) {
            System.out.println("arrayList:第" + i + "项" + arrayList[i]);
            System.out.println("arrayList2:第" + i + "项" + arrayList2[i]);
        }

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

        arrayList2[1] = 20;
        for (int i = 0; i < arrayList.length; i++) {
            System.out.println("arrayList:第" + i + "项" + arrayList[i]);
            System.out.println("arrayList2:第" + i + "项" + arrayList2[i]);
        }
    }
}

1.13 数组反转

数组延伸

  1. 数组扩容 ;
  2. 数组缩减( 思路类似于 方法2 )
  3. 数组排序
    3.1 冒泡排序
  4. 数组查找
    4.1 顺序查找
    4.2 二分查找【二分法】

class ArrayReverse {
    public static void main(String[] args) {
        int arrayList[] = {1, 2, 3, 4, 5, 6};

        // 方法1:
        // for(int i=0;i<arrayList.length/2;i++){
        // int saveItem = arrayList[arrayList.length-1-i];
        // arrayList[arrayList.length-1-i] = arrayList[i];
        //  arrayList[i] = saveItem;
        // }

        // 方法2:
        int arrayList2[] = new int[arrayList.length];
        for (int i = arrayList.length - 1, j = 0; i >= 0; i--, j++) {
            arrayList2[j] = arrayList[i];
        }

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

            System.out.println(arrayList2[i]);
        }
    }
}

1.14 多维数组 - 二维数组

动态初始化:( 注:列数不确定时,new 数据类型[大小][] )
写法1:数据类型 数组名[][] = new 数据类型[大小][大小];
写法2:数据类型[][] 数组名 = new 数据类型[大小][大小];
写法3:数据类型[] 数组名[] = new 数据类型[大小][大小];
例:int[] x,y[]; // x是int类型的一维数组,y是int类型的二维数组

静态初始化:
数据类型 数组名[][] = {{ 元素1,元素2,… }, { 元素1,元素2,… }, { 元素1,元素2,… }}

public class Lesson175_226 {
    public static void main(String[] args) {
//        需求:动态创建下面二维数组,并输出
//        i = 0: 1
//        i = 1: 2 2
//        i = 2: 3 3 3

        int arrList[][] = new int[3][]; // new int[3][] ,列数不确定
        for (int i = 0; i < arrList.length; i++) {
            arrList[i] = new int[i + 1];
            for (int j = 0; j < arrList[i].length; j++) {
                arrList[i][j] = i + 1;
            }
        }

        for (int i = 0; i < arrList.length; i++) {
            for (int j = 0; j < arrList[i].length; j++) {
                System.out.print(arrList[i][j] + "\t");
            }
            System.out.print("\n");
        }
    }
}

1.15 面向对象

  1. 类和对象
    1.1 语法定义:
    1) 声明类:
  class Person {
   // 属性;成员变量;field字段;
  数据类型 属性名称;
 };

2)创建对象:

Person p1 = new Person();

1.2 注意事项:

  1. 属性的定义语法同变量,示例:访问修饰符 属性类型 属性名;
    这里简单的介绍访问修饰符: 控制属性的访问范围
    有四种访问修饰符 public, proctected, 默认, private ,后面我会详细介绍
  2. 属性的定义类型可以为任意类型,包含基本类型或引用类型
  3. 属性如果不赋值,有默认值,规则和数组一致。具体说:
    int 0,short 0, byte 0 , long 0 , float 0.0, double 0.0,char \u0000,boolean false,String null
  1. 成员方法( 方法 )
    2.1 语法定义:
 访问修饰符 返回数据类型 方法名(形参列表..) {//方法体
            语句;
   return 返回值;
 }

2.2 注意事项:
√ 访问修饰符 (作用是控制 方法使用的范围)
如果不写默认访问,[有四种: public, protected, 默认, private], 具体在后面说
√ 返回数据类型

  1. 一个方法最多有一个返回值 [思考,如何返回多个结果 返回数组 ]
  2. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
  3. 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值; 而且要求返回值类型必须和 return 的
    值类型一致或兼容
  4. 如果方法是 void,则方法体中可以没有 return 语句,或者 只写 return ;

√ 方法名
遵循驼峰命名法,最好见名知义,表达出该功能的意思即可, 比如 得到两个数的和 getSum, 开发中按照规范

√ 形参列表
1)一个方法可以有0个参数,也可以有多个参数,中间用逗号隔开
2)参数类型可以为任意类型,包含基本类型或者引用数据类型
3)调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数(兼容:就是遵循自动类型转换规则)
4)方法定义时的参数称为形式参数,简称形参;方法调用时传入的参数称为实际参数,简称实参;实参和形参的类型要一致或兼容、个数、顺序也必须一致!

√ 形参列表
里面写 完成功能的具体的语句,可以为输入、输出、变量、运算、分支、循环、方法调用,但里面不能再定义方法!即:方法不能嵌套定义。

√ 方法调用细节说明(!!!)
1)同一个类中的方法调用:直接调用即可。
2)跨类中的方法 A类 调用 B类方法:需要通过对象名调用。
3)跨类的方法调用和方法的访问修饰符相关。

class ObjectFace {
    public static void main(String[] args) {
        // 创建 Information 对象
        // person01 是对象名(对象引用)
        // new Information() 创建的对象空间(数据) 才是真正的对象
        Information person01 = new Information();
        person01.name = "张三";
        person01.sex = '0';
        person01.age = 18;
        person01.weight = 100;
        System.out.println("person01 姓名:" + person01.name + " " + "性别:" + person01.sex + " " + "年龄:" + person01.age + " " + "体重:" + person01.weight);
        Information person02 = person01;
        System.out.println("person02 姓名:" + person02.name);

        person01.speaking();
        // 这里调用传的参数称为 实参
        int sum = person01.getSum(20, 7);
        System.out.println("求两个数的和为:" + sum);
    }
}

class Information {
    // 190.1 类和对象
    // 属性;成员变量;field字段;
    String name;
    byte sex;
    int age;
    double weight;

    // 190.2 成员方法( 方法 )
    // 解读:
    //1. public 表示方法是公开
    //2. void : 表示方法没有返回值
    //3. speak() : speak 是方法名, () 形参列表
    //4. {} 方法体,可以写我们要执行的代码
    //5. System.out.println("我是一个好人"); 表示我们的方法就是输出一句话
    public void speaking() {
        System.out.println("成员方法 speaking()");
    }

    // 解读:
    //1. public 表示方法是公开的
    //2. int :表示方法执行后,返回一个 int 值
    //3. getSum 方法名
    //4. (int num1, int num2) 形参列表,2 个形参,可以接收用户传入的两个数
    //5. return res; 表示把 res 的值, 返回
    public int getSum(int num1, int num2) {
        return num1 + num2;
    }
}

1.16 成员方法传参机制(非常重要)

  1. 基本数据类型的传参机制
    基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参!
  2. 引用数据类型的传参机制
    引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参!(如果要编写一个方法复制一个对象,使得这个复制的对象与原对象不相互影响,可以在方法体, 创建一个新对象,并复制属性,返回即可)
class MethodExercise02 {
    //编写一个 main 方法
    public static void main(String[] args) {
        //编写一个方法 copyPerson,可以复制一个 Person 对象,返回复制的对象。克隆对象,
        //注意要求得到新对象和原来的对象是两个独立的对象,只是他们的属性相同

        Person p = new Person();
        p.name = "张三";
        p.age = 10;

        MyTools tools = new MyTools();
        Person p2 = tools.copyPerson(p);
        p2.name = "李四";
        p2.age = 20;

        System.out.println("p 的属性 名字=" + p.name + " age=" + p.age);
        System.out.println("p2 的属性 名字=" + p2.name + " age=" + p2.age);
        //对象比较看看是否为同一个对象
        System.out.println(p == p2);//false
    }
}

class Person {
    String name;
    int age;
}

class MyTools {
    //编写方法的思路
    //1. 方法的返回类型 Person
    //2. 方法的名字 copyPerson
    //3. 方法的形参 (Person p)
    //4. 方法体, 创建一个新对象,并复制属性,返回即可
    public Person copyPerson(Person p) {
    //创建一个新的对象
        Person p2 = new Person();
        p2.name = p.name;
        p2.age = p.age;
        return p2;
    }
}

1.17 方法递归调用( 非常重要 )

递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题,同时可以让代码变得简洁

递归的重要规则
1)执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
2)方法的局部变量是独立的,不会相互影响
3)如果方法中使用的是引用类型变量(比如数组、对象),就会共享该引用类型的数据
4)递归必须向退出递归的条件逼近,否则就是无限递归,出现 stackOverflowError,死龟( 栈溢出 )
5)当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕

class Recursion01 {
    //编写一个 main 方法
    public static void main(String[] args) {
        T t1 = new T();
        // 案例1:输出什么?
        t1.test(4);   // n=2 n=3 n=4

        // 案例2:阶乘
        int res = t1.factorial(5);
        System.out.println("5 的阶乘 res =" + res); // 120
        // n=                   5                4                     3                2                1
        // 执行顺序按箭头方向执行
        //                === 递归调用带入 n 的值 得到如下所示 === >
        // return=   factorial(4) * 5   factorial(3) * 4    factorial(4) * 3    factorial(4) * 2         1
        //                < === 然后再通过每次的return 累计想乘 ===
        // res=                1                 2                      6               24              120
    }
}
class T {
    public void test(int n) {
        if (n > 2) {
            test(n - 1);
        }
        System.out.println("n=" + n);
    }

    //factorial 阶乘
    public int factorial(int n) {
        if (n == 1) {
            return 1;
        } else {
            return factorial(n - 1) * n;
        }
    }
}

1.18 方法重载( OverLoad )

java 中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致!

√ 注意事项( 触发方法重载的必要条件 )
1)方法名:必须相同
2)形参列表:形参类型 或 个数 或 顺序,至少有一样不同,形参名称无要求
3)返回类型:无要求

√ 重载的好处:

  1. 减轻了起名的麻烦
  2. 减轻了记名的麻烦
public class Lesson227_262 {
    public static void main(String[] args) {
        sumClass result = new sumClass();

        // 方法重新,会根据传入的参数 自动匹配到对应的 sum方法
        System.out.println("result=" + " " + result.sum(1, 1));
        System.out.println("result=" + " " + result.sum(1.1, 1));
        System.out.println("result=" + " " + result.sum(1.1, 1));
        System.out.println("result=" + " " + result.sum(1.1, 1, 3));
    }
}

class sumClass {
    public int sum(int a, int b) {
        System.out.println("111");
        return a + b;
    }

    ;

    public double sum(double a, int b) {
        System.out.println("222");
        return a + b;
    }

    ;

    public double sum(double a, int b, int c) {
        System.out.println("333");
        return a + b + c;
    }

    ;
}

1.19 可变参数

java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。就可以通过可变参数实现
√ 基本语法
访问修饰符 返回类型 方法名(数据类型… 形参名) {}
√ 注意事项
1)可变参数的实参可以为 0个或任意多个 ( 数据类型… 形参名 被称为可变参数 )
2)可变参数的实参可以为数组
3)可变参数的本质就是数组
4)可变参数可以和普通参数一起放在形参列表,但必须保证可变参数在最后
5)一个形参列表中只能出现一个可变参数

class changeParams {
    public static void main(String[] args) {
        betterSumClass betterSum = new betterSumClass();
        System.out.println("sum=" + betterSum.sum(1, 2, 3));
        System.out.println("sum=" + betterSum.sum(1.1, 2, 3.3, 4, 5.5));
    }
}

class betterSumClass {
    // 上面 sumClass类 中的 sum方法重载 代码太过冗余,优化如下:
    public double sum(double... params) {
        double result = 0;
        for (int i = 0; i < params.length; i++) {
            result += params[i];
        }
        return result;
    }
}

1.20 作用域

√ 基本使用
1)在java编程中主要的变量就是 属性(成员变量) 和 局部变量
2)局部变量一般指在成员方法中定义的变量。
3)java中作用域的分类:
3.1 全局变量:也就是属性,作用域为整个类体
3.2 局部变量:也就是除了属性之外的其他变量,作用域为定义他的代码块中
4)全局变量(属性)可以不赋值,直接使用,因为会有默认值;局部变量必须赋值后才能使用,因为没有默认值

√ 注意事项
1)属性和局部变量可以重名,访问时遵循就近原则
2)在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名
3)属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁;
局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁,即在一次方法调用过程中
4)作用域范围不同
全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
局部变量:只能在本类中对应的方法中使用
5)修饰符不同
全局变量/属性 可以加 修饰符(public protected private…)
局部变量 不可以加 修饰符

class VarScopeDetail {
    public static void main(String[] args) {
        Per p1 = new Per();
        /*
        属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。
        局部变量,生命周期较短,伴随着它的代码块的执行而创建,
        伴随着代码块的结束而销毁。即在一次方法调用过程中
        */
        //p1.say();//当执行 say 方法时,say 方法的局部变量比如 name,会创建,当 say 执行完毕后
        //name 局部变量就销毁,但是属性(全局变量)仍然可以使用

        Ts t1 = new Ts();
        //全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
        t1.test(); //第 1 种跨类访问对象属性的方式

        t1.test2(p1);//第 2 种跨类访问对象属性的方式
    }
}

class Ts {
    public void test() {
        Per p1 = new Per();
        System.out.println(p1.name);//jack
    }

    //
    public void test2(Per p) {
        System.out.println(p.name);//jack
    }
}

class Per {
    //细节: 属性可以加修饰符(public protected private..)
    public int age = 20;
    String name = "jack";

    public void say() {
        // 局部变量不能加修饰符
        // public int age = 20;

        //细节 属性和局部变量可以重名,访问时遵循就近原则
        String name = "king";
        System.out.println("say() name=" + name);
    }

    public void hi() {
        String address = "北京";
        //String address = "上海";//错误,重复定义变量
        String name = "hsp";//可以
    }
}

1.21 构造方法/构造器

构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:

基本语法

[修饰符] 方法名(形参列表){
     方法体;
}

说明:

  1. 构造器的修饰符可以默认, 也可以是 public protected private
  2. 构造器没有返回值
  3. 构造方法名 和类名字 必须一样
  4. 参数列表 和 成员方法 一样的规则
  5. 在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。( 构造器的调用, 由系统完成 )

√ 注意事项

  1. 一个类可以定义多个不同的构造器,即构造器重载
  2. 构造器是完成对象的初始化,并不是创建对象
  3. 如果程序没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器,比如: Cat(){} )
  4. 一旦定义了自己的构造器,默认的构造器就被覆盖了,就不能再使用默认的无参构造器,除非显式的再定义一下,即 Cat(){}()
class Constructor {
    public static void main(String[] args) {
        // /当 new 一个对象时,直接通过构造器设置 名字和年龄 初始值
        Cat c = new Cat("Tom", 18);
        System.out.println("名字=" + c.name + " " + "年龄=" + c.age); // 名字=Tom 年龄=0
    }
}

class Cat {
    String name;
    int age;

    //  系统自动生成的 默认构造器,但是在下面 Cat(String reName, int reAge){ ... } 定义后,此默认器会被覆盖,要想继续使用需再次定义
    //  Cat(){
    //    }
    // 构造方法/构造器
    public Cat(String reName, int reAge) {
        System.out.println("构造方法触发~~");
        name = reName;
        reAge = reAge;
    }
}

1.22 this 关键字

哪个对象调用,this就代表哪个对象

√ 注意事项:

  1. this 关键字可以用来访问本类的属性、方法、构造器
  2. this 用于区分当前类的属性和局部变量
  3. 访问成员方法的语法:this.方法名(参数列表);
  4. 访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一
    条语句)
  5. this 不能在类定义的外部使用,只能在类定义的方法中使用。

class thisKey {
    public static void main(String[] args) {
        dog t1 = new dog("Bob", 8);
        // 没使用 this时,此处打印的 name=null age=0
        // 使用 this 后
        System.out.println("name=" + t1.name + " " + "age=" + t1.age); // name=Bob age=8

        dog t2 = new dog("Buluto", 3);
        // System.out.println("name=" + t2.name + " " + "age=" + t2.age); // name=Buluto age=3
    }
}

class dog {
    String name;
    int age;

    public dog(String name, int age) {
        // name = name;
        // age = age;

        // 在没有改变 对象的属性值时,都为默认值或初始值
        System.out.println("this.name=" + this.name + " " + "this.age=" + this.age); // this.name=null this.age=0
        System.out.println("name=" + name + " " + "age=" + age); // name=Bob age=8

        this.name = name;
        this.age = age;
    }
}

1.23 IDEA编程工具相关

快捷键使用:
1)自动的分配变量名 , 通过 在后面假 .var
2)自动生成构造器、设置/获取属性值 等 alt + insert
3)补全代码 alt + /
4)导入该行需要的类 先配置 auto import , 然后使用 alt+enter 即可
5)查看一个类的层级关系 ctrl + H [学习继承后,非常有用]
6)将光标放在一个方法上,输入 ctrl + B , 可以定位到方法 [学继承后,非常有用]

代码模版使用:
1)main ( 快速生成 main方法 )
2)fori ( 快速生成for循环 )
3)sout ( 快速生成打印语句 )
如果自己想添加其他代码模版:file -> setting -> editor -> Live templates

1.24 包

应用场景:在一个java项目中,想同时定义一个 相同名称的类时,可以使用包。
√ 包的本质(原理):包的本质实际上就是创建不同的文件夹/目录来保存类文件。

√ 包的基本语法
package com.studyPkg.demo
说明:1. package 关键字,表示打包 2. com.studyPkg.demo 表示包名

√ 包的命名
命名规则:只能包含数字、字母、下划线、小圆点(.),但是不能以数字开头,不能是关键字或保留字
命名规范:项目中一般是 小写字母 + 小圆点,com.公司名.项目名.业务模块名
比如: com.sina.crm.user; // 用户模块

√ 包的引入( 一般小圆点可以视为 文件路径中的 \ )
语法: import 包;
目的:我们引入一个包就是为了使用该包下的 类
例如:import java.util.Scanner; //引入一个 Scanner类

√ 注意事项
1)package 的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句 package
2)import 需放在 package 下面,在类定义前面,可以有多句 且 没有顺序要求
3)需要使用到哪个类,就导入哪个类即可,不建议使用 *导入

√ 常用的包
一个包下,包含很多的类,java 中常用的包有:

  1. java.lang.* // lang 包是基本包,默认引入,不需要再引入.
  2. java.util.* // util 包,系统提供的工具包, 工具类,使用 Scanner
  3. java.net.* // 网络包,网络开发
  4. java.awt.* // 是做 java 的界面开发,GUI

√ 包的三大作用:
1)区分相同名称的类
2)当类很多时,可以很好的管理类
3)控制访问范围

案例: com.studyPackage272.demo01.pkgUse        【 package:包 】

1.25 访问修饰符

√ 基本介绍
java 提供四种访问控制修饰符号,用于控制 方法和属性(成员变量) 的访问权限(范围):

  1. 公开级别:用 public 修饰,对外公开
  2. 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
  3. 默认级别:没有修饰符号,向同一个包的类公开.
  4. 私有级别:用 private 修饰,只有类本身可以访问,不对外公开.

√ 4种访问修饰符的访问范围

访问级别访问控制修饰符同类同包子类不同包
公开public
受保护protected×
默认无修饰符××
私有private×××

√ 注意事项
1)修饰符可以用来修饰类中的属性、成员方法 以及 类
2)只有 默认的 和 public 才能修饰类,并且遵循上述访问权限的特点
3)子类中的访问权限放在继承中讲解
4)成员方法的访问规则和属性完全一样

// 案例: com.studyModifier278.demo01.modifier01       【 modifier:修饰符 】

1.26 面向对象编程有三大特征:封装、继承 和 多态。

1.26.1面向对象编程三大特征 - 封装

√ 封装
封装就是把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作【方法】,才能对数据进行操作

√ 封装的实现步骤( 三步 )
1)将 属性 进行私有化 private 【 不能直接修改属性 】
2)提供一个公共的( public ) set方法,用于对属性判断并赋值

   public void setXxx(){
      // 加入数据验证的业务逻辑
         属性 = 参数名;
   }

3)提供一个公共的( public )get方法,用于获取属性的值

   public void getXxx(){
      // 加入权限判断的业务逻辑
         属性 = 参数名;
   }

√ 封装的好处
1)隐藏实现细节:方法 <-- 调用
2)可以对数据进行验证,保证安全合理

案例:com.studyEncapsulation.demo01.Account        【 encapsulation:封装 】

1.26.2 面向对象编程三大特征 - 继承

√ 继承
继承可以实现代码的复用。当多个类存在相同的属性(成员变量)和 方法时,可以从这些类中 抽象 出父类,父类中定义这些类中 相同的属性和方法,所有的子类
不需要重新定义这些属性和方法,只需要通过 extends来声明继承父类即可。

√ 基本语法

class 子类 extends 父类{
}

附加说明:
1)子类就会自动拥有父类定义的属性和方法
2)父类又叫 超类、基类
3)子类又叫派生类

√ 注意事项

  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访
    问,要通过父类提供公共的方法去访问
  2. 子类必须调用父类的构造器, 完成父类的初始化
  3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,
    则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
  4. 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
  5. super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
  6. super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
  7. java 所有类都是 Object 类的子类, Object 是所有类的基类. 8) 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
  8. 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。
    例如:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】
  9. 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系

5继承的好处

  1. 代码的复用性提高了
  2. 代码的扩展性和维护性提高了
// 案例:com.studyExtends.demo01.Human     【 extends:继承 】

1.26.3 super 关键字

√ 基本介绍
super代表父类的引用,用于访问父类的属性、方法、构造器
√ 基本语法

  1. 访问父类的属性,但不能访问父类的 private属性
    super.属性名;
  2. 访问父类的方法,但不能访问父类的 private方法
    super.方法名(参数列表);
  3. 访问父类的构造器,只能放在构造器的第一句,只能出现一句
    super(参数列表);

√ super的好处

  1. 调用父类的构造器的好处( 分工明确,父类属性由父类初始化,子类的属性由子类初始化 )
  2. 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this,直接访问是一样的效果
  3. super的访问不限于直接父类,如果爷爷类和本类中都有同名的成员,使用super访问遵循就近原则。Son->Father->Grandpa,当然也需要遵守访问
    权限的相关规则

√ super的好处

区别点thissuper
访问属性访问本类中的属性,如果本类没有此属性,则从父类中继续查找。从父类开始查找属性。
调用方法访问本类中的方法,如果本类没有此方法,则从父类继续查找。从父类开始查找方法。
调用构造器调用本类构造器,必须放在构造器的首行。调用父类构造器,必须放在子类构造器的首行。
特殊表示当前对象。子类中访问父类对象。
// 案例:com.studySuper297.demo01.Son

1.26.4 方法重写/覆盖

√ 基本介绍
简言而之,方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法。

√ 注意事项( 触发 方法重写/覆盖 的条件 )

  1. 子类的方法的 形参列表、方法名称 ,要和父类方法的 形参列表、方法名称 完全一样。
  2. 子类方法的返回类型和父类方法返回类型一样,或者是 父类返回类型的子类
  3. 子类方法不能缩小父类方法的访问权限。 public -> protected -> 默认 -> private

√ 方法重载 与 重写 对比
名称 发生范围 方法名 形参列表 返回类型 修饰符
重载(overload) 本类 必须一样 类型,个数或者顺序 无要求 无要求
至少有一个不同
重写( override ) 父子类 必须一样 相同 子类重写的方法,返回 子类方法不能缩小父类
的类型和父类返回的类 方法的访问范围
型一致,或者是其子类

// 案例:com.study06Override301.demo01.TestDemo        【override:覆盖】

1.26.5 面向对象编程三大特征 - 多态

√ 基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

√ 对象的多态( 重要 )

  1. 一个对象的 编译类型 和 运行类型 可以不一致
  2. 编译类型在定义对象的时候就确定了,不能改变
  3. 运行类型是 可以改变的
  4. 编译类型看定义时 = 的 左边,运行类型看 = 的 右边
    例如:
    Animal animal = new Animal(“猫咪01”, 1); // animal 的编译类型是Animal,运行类型是 Dog
    animal = new Dog(“狗子”, 2); // animal 的编译类型仍然是 Animal,运行类型 变成了 Dog

√ 注意事项
多态的前提是: 两个对象(类) 之间存在 继承的关系
多态的 向上转型:
1)本质:父类的引用指向了 子类的对象
2)语法:父类类型 引用名 = new 子类类型();
3)特点:
编译类型看左边,运行类型看右边;
可以调用父类中所有成员( 需遵守访问权限 )
不能调用子类中特有成员
最终运行效果看子类的具体实现
多态的 向下转型
1)语法:子类类型 引用名 = (子类类型)父类引用;
2)只能强转父类的引用,不能强转父类的对象
3)要求父类的引用必须指向的是当前目标类型的对象
4)当向下转型后,可以调用子类类型中所有的成员

√ java的动态绑定机制( 重要 )
1)当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
2)当调用对象属性时,没有动态绑定机制,哪里声明,哪里调用

√ instanceOf 比较操作符,用于判断对象的运行类型是否为 XX类型 或 XX类型的子类型

// 案例:com.study07Polymorphic305.demo01.TestDemo01       【 polymorphic:多态 】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值