javaSE复习

复习javase

1、数据类型

 jdk  jre jvm
 配置环境变量 
 标识符 
 关键字 
 常量+变量
 运算符:  算术运算符  比较运算符 赋值运算符  位运算符  逻辑运算符  三元运算符
 数据类型:   
 数据类型转换:java是强类型语言:值的类型必须和变量类型一致
        1: 自动类型转换情况1:  高精度变量=低精度数据;
                eg:  float  f=1;
                     左边float类型的变量f  右边int类型的整数1
                     编译器会把 4个字节int类型的1  自动转换为4个字节float类型的1.0f 然后赋值
       2: 自动类型转换情况2:  char/byte/short类型的变量=int常量值;
               eg:     byte  b1=1;
                      编译器判断1 处在byte范围内,把4个字节int类型的自动转换为1个字节byte类型的1
                      然后赋值
               eg:     short  s1= 50000;  (short取值:-32768到32767) 
                       编译器判断50000不在short范围内,直接报错
      3: 强制类型转换: 低精度变量=(低精度变量的类型)高精度数据; 
               eg:     short  s2=(short)50000;
                       int i1=(int)1.1;
                       编译器强制把8个字节double类型的1.1 转换为4个字节int类型的1  然后赋值
//数据类型精度表:(boolean)byte short (char)int long float double 
/*
boolean、byte 1个字节 8位;
short、char 2个字节 16位;
int float 4个字节 32位;
double、long 8个字节 64位
*/
//自动转化三类:
//自动转化类型1,高的精度=低的精度
long l =  1 ;
double d =  '1';
//自动转化类型2,byte/short/char 变量 = int 常量值
 byte b = 1 ;
//byte占1个字节,8位-127到127
//自动转化类型3,低的精度=(低精度)高的精度
short f = (short) 100000;
//这里输出为负数,因为超过了short的最大值
/*
思考
 */
 byte b1 = (int)1.1;
 //注意是常量值不是变量,变量必须自己强转
int i1=1;byte b2 = (byte) i1;
short s1 = 1;char c1 = (char) s1;

2、流程控制

学过的内容总结自己的话

计算机所有语言所有概念都是望文生义

流程控制:就是计算机执行程序的流程,一般为从上到下、从左到右。
1.选择结构
if-else
switch:只适用于穷举法,必须把所有可能列举出来
2.循环结构
while
do-while:至少执行一次
for
3: 循环结构
    for
    while
    do while
4: 跳转
    break
    continue 
  • ifelse
 //2.1 if-else
        int a=1;
        if(a>0){
            System.out.println("a=" + a + "大于0!");
        }
        if(a>0)   //如果执行的代码块只有一个语句  大括号可以省略---不规范
            System.out.println("a=" + a + "大于0!");
        System.out.println(111);
  • switch
       //2.2 switch
        /*
        * switch: 只适用于穷举法: 必须把所有可能的清空列举  不适用范围判断
        * switch注意事项:
        *    1  switch表达式的值的数据类型仅限于:int+String+enum
        *    2  case后面的值不能重复
        *    3  只有当所有的case都不正确时 才运行default 与其位置无关
        *    4  break的作用是 结束switch结构
        * */
        //根据月份判断季节: 3 4 5春天 678 夏 9 10 11 秋季 12 1 2 冬季
        int month=1;
        switch(month){
            default:
                System.out.println("momnth="+month+"月是火星季!");
                break;
            case  1:
            case  2:
            case  12:
                System.out.println("momnth="+month+"月是冬季!");
                break;
            case  3:
            case  4:
            case  5:
                System.out.println("momnth="+month+"月是春季!");
                break;
            case  6:
            case  7:
            case  8:
                System.out.println("momnth="+month+"月是夏季!");
                break;
            case  9:
            case  10:
            case  11:
                System.out.println("momnth="+month+"月是秋季!");
                break;

        }
  • while和dowhile的区别
//1 while和dowhile的区别
//while是先判断再执行
//dowhile是先执行再判断::dowhile至少执行一次
int a=-1;
while(a>=0){
    System.out.println(a+">=0成立!while");
    a--;//迭代语句:按指定的算法更改变量的值
}
a=-1;
do{
    System.out.println(a+">=0成立!do---while");
    a--;//迭代语句:按指定的算法更改变量的值
}while(a>=0);
  • for
//1 for格式
/*
        * for(初始化语句;循环条件;迭代语句){
        *      循环体
        * }
        * */
for(int a=1;a<=5;a++){
    //System.out.println("a="+a);
}
//2 省略
//        for(;;){  //如果条件表达式省略 默认是true  死循环
//            System.out.println("111");
//        }
//3 执行流程
//初始化语句只执行一次:第一次循环前执行一次
//先执行初始化语句  -》
//      1:判断条件表达式是否成立  不成立结束循环
//      2:条件表达式成立 执行循环体
//      3:循环体执行完 执行迭代语句
//      迭代语句执行完  再次判断条件表达式是否成立  一直循环执行1 2 3步
//      直到1的条件表达式不成立 才结束循环
int i=1;
for(System.out.println("i="+i+"初始化语句!");i<=0; System.out.println("i="+i+"迭代语句!")){
    //System.out.println("i="+i+"循环体!");
    i++;
}
//4 变量作用范围
int a=1;//1 变量a在for循环外面定义的: 作用于整个for循环  并且在for循环结束后仍然可以访问到
for(int b=1;b<=5;){// 2 变量b在for循环的初始化语句中定义的: 作用于整个for循环  for循环结束后变量消失
    int c=1;  // 3 变量c在for循环的循环体中定义的:只作用于本次循环
    //System.out.println("a="+a+",b="+b+",c="+c);
    b++;a++;c++;
}
System.out.println("a="+a);

//案例1:获取1到100内个位数值为1 并且可以被3整除的所有数平均值
// 需要让一个数从值1跑到值2  使用循环
//定义变量记录和 和 个数
int sum1=0,geShu1=0;
for(int n=1;n<=100;n++){
    //判断当前n的个位数值为1 并且可以被3整除
    if(n%3==0){
        //获取个位数
        int geWeiShu=n%10;
        if(geWeiShu==1){
            System.out.println("n="+n+":::满足条件!");
            geShu1++;
            sum1+=n;
        }
    }
}
System.out.println("获取1到100内个位数值为1 并且可以被3整除的所有数平均值="+sum1*1.0/geShu1);

3、数组

  • 概念
数组:装相同类型 指定个数个数据 的容器
元素:数组中存储的每个数据称为数组的元素
下标/索引:  元素在数组中位置(顺序),通过数组名+下标可以获取元素
关键字:[]
  • 特点
1  装多个数据的容器:对象类型
     java中把数据按复杂程度分成两种:1 单值数据--八种基本数据类型(值:常量值)
                                2 复杂数据--多个基本数据有机组合形成的整体(值:对象)
2  元素类型必须相同
3  元素个数固定
4  创建时 必须目前元素类型和元素个数
  • 使用
一个数据使用变量记录
多个相同类型的数据使用数组记录
好处:
int age1,age2,age3,age4,age5;
int[] arrAge=new int[5];
数组会自动给装入期中的元素分配下标:下标从0到length-1  通过arrAge[下标] 可以获取指定元素
  • 注意事项
1  数组中的元素 不赋值 有默认初始值:值取决于元素的类型
           值:此类型的0  boolean是false
2  获取元素时  下标取值为0到length-1  否则:ArrayIndexOutOfBoundsException
  • 内容介绍
//等于一个数组装5个int类型的数据
//创建数组时 必须明确:元素类型 元素个数
int[] arr;//定义数组名
arr=new int[5];//new int[5]在内存中创建一个数组 元素类型时int 元素个数时5
// =  让左边的对象名arr指向右边在内存中new的对象
int[] arr2=new int[5];//每new一个 就一个新的对象

//遍历数组:使用for循环
for(int i=0;i<arr.length;i++){
    System.out.println("arr["+i+"]="+arr[i]);
}
//遍历数组:使用foreach:简洁for循环
//    优点:简洁
//    缺点:1 不能获取元素的下标
//         2 元素不能增和删
for(int a:arr2){
    System.out.println("a="+a);
}

System.out.println(arr[5]);//ArrayIndexOutOfBoundsException: 5
System.out.println(1+1);

//创建数组的三种格式
//格式1: 元素类型[] 对象名=new 元素类型[元素个数];
//不直到元素的具体值:
int[] arr01=new int[3];//数组中的元素有默认值
arr01[0]=19; arr01[1]=29; arr01[2]=18;//给元素赋值

//格式2: 元素类型[] 对象名=new 元素类型[]{值1,值2,值3...};
//知道元素的具体值
int[] arr02=new int[]{1,2,3,4};
//格式3: 元素类型[] 对象名={值1,值2,值3...};
int[] arr03={1,2,3,4};
  • 一维数组的要求
//一维数组的要求
//1:遍历
//2:求最大值
arr=new int[]{1,4,5,7,9,0,2,11,4};
int max1=arr[0];//定义变量记录最大值:初始值为第一个元素
for(int i=1;i<arr.length;i++){
    //拿max1与所有元素作比较
    max1=(max1>arr[i]?arr[i]:max1);
}
//3: 排序

3.1、数组排序:

顺序排序
  • 概念
顺序排序:依次拿当前元素何其后面的所有元素做比较
  • 图解

image

  • 使用代码模拟打印的效果
int[] arr={9,1,3,6,8,2};//要求从小到大排序
for(int i=0;i<arr.length;i++){
    System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
//打印的效果
/*
        * arr[0]-arr[1] arr[0]-arr[2] arr[0]-arr[3] arr[0]-arr[4] arr[0]-arr[5]
        * arr[1]-arr[2] arr[1]-arr[3] arr[1]-arr[4] arr[1]-arr[5]
        * arr[2]-arr[3] arr[2]-arr[4] arr[2]-arr[5]
        * arr[3]-arr[4] arr[3]-arr[5]
        * arr[4]-arr[5]
        * */
for(int i=0;i<arr.length-1;i++){//外层for循环记录当前元素的下标:
    //System.out.println("当前元素:arr["+i+"]");
    for(int j=i+1;j<arr.length;j++){
        //arr[i]是当前元素
        //arr[j]是当前元素后面的元素
        //拿arr[i]和arr[j]比较
        System.out.print("arr["+i+"]-arr["+j+"] ");
    }
    System.out.println();//打印换行
}
  • 把打印更改为比较即可
//顺序排序:依次拿当前元素何其后面的所有元素做比较
int[] arr={9,1,3,6,8,2};//要求从小到大排序
for(int i=0;i<arr.length;i++){
    System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
//把打印更改为比较
for(int i=0;i<arr.length-1;i++){//外层for循环记录当前元素的下标:
    for(int j=i+1;j<arr.length;j++){
        //arr[i]是当前元素
        //arr[j]是当前元素后面的元素
        //拿arr[i]和arr[j]比较
        if(arr[i]<arr[j]){
            int k=arr[i];arr[i]=arr[j];arr[j]=k;
        }
    }
}
for(int i=0;i<arr.length;i++){
    System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
冒泡排序
  • 核心思想
依次拿相邻运算作比较
  • 图解
    image

  • 使用java打印出比较过程

int[] arr={1,4,8,9,0,2};
//打印效果
/*
            arr[0]-arr[1] arr[1]-arr[2] arr[2]-arr[3] arr[3]-arr[4] arr[4]-arr[5]
            arr[0]-arr[1] arr[1]-arr[2] arr[2]-arr[3] arr[3]-arr[4]
            arr[0]-arr[1] arr[1]-arr[2] arr[2]-arr[3]
            arr[0]-arr[1] arr[1]-arr[2]
            arr[0]-arr[1]
        */
//二维图形:两层for循环
//外层for循环控制行数  内层for循环控制本行的列数
//分析:每次比较的两个元素:前一个元素如果是arr[i] 后一个元素就是arr[i+1]
for(int  i=0;i<arr.length-1;i++){//共arr.length-1行
    for(int j=0;j<arr.length-i-1;j++){//让arr[j]作为前面的元素 arr[j+1]是后面的元素
        //打印
        System.out.print("arr["+j+"]-arr["+(j+1)+"]\t");
    }
    System.out.println();
}
  • 把打印更改为比较即可
int[] arr={1,4,8,9,0,2};
//打印当前数组
for(int i=0;i<arr.length;i++){
    System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
//把打印更改为比较即可
for(int  i=0;i<arr.length-1;i++){//共arr.length-1行
    for(int j=0;j<arr.length-i-1;j++){//让arr[j]作为前面的元素 arr[j+1]是后面的元素
        if(arr[j]<arr[j+1]){
            int k=arr[j];arr[j]=arr[j+1];arr[j+1]=k;
        }
    }
}
//打印当前数组
for(int i=0;i<arr.length;i++){
    System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
冒泡排序和顺序排序的区别
//冒泡排序
for(int  i=0;i<arr.length-1;i++){//共arr.length-1行
    for(int j=0;j<arr.length-i-1;j++){//让arr[j]作为前面的元素 arr[j+1]是后面的元素
        if(arr[j]<arr[j+1]){
            int k=arr[j];arr[j]=arr[j+1];arr[j+1]=k;
        }
    }
}
//顺序排序
for(int  i=0;i<arr.length-1;i++){//共arr.length-1行
    for(int j=i+1;j<arr.length;j++){//arr[i]作为当前元素 arr[j]作为当前元素后面的元素
        if(arr[j]<arr[i]){
            int k=arr[j];arr[j]=arr[i];arr[i]=k;
        }
    }
}

/*
分析:
 外层for循环变量i 都是从0开始到length-2:轮数相同 都是length-1轮
 内层for循环变量j
        冒泡排序:j从0开始到length-i-2     取值:length-i-1 
        顺序排序:j从i+1开始到length-1     取值:length-i-1
  比较的元素:
        冒泡排序:arr[j]和arr[j+1]比较
        顺序排序:arr[i]和arr[j]比较
*/

3.2、二维数组

  • 概念
n维数组:装指定个数个 n-1维数组的容器
注意:一般说的数组::指的是一维数组
二维数组关键字:[][]
  • 学习重点
//二维数组要求:
//1 会创建  2 会遍历
//创建二维数组:
//格式1:元素类型[][] 对象名=new 元素类型[n][m];
int[][] arr1=new int[3][4];
//格式2:元素类型[][] 对象名=new 元素类型[][]{{值1,值2,值3..},{值1,值2,值3..},{值1,值2,值3..}};
int[][] arr2=new int[][]{{1},{1,4,6},{1,5},{0,1,2,4,65}};
//格式3:元素类型[][] 对象名={{值1,值2,值3..},{值1,值2,值3..},{值1,值2,值3..}};
int[][] arr3={{1},{1,4,6},{1,5},{0,1,2,4,65}};

//注意1:元素有默认值 int[][] arr1=new int[3][4];
arr1=new int[][]{{1},{1,4,6},{1,5},{0,1,2,4,65}};
System.out.println("arr1="+arr1);
//arr1=[[I@1540e19d  对象类型@16进制内存地址
System.out.println("arr1.length="+arr1.length);
//arr1.length:二维数组arr1中 一维数组的个数
System.out.println("arr1[0]="+arr1[0]);
//arr1[0]:二维数组arr1中 下标为0的一维数组对象
System.out.println("arr1[0].length="+arr1[0].length);
//arr1[0].length:二维数组arr1中 下标为0的一维数组的元素个数
System.out.println("arr1[1][2]="+arr1[1][2]);
//arr1[1][2]:二维数组arr1中 下标为1的一维数组对象中下标为2的元素的值

//遍历二维数组
for(int i=0;i<arr1.length;i++){  //遍历二维数组中的一维数组
    for(int j=0;j<arr1[i].length;j++){//遍历当前一维数组arr[i]中的所有元素
        System.out.print(arr1[i][j]+(j==arr1[i].length-1?"\n":","));
    }
}

3.3数组练习题

        /*
         * 数组练习题:
         * 创建一个装10个int元素的数组:  1 2 3 0 6 7 8 9 9 10 10
         * 1  获取数组的次大值:
         * 2  数组倒序:
         * 3  打印数组:
         *     1   3  5  6  4
         *     *
         *     ***
         *     *****
         *     ******
         *     ****
         * 4 打印数组:
         *     1    3    5    6    4
         *                    *
         *               *    *
         *               *    *    *
         *          *    *    *    *
         *          *    *    *    *
         *     *    *    *    *    *
         * 5 扩展题:
         *     打印杨辉三角
         *
         * 1
         * 1   1
         * 1   2    1
         * 1   3    3    1
         * 1   4    6    4    1
         * 1   5    10   10   5    1
         * 1   6    15   20   15   6   1
         * */

第四题for循环解法:

private static void print2(int[] arr) {
    /* 4 打印数组:
         *     1    3    5    6    4               拿所有元素与n比较
         *                    *                           6
         *               *    *                           5
         *               *    *    *                      4
         *          *    *    *    *
         *          *    *    *    *
         *     *    *    *    *    *                      1
          */
    //行数:max
    //列数:length
    //什么时候打印空格 什么时候打印星:::
    System.out.println("打印数组:::");
    for(int i=0;i<arr.length;i++){
        System.out.print((" "+arr[i]+" ")+(i==arr.length-1?"\n":""));
    }
    //获取最大值
    int max=arr[0];
    for(int i=1;i<arr.length;i++){
        max=max>arr[i]?max:arr[i];
    }
    //两层for循环
    for(int i=max;i>=1;i--){//行数:max行
        for(int j=0;j<arr.length;j++){  //拿当前元素arr[j]与i比较
            System.out.print(arr[j]>=i?" * ":"   ");
        }
        System.out.println();
    }
}

第四题二维数组解法:

public class PrintArrayPlus {
    public static void main(String[] args) {
        int a[] = { 1,3, 5, 6, 4,1};
        char b[][] = new char[6][6];
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < a[i]; j++) {
                b[i][j]='*';
            }
        }
        //                           (0,2) (1,2)
        //(0,0) (0,1) (0,2)          (0,1) (1,1)
        //(1,0) (1.1) (1.2)    -->   (0,0) (1,0)

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

        for (int i = 0; i < b[0].length; i++) {
            for (int j = 0; j < b.length; j++) {
                System.out.print(b[j][b.length-1-i]+"\t");
            }
            System.out.println();
        }
        }
    }

杨辉三角:

public class YangHuiTriangle {
    public static void main(String[] args) {
        int a[][] = new int [10][10];
        for (int i = 0; i < a.length; i++) {
                a[i][0]=1;
                a[i][i]=1;
        }
        for (int i = 2; i < a.length; i++) {
            for (int j = 1; j < i; j++) {
                a[i][j]=a[i-1][j]+a[i-1][j-1];
            }
        }
        for (int i = 0; i < a.length; i++) {
            for (int j  = 0; j < i+1; j++) {
                System.out.print(a[i][j]+"\t");
            }
            System.out.println();
        }

    }
}

4、方法:method

  • 概念
方法:类中定义的具有特定功能的代码块
分析: 方法位置:类中
      方法实质:代码块{}
      方法关键字:()
      方法作用:代码的复用
      方法意义:一个指定功能
  • 格式
修饰符  返回值类型  方法名(参数列表){
    方法体
    return 返回值;
}

分析:
     修饰符:让被修饰者具有一些本来不具有的特征的关键字
     修饰符分类:范围修饰符  静态修饰符 常量修饰符 同步修饰符
      
     返回值:方法运行完后给与调用者的结果数据
     参数列表:用于方法接受方法运行需要传递的原始数据而定义的变量列表
     方法名:标识符:方便调用 和 同类区分
     方法体:实现具体功能的代码块
     return:关键字:结束方法+把返回值返回给调用者
组成:
    方法声明部分: 修饰符  返回值类型  方法名(参数列表)
              方法的使用说明书:对方法进行介绍说明
    方法体部分:   {...}     
              方法功能具体实现:        
  • 方法的本质 就是一个功能

image-20210824160200705

  • 案例
package com.zhiyou100;
public class Test02Method {
    public static void main(String[] args) {
              //调用方法 方法才能运行
              int n=add1(1,2);
              System.out.println("n="+n);
    }
    //定义方法
    public static int add1(int a,int b){
        int sum=a+b;
        System.out.println("a="+a+":b="+b+":sum="+sum);
        return sum;
    }
    /*
    * public:修饰符  可以在整个项目中访问到
    * static:修饰符  可以被main方法直接调用
    * int: 方法会返回一个int类型的数据
    * add1:方法名
    * int a,int b:参数列表:方法需要调用者传递两个int类型的数据 用变量a接受第一个数据 变量b接受第二个数据
    *   int sum=a+b;
        System.out.println("a="+a+":"+b+"="+sum);
       方法体:实现方法求和功能的代码
       * return sum: 结束方法 把sum返回给调用者
    * */
}
  • 注意事项
package com.zhiyou100;

public class Test02Method {
    public static void main(String[] args) {
              //调用方法 方法才能运行
              int n=add1(1,2);
              System.out.println("n="+n);
              //n=printAdd(1,1);

             //注意2:方法如果有返回值  调用者可以选择接受
             add1(1,2);

             //注意3:调用方法时传递的参数类型必须和方法的参数列表类型一致
             //add1(1,2.1);
             //定义方法时的参数列表:::形参  int a,int b
             //调用方法时传递的实际数据::实参 1,2
             //方法运行时 通过形参的名字来使用实参的值

            //注意4:
           //基本数据类型作为方法参数:传递的是变量的值  方法体运行完后 实参对应的变量值不会更改
           int aa=1;
           test1(aa);//代码替换:int a=aa;a++;
           //int a=aa;把变量aa的值1复制一份给了变量a  在方法体中对变量a进行修改 和变量aa无关
           System.out.println("aa="+aa);//aa=1

           //引用数据类型作为方法参数:传递的是对象的内存地址 两个引用指向同一个对象
           int[] array=new int[]{1,4,5,7,9,0};
           printArr(array);//代码替换:int[] arr=array;arr[0]++;
           //int[] arr=array;让数组名arr和array指向同一个数组对象(27行的对象)
           test2(array);
           printArr(array);


    }
    public static void test2(int[] arr){
        for(int i=0;i<arr.length;i++){
            arr[i]++;
        }
    }
    public static void test1(int a){
        a++;
    }
    public static void printArr(int[] arr){
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+(i==arr.length-1?"\n":","));
        }
    }
    //注意1:方法没有返回值:返回值类型用关键字void标识
    public static void printAdd(int a,int b){
        System.out.println(a+"+"+b+"="+(a+b));
        //return ;//如果redtun后面没有返回值  return可以省略
    }
    //定义方法
    public static int add1(int a,int b){
        int sum=a+b;
        System.out.println("a="+a+":b="+b+":sum="+sum);
        return sum;
    }
    /*
    * public:修饰符  可以在整个项目中访问到
    * static:修饰符  可以被main方法直接调用
    * int: 方法会返回一个int类型的数据
    * add1:方法名
    * int a,int b:参数列表:方法需要调用者传递两个int类型的数据 用变量a接受第一个数据 变量b接受第二个数据
    *   int sum=a+b;
        System.out.println("a="+a+":"+b+"="+sum);
       方法体:实现方法求和功能的代码
       * return sum: 结束方法 把sum返回给调用者
    * */
}

4.1、方法重载

  • 概念:
方法重载:overload:同一个类中几个方法 方法名相同 参数列表不同的现象
  • 要求
1 必须是同一个类
2 方法名必须相同
3 参数列表必须不同: 参数个数不同 参数类型不同 参数顺序不同
  • 案例
public class Test03OverLoad {
    public static void main(String[] args) {
             add(1,1);
             add(1.1,1);
             add(1,1.1);
    }
    public static void add(int a,int b){
        System.out.println("int int:::");
    }
    public static void add(int a,int b,int c){
        System.out.println("int int int::::");
    }
    public static void add(int a,double b){
        System.out.println("int double:::");
    }
    public static void add(double a,int b){
        System.out.println("double int:::");
    }
}
  • 意义
方法重载:几个功能一致 只是参数列表不同
        功能基本一致  满足不同参数列表的需求

5、 面向对象

学习方法

  • 联系现实生活
  • 内存图

5.1、 OOP概念

OOP:Object Oriented Programming  面向对象编程
    一种编程思想(写代码的一种套路 固定模式)
POP:Procedure Oriented Programming 面向过程编程
     计算机的两种编程思想
举例:解决吃饭问题
     oop: 找饭店 掏钱 说出你的要求  等待厨师做晚饭  吃饭 拍屁股走人  
     pop: 种米 挖菜 收米  淘米 生火  煮饭 切菜 炒菜 吃饭 刷锅 
总结:
     pop: 按动作把整个过程分成多个步骤 逐个步骤去完成 最终解决问题
          重点:动作
     oop: 找具有帮我解决问题功能的对象 指挥对象解决问题 
          重点:对象          
  • oop的铁打四步
1 定义类描述一类事物:类中两部分(通过变量表示数据  通过方法表示功能)
2 根据类创建对象
3 给对象的变量赋值
4 调用对象的方法 解决问题
package com.zhiyou100;

public class Test01OOP {
    //解决问题:在电脑中模拟人物进行自我介绍
    public static void main(String[] args) {
          //2 在主方法中:根据Person类创建一个人物对象
          //格式:对象类型  对象名=new 对象类型();
          //     对象类型  对象名  ---创建引用
          //     new 对象类型();   ---创建对象
          //     =  让引用指向对象
          Person p1=new Person();

          //3 给对象的变量赋值人物的数据
          p1.age=65;p1.sex='男';p1.job="作家";p1.name="叶秋雨";

          //4 调用对象的方法 解决问题
          p1.show();
    }
}
//1 通过person类描述人物的类型(人类)  让电脑对人这个类型有个概念
class Person{
    // 通过变量表示数据
    int age;
    String name;
    char sex;
    String job;
    //通过方法表示功能
    public void show(){
        System.out.println(name+":"+age+":"+sex+":"+job);
    }
    public void sleep(int second){
        System.out.println(name+"休息"+second+"秒!");
    }
}

5.2、 类和对象

1: 类是代码的载体
2: 对一类事物的描述:通过变量表示数据 通过方法表示功能
3: 类是创建对象的模板/图纸
  • 对象
1:引用数据类型数据:多个基本数据有机组合形成的整体
2:对象是现实事物在电脑中的模型
3:对象是类的实例
  • 关系
对象 是通过类创建的  必须现有类 才有对象
一个类可以创建多个对象
类中定义了那些变量 决定了此类创建的对象有那些数据
类中定义了那些方法 决定了此类创建的对象有那些功能

5.3、 成员

成员:组成的一员
类的成员:类的组成
         表示数据的变量---成员变量
         表示功能的方法---成员方法
变量的分类:
     成员变量:类中定义的变量
     局部变量:方法中定义的变量(方法参数列表+方法体中定义的变量)     
  • 案例
package com.zhiyou100;

public class Test01OOP {
    public static void main(String[] args) {
          
    }
}
class Person{
    int a;//成员变量
    public void test1(int b){//局部变量
        int c=1;//局部变量
        System.out.println(a+":"+b+":"+c);
    }
    public void test2(){
        System.out.println(a);//此处只能访问成员变量a 不能访问test1方法中定义的局部变量bc
    }
}
  • 区别
成员变量和局部变量的区别:
概念解释: 成员变量:类中直接定义的变量
         局部变量:方法中调用的变量
相同之处: 都是变量 用于记录数据的
不同之处:
      1 定义位置不同
          成员变量定义在类中  局部变量定义在方法中
      2 作用范围不同
          成员变量作用域是整个类  局部变量的作用域是当前方法
      3 是否有默认值(不赋值 编译器会自动设置值)
          成员变量有默认值(值取决于变量的类型)  局部变量必须显式赋值
      4 修饰符不同
          成员变量可以有 范围修饰符 静态修饰符 final修饰符
          局部变量只可以加 fianl修饰符           
  • 注意
笔试题类型
1 选择题
2 智力题
3 简单题  :xx与yy的区别
     第一:先解释 什么是xx 什么是yy
     第二:xx与yy的相同之处
     第三:分条阐述xx与yy的不同之处
4 编程题

5.4、 构造方法

  • 概念
构造方法/构造器 Constructor :用于构建创造对象的方法
  • 特点
1 构造方法名字必须和类名相同
2 一个类没有构造方法 编译器默认添加一个无参数的构造方法
3 构造方法没有返回值 不用void标识
4 构造方法的参数列表 一般用于给对象的属性赋值
5 构造方法只能被关键字new调用   用于创建对象  每调用一次就创建一个新的对象
6 构造方法不能被对象调用
  • 构造方法和普通方法的区别
第一步:概念
   构造方法:类中定义的用于创建对象的方法
   普通方法:类中定义的用于描述指定功能 而非创建对象的方法
第二步:相同
   都是方法:格式基本相同、都用于表示功能
第三步:不同之处
   1 格式不同: 构造方法没有返回值  不用void标识
               普通方法必须有返回值类型的标识  没有返回值 用void标识
   2 作用不同:  构造方法用于创建对象  
               普通方法用于描述功能
   3 调用不同:  构造方法被关键字new调用  调用一次就创建一个新的对象
               普通方法被对象对象  一个对象可以调用多次普通方法
   4 是否有默认  如果一个类没有构造方法 编译器默认添加一个无参数的构造方法 
               普通方法没有默认  

5.5、 this

  • 概念
this:关键字 在类中表示当前对象(类似于显示中:我自己)   比较特殊的引用
  • 案例
package com.zhiyou100;

import java.lang.reflect.Constructor;

public class Test03This{
    public static void main(String[] args) {
        Test03 t1=new Test03();
        t1.test();//this=com.zhiyou100.Test03@1540e19d
        System.out.println("t1="+t1);//t1=com.zhiyou100.Test03@1540e19d

        Test03 t2=new Test03();
        t2.test();//this=com.zhiyou100.Test03@677327b6
        System.out.println("t2="+t2);//t1=com.zhiyou100.Test03@677327b6

    }
}
class Test03{
    public void test(){
        System.out.println("this="+this);//哪个对象调用test方法  此处的this指的就是哪个对象
    }
}
  • this的使用场景1

当成员变量与局部变量重名时 变量名默认指向的是局部变量 通过this.变量名来指向成员变量

注意:方法中调用成员时 前面默认有this.

package com.zhiyou100;

public class Test03This {
    public static void main(String[] args) {
           //调用方法只能通过对象
           Test03 t1=new Test03();
           t1.test01();
    }
}
class Test03{
    int a=2;//成员变量
    int b=3;
    public void test02(){}
    public void test01(){
        int a=1;//局部变量
        System.out.println("a="+a);//a=1 就近原则
        //成员变量与局部变量重名时  变量名默认指向的是局部变量
        System.out.println("this.a="+this.a);//通过this.变量来指向成员变量
        test02();//this.test02(); 调用成员方法时 前面默认有this.
        System.out.println("b="+this.b);//this.b 调用成员变量时 前面默认有this.
    }
}
  • this的使用场景2

构造方法之间相互调用通过this(参数列表)

注意:this(参数列表) 必须是第一个语句

package com.zhiyou100;
public class Test03This {
    public static void main(String[] args) {
           new Test03(1,4);
    }
}
class Test03{
    Test03(int a){
        System.out.println("构造方法::Test03(int a)");
    }
    Test03(int a,int b){
        //构造方法之间的调用 是为了代码的复用
        this(a);//调用构造方法Test03(int a)  //注意this(参数列表) 必须时第一个语句
        System.out.println("构造方法::Test03(int a,int b)");
    }
}

5.6、 给成员变量赋值的方式

package com.zhiyou100;

public class Test04SetValue {
    public static void main(String[] args) {
        //1 方式1: 直接在类中给成员变量赋值
        //   特点:此类创建的所有对象的此属性初始值都是此值
        //   类似于:直接买一个出场为红色的车
        Car c11=new Car();//属性:类中定义什么成员变量  此类创建的对象就有什么属性
        Car c12=new Car();
        Car c13=new Car();
        //每个对象都拥有一套只属于自己的成员(属性和方法)

        //2 方式2:通过对象.属性给属性赋值
        //  特点:必须先创建对象  只能给当前对象的属性赋值
        //  类似于:自己刷红漆
        //  严厉禁止:属性不安全 无法校验
        Car c14=new Car();
        c14.number="豫A88888";


        //3 方式3:通过构造方法的参数列表给属性赋值
        //  特点:对象一创建 属性就有指定的值  只能给当前对象的属性赋值
        //  类似于:定制一个红色的
        //  鼓励使用
        Car c15=new Car(100000);

        //4 方式4:通过普通方法的参数列表给属性赋值
        //  特点:必须先创建对象  只能给当前对象的属性赋值
        //  类似于:拉到4s店改装为红色
        // 最常见
        Car c16=new Car();
        c16.setColor('黑');

        c14.show();
        c11.show();
        c12.show();
        c13.show();
        c15.show();
        c16.show();
    }
}
class Car{
    char color;
    String number;
    double money;
    String logo="bmw";//方式1: 直接在类中给成员变量赋值
    void show(){
        System.out.println(color+":"+number+":"+money+":"+logo);
    }
    Car(){}
    Car(double money){//局部变量money
        if(money<10000){return;}//数据可控
        this.money=money;//通过局部变量给成员变量赋值
    }
    void setColor(char color){
        if(color!='白'&&color!='红'&&color!='黑'){return;}//数据可控
        this.color=color;
    }
}

5.7、 创建对象内存图

image

5.8、 static

修饰符: 静态的
        可以修饰 成员变量  成员方法 内部类  代码块        
  • static修饰的成员:::类成员 (此成员是属于整个类 为整个类的所有对象共有)

  • 没有static修饰的成员:::实例成员(此成员是属于对象的 每一个对象都拥有一套只属于自己的实例成员)

  • static修饰的成员变量:::类变量/共享数据

  • static修饰的成员方法:::类方法

  • 没有static修饰的成员变量:::实例变量

  • 没有static修饰的成员方法:::实例方法

static修饰的变量有什么特点

  • 1 类变量不但可以被对象调用 还可以通过类名直接调用
  • 2 类变量是共享数据 被所有对象公用
package com.zhiyou100;

//一个源文件可以定义多个类:
//但只能有一个public修饰的类
//并且此类public类必须和源文件名一致
//开发过程中不能这样使用:
public class Test01StaticVariable {
    public static void main(String[] args) {
        Test01  t1=new Test01();
        t1.a=10;
        Test01  t2=new Test01();
        //每个Test01类型的对象都拥有一个只属于自己的a
        System.out.println("a="+t1.a);//10
        System.out.println("a="+t2.a);//0

        //特点1:类变量可以通过类名直接掉用 还可以通过对象调用
        Test01.aa=3;
        System.out.println(Test01.aa+":::"+t1.aa);//
        //特点2:类变量是共享数据 所有对象公用
        t1.aa=4;
        System.out.println(t1.aa+":::"+t2.aa+":::"+Test01.aa);
    }
}
class Test01{
    int a;//成员变量--实例变量
    static int aa;//成员变量--类变量/共享数据
}

static修饰的方法有什么特点

  • 1 静态方法不但可以被对象可以 还可以被类名直接调用
  • 2 静态方法中只能调用类成员 不能调用实例调用
package com.zhiyou100;

public class Test02StaticMethod {
    public static void main(String[] args) {
        Test02  t1=new Test02();
        Test02  t2=new Test02();
        t1.show();
        t2.show();
        //特点1:静态方法不但可以被对象调用  还可以被类名直接调用
        t1.showStatic();t2.showStatic();
        Test02.showStatic();
        //特点2:静态方法中只能调用类成员 不能调用实例成员
        //      实例方法中可以调用实例成员和类成员
    }
}
class Test02{
    int a=1;
    static int b=1;
    void show(){
        System.out.println(a+":::"+b);
        showStatic();
    }
    static void showStatic2(){}
    static void showStatic(){
        //System.out.println(a);//静态方法中不能调用实例变量
        System.out.println(b);
        //show();//静态方法中不能调用实例方法
        showStatic2();
    }
}

静态内存图

image-20210826110402979

5.9、 继承 extends

继承概念

当定义一个新类时 如果新类拥有一个现有的类所有成员  可以让新类从现有的类派生、衍生
新类:::子类
现有的类:::父类
继承格式:::class 子类  extends 父类{}
继承作用:类与类之间创建关系

继承特点

  • 1 子类可以继承父类中定义的所有实例成员
  • 2 子类可以定义子类特有的成员
  • 3 子类不能继承父类的构造方法
  • 4 子类可以重新定义父类已有的成员变量:要求变量名相同即可
  • 5 子类可以重新定义父类已有的成员方法:重写(override) 要求:方法声明必须和父类完全相同
  • 6 java只支持类与类的单继承:一个子类只能有一个直接父类
  • 7 一个类没有继承其他类 默认继承Object类
package com.zhiyou100;

public class Test03Extends {
    public static void main(String[] args) {
               Zi03 zi1=new Zi03();
               //特点1: 子类可以继承父类中定义的所有成员
               System.out.println(zi1.f1+":"+zi1.f2);//zi03_f1:Fu01_f2
               zi1.method01();
               zi1.method02();
               //特点2:子类可以定义子类特有的成员
               System.out.println(zi1.a);
               //特点3:子类不能继承父类的构造方法
               //zi1=new Zi03(1);
               //特点4:子类可以重新定义父类已有的成员变量:要求变量名相同即可
               System.out.println(zi1.f1);//11
               //特点5:子类可以重新定义父类已有的成员方法:override重写
               //       要求:方法名相同 参数列表相同 返回值类型相同
               //             方法声明必须和父类一致
              zi1.method02();//zi03_method02222
               //特点6:java中只支持类与类的单继承:一个子类只能继承一个直接父类
               System.out.println(zi1.c);
               //特点7:一个类没有继承其他类 默认继承Object类
               zi1.toString();
    }
}
class Fu033 {//默认继承Object:::lass Fu033 extends Object
    int c=1;
}
class Fu03 extends  Fu033{
    String f1="Fu01_f1";
    String f2="Fu01_f2";
    void method01(){
        System.out.println("Fu01_method01");
    }
    void method02(){
        System.out.println("Fu01_method02");
    }
    Fu03(){}
    Fu03(int i){}
}
class Zi03 extends Fu03{
     // String f1="zi03_f1";
     int f1=11;//重新定义父类的成员变量
     int a=1;//子类特有成员变量
     void hehe(){}//子类特有的成员方法

    void method02(){//子类重新定义父类的成员方法
        System.out.println("zi03_method02222");
    }
}

5.10、 重写 override

重写概念

重写:override
     子类根据自己的需求重新定义父类已有成员方法
     类似于生物中的进化
要求:方法声明必须和父类完全相同     

5.11、 super

super概念

super:是关键字  父类的(我父亲的)
this:是关键字   当前对象的(我自己的)

super使用场景

  • 参照this
使用场景1:
     成员变量和局部变量重名时  变量名默认指向的是局部变量  通过this.变量名来指向成员变量
     注意:方法体中涉及的所有成员前面 默认有this.
使用场景2:
     构造方法之间的相互调用 通过this(参数列表)
     注意:this(参数列表)必须是第一个语句
  • super使用
使用场景1:
     子类重新定义父类的成员  子类方法中调用此成员默认调用的是子类中的成员 
     通过super.成员来调用从父类继承而被隐藏的成员
     注意:子类方法中调用父类成员 前面默认都super.
使用场景2:
     所有的子类构造方法第一个语句默认是super()来调用父类无参数的构造方法
     如果父类没有无参数的构造方法 子类构造方法需要显式的通过super(参数列表)来调用父类其他构造方法
package com.zhiyou100;

public class Test04Super {
    public static void main(String[] args) {
        Zi04 zi1=new Zi04();
        zi1.show();
        System.out.println(zi1.a+"::"+zi1.e);
    }
}
class Fu04{
    int b=3;
    int a=1;
    int c=1;
    int e=1;
    void hehe(){
        System.out.println("fu hehe");
    }
    //Fu04(){}
    Fu04(int b,int c,int e){this.b=b;this.c=c;this.e=e;}
}
class Zi04 extends Fu04{
    void hehe(){
        System.out.println("zi hehe");
    }
    int a=2;
    void show(){
        //子类重新定义父类的成员:子类方法中调用的成员 默认是子类的成员
        System.out.println("a="+a);//a=2
        hehe();//zi hehe
        //子类方法中通过super.成员 来调用父类因被重新定义而被隐藏的成员
        System.out.println("super.a="+super.a);//super.a=1
        super.hehe();//fu hehe
        //注意:子类方法中调用父类成员 前面默认有super.
        System.out.println("b="+b);//
    }
    Zi04(){
        super(1,2,2);
    }
    Zi04(int b,int c,int e){
        //super();
        //子类构造方法中调用父类构造方法 通过super(参数列表)
        super(b,c,e);
        //所有子类构造方法的第一个语句默认super()来调用父类无参数的构造方法
    }

}

5.12、 final

概念

final是修饰符:
   修饰类--最终类
   修饰方法--最终方法
   修饰变量--常量 (既可以成员变量也可以是局部变量)

特点

  • final修饰符类不能被继承
  • final修饰符的方法不能被重写
  • final修饰的变量是常量 只能赋值一次 、没有默认初始值
package com.zhiyou100;

public class Test05Final {
    public static void main(String[] args) {
        //final类的特点:final修饰的类不能被继承
        Test05  test05=new Test05();
        //final变量的特点1: final修饰的变量称之为常量:只能赋值一次
        int a=1;
        final int b=1;
        //final变量的特点2:final修饰的成员变量没有默认值  必须显式赋值

        //使用:项目中大量使用身份证号:410195198502222222
        //final变量命名规范:所有字母大写 通过下划线分割单词 WO_DE_MING_ZI   "苗天宝"
        final String ID="410195198502222222";
         //作用:增加可读性+简化书写
    }
}
//class Test05 extends Test051{ }//报错
final class Test051{}
class Test05{
    int a;
    final int b=1;//final修饰的成员变量没有默认值  必须显式赋值
    //final int b=1;Test05创建的所有对象的b属性 值都是1 而且不能更改
    final int c;
    Test05(int c){this.c=c;}//这样 就可以根据
    void hehe(){}
    final void hai(){}
}
class Test052 extends  Test05{
    Test052(){super(1);}//
    void hehe(){}//重写父类的方法
    //final void hai(){}//final方法特点:final方法不能被重写
}
//班训:天道酬勤 不忘初衷

5.13、 范围修饰符

概念

关键字:指定被修饰者作用范围的关键字
可以修饰:类+成员变量+成员方法
范围修饰符:public(公共的)+protected(受保护的)+(省略的)+private(私有的)

测试范围

image-20210826154958929

5.14、 继承内存图

image-20210826161024093

5.15、 abstract

abstract概念

abstract:抽象的:修饰符:修饰符类和方法
抽象:笼统 模糊 不清晰 信息不完整

abstract特点

1 抽象方法不能有方法体
2 有抽象方法的类必须是抽象类
3 抽象类不能创建对象 但可以定义引用
4 子类继承抽象类 除非实现所有的抽象方法 否则仍然是抽象类
5 抽象类有构造方法:此构造方法不是用于创建本类对象 而是用于帮助创建子类对象
package com.zhiyou100;

public class Test07Abstract {
    public static void main(String[] args) {
        //特点1:抽象方法不能有方法体:
        //特点2:有抽象方法的类 必须是抽象类
        //       注意:抽象类中可以没有抽象方法
        //特点3: 抽象类可以定义引用  但不能创建对象
        //特点4: 子类除非实现父类所有的抽象方法 否则子类任然是抽象类
        //特点5:  抽象类有构造方法 不是用来创建本类对象 而是用于创建子类对象的
        Test07 t1;
       // t1=new Test07();
        new Test07Zi1().show();
    }
}
abstract class Test07{
     void show(){}
     abstract void hai();
}
 class Test07Zi1 extends  Test07{
     Test07Zi1(){
         super();
     }
    void hai(){}//实现父类的所有抽象方法
}
abstract class Test07Zi2 extends  Test07{}//子类还是抽象类

/*1 模拟:台灯和灯泡:
    台灯有开始和关闭方法  台灯上面可以安装灯泡
    灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
 *
 *2 默认:饲养员拿食物喂动物
    给狗喂骨头
    给兔喂胡萝卜
 * */

5.16、 私有化封装

  • 概念
封装: 让本类的成员对可信任的类和对象可见  对不可信任的类和对象隐藏
  • 代码
package com.zhiyou100;

public class Test01Private {
    public static void main(String[] args) {
             Test01 t1=new Test01();//其他类中的对象
             //t1.age=-1; t1.sex='妖';//此对象t1是不可信任的对象  赋值的范围Test01类无法控制
             //不可信任的类或者对象 只能简介的通过get set方法访问封装的成员
              t1.setAge(-1);//通过方法 赋值就可控了
              System.out.println("age="+t1.getAge());
              //开发中:所有的属性必须私有化封装
              //get方法格式:public 类型  getXxx();
              //set方法格式:public void setXxx(类型 xxx);
    }
}
class Test01{
    private int age;
    char sex;
    void show(){
         System.out.println("年龄="+age+",性别="+sex);
    }

    public static void main(String[] args) {
        Test01 t1=new Test01();//本类中的对象
        t1.age=28;
        t1.sex='男';
        System.out.println(t1.age+":::"+t1.sex);
    }
    public void setAge(int age){
        if(age<=0||age>=120){return;}
        this.age=age;
    }
    public int getAge(){return this.age;}
}

5.17、 多态(重点)

1 什么是多态

让父类引用指向子类对象
   (给子类对象起个父类类型的名字)
   (把子类对象伪装成父类类型)
格式:父类引用=子类对象;  等号两边两种形态
多态对象:我们自己方便区分定义的一个概念:::被伪装成父类类型的子类对象
向上转型:让父类引用指向子类对象的过程

2 多态的对象有什么特点

1: 子类特有成员被隐藏
2:子类重新定义的成员变量 显示的是父类中定义的
3:子类重写的方法 使用的是子类中定义的
总结成一句话:::多态对象除了重写的方法 其他和父类对象完全相同

3 什么时候使用多态

使用场景1:

定义方法参数列表时 定义为父类类型 这样就可以传递任意子类类型的对象

  • 案例
饲养员给多种动物喂食 喂食完后运动
  • 不使用多态实现
package com.zhiyou100;

public class Test031DuoTaiUse {
    public static void main(String[] args) {
         Dog d=new Dog("哈士奇");
         Pig p=new Pig("乔治");
         Rabbit r=new Rabbit("兔八哥");
         wei(d);
         wei(p);
         wei(r);
         /*
            缺点:1 扩展性差
                  如果有新的动物:需要创建类描述此新类型的动物  并且还需要更改Test031DuoTaiUse 为新类型添加一个wei方法
                 2 代码复用性差
                   如果有一百种动物  需要为每种动物都写一个wei方法
          * */
    }
    //由于喂养的动物的类型不同  必须写三个重载的方法 分别指定要喂养的动物的类型
    //喂狗
    static void wei(Dog d){
        System.out.println("饲养员正在喂养动物:"+d.name);
        d.yunDong();
    }
    //喂兔子
    static void wei(Pig d){
        System.out.println("饲养员正在喂养动物:"+d.name);
        d.yunDong();
    }
    //喂猪
    static void wei(Rabbit d){
        System.out.println("饲养员正在喂养动物:"+d.name);
        d.yunDong();
    }

    static void wei(Cat d){
        System.out.println("饲养员正在喂养动物:"+d.name);
        d.yunDong();
    }
}
//三种动物
class Dog{
    String name;
    Dog(String name){this.name=name;}
    void yunDong(){
        System.out.println("狗"+name+":吃饱了 开始捉老鼠玩!");
    }
}
class Pig{
    String name;
    Pig(String name){this.name=name;}
    void yunDong(){
        System.out.println("猪"+name+":吃饱了 睡觉!");
    }
}
class Rabbit{
    String name;
    Rabbit(String name){this.name=name;}
    void yunDong(){
        System.out.println("兔"+name+":吃饱了 游戏!");
    }
}

class Cat{
    String name;
    Cat(String name){this.name=name;}
    void yunDong(){
        System.out.println("兔"+name+":吃饱了 晒太阳!");
    }
}

  • 缺点
 缺点:1 扩展性差
        如果有新的动物:需要创建类描述此新类型的动物  并且还需要更改Test031DuoTaiUse 
                    为新类型添加一个wei方法
      2 代码复用性差
        如果有一百种动物  需要为每种动物都写一个wei方法
  • 使用多态实现
package com.zhiyou100;

public class Test032DuoTaiUse {
    public static void main(String[] args) {
         Dog2 d=new Dog2("哈士奇");
         Pig2 p=new Pig2("乔治");
         Rabbit2 r=new Rabbit2("兔八哥");
         wei(d);//Animal2 a=d;//多态
         wei(p);//Animal2 a=p;//多态
         wei(r);//Animal2 a=r;//多态

        //多态使用场景1: 定义方法参数列表时 定义为父类类型 这样就可以传递任意子类类型的对象
        //优点:1 增加了扩展性
        //       有新的类型时  只需要此新类型继承Animal2 实现yunDong方法即可 不需要更改Test032DuoTaiUse类 即可使用wei方法
        //     2 增加了代码复用性
        //       只需要写一个wei方法 即可实现喂所有的动物

        /*
           1 定义三个类:Square  rect circle
        *     写一个方法:根据参数int n的值 返回不同类型的对象:n>0返回正方形 n<0 返回长方形 n==0返回圆
  
           3  定义三个类:Square  rect circle
              写一个方法返回一个数组:此数组种要装2个圆 2个长方形 2个正方形
        * */
    }
    //4 定义方法时  把参数两边定义为父类类型
    static void wei(Animal2 a){
        System.out.println("饲养员正在喂养动物:"+a.name);
        a.yunDong();
    }

}
//1  定义一个父类 描述所有的动物
//抽取所有子类的共同数据和功能
abstract class Animal2{
    String name;
    Animal2(String name){this.name=name;}
    //每种动物都有yunDong方法  但yunDong方法的实现过程 都不同
    //由于不知道animal的具体类型  信息不完整  所以父类Animal2的yunDong方法 无法实现
    abstract void yunDong();
}
//2 让所以的具体的动物类继承Animal2类
//三种动物
class Dog2 extends  Animal2{
    Dog2(String name){super(name);}
    //3 根据子类的需求实现父类的yunDong方法
    //重写父类的抽象方法---实现
    void yunDong(){
        System.out.println("狗"+name+":吃饱了 开始捉老鼠玩!");
    }
}

class Pig2 extends  Animal2{
    Pig2(String name){super(name);}
    void yunDong(){
        System.out.println("猪"+name+":吃饱了 睡觉!");
    }
}

class Rabbit2 extends  Animal2{
    Rabbit2(String name){super(name);}
    void yunDong(){
        System.out.println("兔"+name+":吃饱了 游戏!");
    }
}

class Cat2 extends  Animal2{
    Cat2(String name){super(name);}
    void yunDong(){
        System.out.println("猫"+name+":吃饱了 晒太阳!");
    }
}
  • 优点
1 增加了扩展性
  有新的类型时  只需要此新类型继承Animal2 实现yunDong方法即可 不需要更改Test032DuoTaiUse类 
  即可使用wei方法
2 增加了代码复用性
  只需要写一个wei方法 即可实现喂所有的动物

使用场景2:

定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象

  • 案例
2 模拟:台灯和灯泡:
台灯有开始和关闭方法  台灯上面可以安装灯泡
灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
  • 不用多态实现
package com.zhiyou100;

//台灯和灯泡:
//台灯有开始和关闭方法  台灯上面可以安装灯泡
//灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
public class Test041DuoTaiUse {
    public static void main(String[] args) {
        RedBulb  r=new RedBulb();
        Lamp l=new Lamp();
        //给台灯的灯泡属性red赋值
        l.red=r;
        l.on();
    }
    /*
    * 缺点:
    * 1 扩展性差
    *     当前台灯只能安装红灯跑和绿灯跑  如果有新的类型的灯泡 需要对台灯类lamp修改
    *     添加此灯泡类型的属性才行
    * 2 代码复用性差
    *     Lamp类中定义的灯泡类型 只能接受某一种类型的灯泡对象
    *     如果有10种类型的灯泡  就需要定义10个不同类型的成员变量
    * */
}
//红灯泡
class RedBulb{
    void light(){
        System.out.println("红灯泡 发出红光---------------");
    }
}
//绿灯泡
class GreenBulb{
    void light(){
        System.out.println("绿灯泡 发出绿光++++++++++++++");
    }
}
//台灯
class Lamp{
     //灯泡是台灯的一部分:需要把灯泡定义为台灯的成员变量
    RedBulb red;//只能安装红灯泡
    GreenBulb green;//只能安装绿灯泡
    void on(){//把灯泡作为成员变量传递给on方法
       if(red!=null){
           red.light();
       }
       if(green!=null){
           green.light();
       }
    }
    //类种的方法可以使用的数据:成员变量+参数列表
    //判断数据是不是当前类的一部分 如果是就定义为成员变量  如果不是就定义为参数列表
//   void on(RedBulb red){//把灯泡作为参数列表传递
//        red.light();
//   }
}
  • 缺点
    * 1 扩展性差
    *     当前台灯只能安装红灯跑和绿灯跑  如果有新的类型的灯泡 需要对台灯类lamp修改
    *     添加此灯泡类型的属性才行
    * 2 代码复用性差
    *     Lamp类中定义的灯泡类型 只能接受某一种类型的灯泡对象
    *     如果有10种类型的灯泡  就需要定义10个不同类型的成员变量
  • 使用多态实现
package com.zhiyou100;

//台灯和灯泡:
//台灯有开始和关闭方法  台灯上面可以安装灯泡
//灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
public class Test042DuoTaiUse {
    public static void main(String[] args) {
        RedBulb2  r=new RedBulb2();
        GreenBulb2 g=new GreenBulb2();
        Lamp2 l=new Lamp2();
        //给台灯的灯泡属性red赋值
        l.b=r;//多态:Bulb2  b=r;
        l.on();
        l.b=g;//多态:Bulb2  b=r;
        l.on();
    }
    /*
     * 优点:
     * 1 扩展性强
     * 2 代码复用性强
     * */
}
//1 定义父类:抽取所有子类的共同成员
abstract class Bulb2{
    //不知道灯泡的具体类型  但只知道有发亮功能  信息不完整 定义为抽象方法
    abstract void light();
}
//红灯泡
//2 让子类继承父类
class RedBulb2 extends Bulb2{
    //3 子类根据自己的需求 实现父类的抽象方法
    void light(){
        System.out.println("红灯泡 发出红光---------------");
    }
}
//绿灯泡
class GreenBulb2 extends Bulb2{
    //3 子类根据自己的需求 实现父类的抽象方法
    void light(){
        System.out.println("绿灯泡 发出绿光++++++++++++++");
    }
}
//台灯
class Lamp2{
    //灯泡是台灯的一部分:需要把灯泡定义为台灯的成员变量
    //4 定义成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象
    Bulb2  b;
    void on(){//把灯泡作为成员变量传递给on方法
        b.light();
    }
}
  • 优点
     * 1 扩展性强
     * 2 代码复用性强

使用场景3:

定义方法返回值类型时 定义为父类类型 这样就可以返回返回任意子类类型的对象

  • 案例
//  定义三个类:Square  rect circle
//  写一个方法:根据参数int n的值 返回不同类型的对象:
//        n>0返回正方形 n<0 返回长方形 n==0返回圆
  • 只能通过多态实现
package com.zhiyou100;

import javafx.scene.shape.Circle;

//  定义三个类:Square  rect circle
//  写一个方法:根据参数int n的值 返回不同类型的对象:
//        n>0返回正方形 n<0 返回长方形 n==0返回圆
public class Test051DuoTaiUse {
    public static void main(String[] args) {
           Shape01 s=get(1);//多态:Shape01 s=new Square01(1);
    }
    //此方法的返回值类型写成任意一个具体的形状类型都不合适
    //4 定义方法返回值类型时 定义为父类类型 这样就可以返回任意子类类型的对象
    public static  Shape01    get(int n){
        if(n>0){
            return new Square01(1);
        }
        if(n<0){
            return new Rect01(2,1);
        }
        return new Circle01(1);
    }
}
//1 定义一个父类 描述所有的形状类型:::抽取所有子类的共同成员
abstract class  Shape01{
    abstract void show();//信息不完整 show方法体无法实现 定义为抽象方法
}
//2 所有的子类继承父类
class Square01 extends Shape01{
    int bianChang;
    Square01(int bianChang){this.bianChang=bianChang;}
    //3 根据自己的需求实现show方法
    void show(){
        System.out.println("正方形:边长="+bianChang);
    }
}
class Rect01 extends Shape01{
    int chang,kuan;
    Rect01(int chang,int kuan){this.chang=chang;this.kuan=kuan;}
    void show(){
        System.out.println("长方形:长="+chang+",宽="+kuan);
    }
}
class Circle01 extends Shape01{
    int r;
    Circle01(int r){this.r=r;}
    void show(){
        System.out.println("圆形:半径="+r);
    }
}

使用场景4:

定义数组的元素类型时 定义为父类类型 这样就可以装任意子类类型的对象

  • 案例
 3  定义三个类:Square  rect circle
    写一个方法返回一个数组:此数组种要装2个圆 2个长方形 2个正方形
  • 只能通过多态实现
package com.zhiyou100;

// 3  定义三个类:Square  rect circle
//         写一个方法返回一个数组:此数组种要装2个圆 2个长方形 2个正方形
public class Test061DuoTaiUse {
    public static void main(String[] args) {
        Shape02[] array=getArray();
        for(Shape02 s:array){
            s.show();
        }
    }
    //定义数组的元素类型时  定义为父类类型 这样就可以装任意子类类型的对象
    public static Shape02[]  getArray(){
        Shape02[] arr=new Shape02[6];
        arr[0]=new Circle02(1);
        arr[1]=new Circle02(2);
        arr[3]=new Square02(1);
        arr[4]=new Square02(2);
        arr[2]=new Rect02(2,1);
        arr[5]=new Rect02(3,2);
        return arr;
    }
}

//1 定义一个父类 描述所有的形状类型:::抽取所有子类的共同成员
abstract class  Shape02{
    abstract void show();//信息不完整 show方法体无法实现 定义为抽象方法
}
//2 所有的子类继承父类
class Square02 extends Shape02{
    int bianChang;
    Square02(int bianChang){this.bianChang=bianChang;}
    //3 根据自己的需求实现show方法
    void show(){
        System.out.println("正方形:边长="+bianChang);
    }
}
class Rect02 extends Shape02{
    int chang,kuan;
    Rect02(int chang,int kuan){this.chang=chang;this.kuan=kuan;}
    void show(){
        System.out.println("长方形:长="+chang+",宽="+kuan);
    }
}
class Circle02 extends Shape02{
    int r;
    Circle02(int r){this.r=r;}
    void show(){
        System.out.println("圆形:半径="+r);
    }
}

总而言之:

1:定义方法参数列表时  定义为父类类型 这样就可以传递任意子类类型的对象
2:定义类的成员变量时  定义为父类类型 这样就可以赋值任意子类类型的对象
3:定义方法返回值类型时 定义为父类类型 这样就可以返回返回任意子类类型的对象
4:定义数组的元素类型时 定义为父类类型 这样就可以装任意子类类型的对象

定义方法的返回值类型、方法参数列表、类的成员变量、数组元素时 ,都定义为父类类型,这样就可以返回、传递、赋值、装任意子类类型的对象

5.18、 多态内存图

image

5.19、 接口 interface

  • 概念
interface:接口
          当一个抽象类所有的方法都是抽象方法时 可以把此类定义为接口
    如:Shape类    
接口使用:和抽象类完全相同
接口作用:给实现类定义规范
关键字:interface
注意:接口与类不是同一种形态
  • 特点
1 接口中的成员变量默认修饰符:public static final
2 接口中的成员方法默认修饰符:public abstract
3 接口不是用于创建对象 没有构造方法
4 类"继承"接口--实现  此类称为接口的实现类 关键字implements
5 java支持一个类可以实现多个接口 并且不影响其继承父类
6 接口不能创建对象 但可以定义引用 来指向实现类类型的对象
7 java支持接口之间的多继承
  • 代码
package com.zhiyou100;

public interface Test071Interface {
       void show();//1 接口中的成员方法默认修饰符  public abstract
       int a=1;    //2 接口中的成员变量默认修饰符  public static final
                   //3 接口没有构造方法
                   //4 子类"继承"接口 成为实现 关键字implements
                   //     此子类称为接口的实现类
                   //5  java支持一个类可以实现多个接口 并且不影响其继承父类
                   //    eg:class Test07Zi1 extends Object implements  Test071Interface,Inte1{}
                   //6  接口不能创建对象 但可以定义引用 来指向实现类类型的对象
                   //    eg:Inte1  t=new Test07Zi1();//多态
                   //7   java支持接口之间的多继承
                    //   interface  Inte3 extends Inte1,Inte2{}
}
class Test07Zi1 extends Object implements  Test071Interface,Inte1{
      public void show(){}
}
interface  Inte1{}
interface  Inte2{}
interface  Inte3 extends Inte1,Inte2{}
class Test07{
    public static void main(String[] args) {
        Inte1  t=new Test07Zi1();//多态
    }
}
  • 作用
接口总的作用 为两个有关联的模块之间定义规范
好处:1 增加程序的扩展性
     2 提高代码的复用性
     3 降低模块之间的耦合度

5.20、package和import

package:包

//class Test01{}
package com.zhiyou100.day06;

public class Test01Package {
	static int a=1;
	
	public static void main(String[] args) {
		   //package的作用:类似于windows的文件夹:对类或者接口的分类管理
		   // 1 类的全称呼是:包名.类名
		   System.out.println(Test01Package.a);  //syso  alt+/自动补齐和提示的快捷键 
		   //没有加包名  默认是本包
		   System.out.println(com.zhiyou100.day06.Test01Package.a);
		   
		   //2 package声明包 必须是当前项目的第一个语句
	}
}

import:引入/导入

package com.zhiyou100.day06;

import java.io.File;
import java.util.Date;//通过import引入了类全称:在当前源文件中  就可以通过类名来表示此类
import java.lang.*; //注意: 所有源文件默认引入java.lang包的所有类
public class Test02Import {

	public static void main(String[] args) {
		Date  date;
		java.util.Date  date2;
		File  file;
		java.io.File file2;
        //注意: 所有源文件默认引入java.lang包的所有类
		System.out.println(111);
	}
}

5.21、 instanceof

概念

instanceif是关键字
          是运算符
instanceof作用:判断对象的类型
          使用:用于判断多态对象的具体类型

5.22、 向下转型

package com.zhiyou100.day06;

public class Test03Instanceof {
	
	public static void main(String[] args) {
		 //1 创建一个数组 装2个正方形 2个长方形 2个圆形
		 //  定义数组时 元素类型定义为父类类型 这样就可以装任意子类类型的对象
		
		 //2 调用方法 接受数组
		  Shape01[]  array=Test03Instanceof.getArr();//当前类的静态方法
		  
		 //3 获取每个元素的  获取对象的特有成员
		  for(Shape01 s:array){
			   s.show();
//			   System.out.println("s instanceof Shape01 "+(s instanceof Shape01));
//			   System.out.println("s instanceof Square01 "+(s instanceof Square01));
//			   System.out.println("s instanceof Rect01 "+(s instanceof Rect01));
//			   System.out.println("s instanceof Circle01 "+(s instanceof Circle01));
			   			   		   
			   //Square01  sq=(Square01)s;
			   //System.out.println("边长="+sq.bianChang);
			   //向下转型时:ClassCastException: 要转型的类型与具体类型不一致  
			   //避免ClassCastException异常:向下转型时  必须通过instanceof判断 多态对象的具体类型
			   
			   //通过instanceof判断当前多态对象的具体类型	
			   if(s instanceof Square01){
				    //向下转型:把多态对象 打回原型
				    //向下转型格式: 子类引用=(子类类型)多态对象;
				    Square01  sq=(Square01)s;
				    System.out.println("边长="+sq.bianChang);
			   }else  if(s instanceof Rect01){
				    Rect01  sq=(Rect01)s;
				    System.out.println("chang="+sq.chang+",宽="+sq.kuan);
			   }else  if(s instanceof Circle01){
				    Circle01  sq=(Circle01)s;
				    System.out.println("半径="+sq.r);
			   }
		  }
	}
	// 写一个方法返回一个数组
	public static Shape01[]  getArr(){
		Shape01[]   arr=new Shape01[6];
		arr[0]=new Square01(1);
		arr[1]=new Rect01(2, 1);
		arr[2]=new Circle01(1);
		arr[3]=new Square01(2);
		arr[4]=new Rect01(3, 2);
		arr[5]=new Circle01(2);//多态::向上转型
		return arr;
		
	}
}
//1 定义接口:为所有实现类定义规范
//如果一个类 所有的方法都是抽象的  可以定义为接口
interface Shape01{
	void show();
}
//2 根据接口创建实现类
class Square01 implements Shape01{
	//特有成员
	int bianChang;
	Square01(int bianChang){this.bianChang=bianChang;}
	//根据实现类需求  实现接口的方法
	public void show(){
		  System.out.println("正方形::边长="+bianChang);
	}
}
//2 根据接口创建实现类
class Rect01 extends Object implements Shape01{
	//特有成员
	int chang,kuan;
	
	public Rect01(int chang, int kuan) {//alt + shift + s
		//super();//Object
		this.chang = chang;
		this.kuan = kuan;
	}

	//根据实现类需求  实现接口的方法
	public void show(){
		  System.out.println("长方形::chang="+chang+",kuan="+kuan);
	}
}
//2 根据接口创建实现类
class Circle01 implements Shape01{
	//特有成员
	int r;
	
	Circle01(int r){this.r=r;}
	//根据实现类需求  实现接口的方法
	public void show(){
		  System.out.println("圆形::半径="+r);
	}
}
posted @ 2021-08-23 18:57  RenVei  阅读(78)  评论(0编辑  收藏  举报