当前位置: 首页 > article >正文

day02_Java基础

文章目录

  • day02_Java基础
    • 一、今日课程内容
    • 二、数组(熟悉)
      • 1、定义格式
      • 2、基本使用
      • 3、了解数组的内存图介绍
      • 4、数组的两个小问题
      • 5、数组的常见操作
    • 三、方法(熟悉)
      • 1、定义格式
      • 2、方法重载overload
    • 四、面向对象(掌握)
      • 1、类的定义与使用
      • 2、构造方法
      • 3、封装
      • 4、继承
      • 5、多态
      • 6、两个关键字
      • 7、抽象类
      • 8、接口
      • 9、内部类
    • 五、作业

day02_Java基础

一、今日课程内容

  • 1- 数组(熟悉)

  • 2- 方法(熟悉)

  • 3- 面向对象(掌握)

今日目的:面向对象

二、数组(熟悉)

​ 和Python中一样, Java中也是有用来同时存储多个同类型元素的容器的, 那就是: 数组。在一个数组中,数据元素的类型是唯一的,即一个数组中的元素的类型相同。

1、定义格式

  • 方式一: 动态初始化 (我们给定长度, 由系统给出默认初始化值)
格式一: 数据类型[] 数组名 = new 数据类型[长度];

格式二: 数据类型 数组名[] = new 数据类型[长度];

解释: 上述两种定义方式只是写法不同, 并无其他区别。推荐使用格式一

  • 方式二: 静态初始化(我们给定初始化值, 由系统指定长度)
格式一:
	数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, 元素3};		

格式二:
	数据类型[] 数组名 = {元素1, 元素2, 元素3};

解释: 上述两种定义方式只是写法不同, 并无其他区别. 推荐使用格式二

数组中的每个元素都是有编号的, 且编号是从0开始的. 可以方便我们快速操作数组中的元素.

解释: 编号也叫索引(这个是最常见的念法), 下标、角标、index
注意: Java中的数组只有正向索引,没有负向索引。

数组中每个元素都有默认值.

例如:
int类型数组, 元素默认值是: 0
double类型的数组, 元素默认值是: 0.0
boolean类型的数组, 元素默认值是: false
String类型的数组, 元素默认值是: null

2、基本使用

  • 1- 通过数组名[索引]的形式, 可以快速获取数组中的指定元素
格式: 数组名[索引]

例如:
int[] arr = {11, 22, 33};
System.out.println(arr[0]);	//打印结果是: 11
  • 2- 通过数组名[索引] = 值;的方式, 可以修改数组中的指定元素值.
格式: 
	数组名[索引] = 值;

 //例如:
int[] arr = {11, 22, 33};
System.out.println(arr[1]);	//打印结果是: 22
arr[1] = 222;
System.out.println(arr[1]);	//打印结果是: 222
  • 3- 通过数组名的length方法, 可以获取数组的长度
格式: 数组名.length

例如:
int[] arr = {11, 22, 33};
System.out.println(arr.length);	//打印结果是: 3

案例实现:

package com.itheima;

import java.util.Arrays;

public class Test09 {
    public static void main(String[] args) {
        //1. 创建一个数组
        // 方式一: 动态指定, 构建数组的时候, 只需要指定长度即可
        int[] arr1 = new int[10];
        //int arr2[] = new int[10];

        // 方式二: 静态指定, 构建数组的时候, 直接指定数组中每一个元素的值
        //double[] arr3 = new double[]{3.5,6.2,1.3,4.5};
        double[] arr4 = {3.5,6.2,1.3,4.5};


        //2. 执行相关的操作
        // 2.1 如何获取数组中指定位置的元素: 在数组中, 通过索引下标的方式获取, 默认下标从0开始
        int e1 = arr1[2];
        System.out.println(e1);

        double e2 = arr4[3];
        System.out.println(e2);

        //double e3 = arr4[4]; // 注意: 当获取超出数组范围的数据时候, 会报出如下的错误: ArrayIndexOutOfBoundsException
        //System.out.println(e3);

        // 2.2 如何为数组中元素进行重新赋值
        arr1[2] = 10;
        System.out.println(arr1[2]);

        // 2.3 如何获取数组的长度:
        int length = arr4.length;
        System.out.println(length);

        // 2.4 遍历数组
        System.out.println("-------------------");
        // for循环
        for(int i = 0; i< arr4.length; i++){
            System.out.println(arr4[i]);
        }
        // while循环
        System.out.println("-------------------");
        int i = 0;
        while(i< arr4.length){
            System.out.println(arr4[i]);

            i++;
        }

        // 增强for: 迭代器   快捷键:  iter + 回车   此种方式与Python中For循环有一些相似了
        System.out.println("-------------------");
        for (double v : arr4) {
            System.out.println(v);
        }
        System.out.println("-------------------");
        // 2.5 将arr4中数据进行反转操作
        double[] arr5 = new double[arr4.length];

        for(int j = arr4.length-1; j >= 0; j--){
            arr5[arr4.length -1 - j] = arr4[j];
        }

        System.out.println(Arrays.toString(arr5)); // 将数组以字符串的形式打印出来

        // 演示 小错误:
        String[] arr6 = new String[10];

        String e3 = arr6[2]; // 注意 e3 = Null
        e3.concat("xxx'"); // 注意: 使用 null 调用API, 会报: NullPointerException (空指针异常)
    }
}

3、了解数组的内存图介绍

​ 内存是计算机中的重要原件,也是临时存储区域,作用是运行程序。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。

​ 即: Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

JVM的内存划分

1.栈: 存储局部变量以及所有代码执行的.  
	局部变量: 指的是定义在方法中, 或者方法声明上的变量. 
	特点: 先进后出. 
2.堆: 存储所有new出来的内容(即: 对象).
	特点: 堆中的内容会在不确定的时间, 被GC(垃圾回收)回收. 
3.方法区: 存储字节码文件的.
	字节码文件: 指的是后缀名为.class的文件. 
4.本地方法区:
	和系统相关, 了解即可. 
5.寄存器
	和CPU相关, 了解即可.

以下为一个数组的内存图:

public class ArrayDemo03 {
    public static void main(String[] args) {
        int[] arr = new int[3];
		//打印数组中的第一个元素, 值为: 0
        System.out.println(arr[0]);	
		//[I@1540e19d
        System.out.println(arr);
	}
}

其中[I@1540e19d是arr数组的地址值

在这里插入图片描述

核心点: 当创建一个数组的时候, 由于数组是一个引用类型, 是一个对象, 首先会在堆空间中开辟一块空间, 将数组中数据放置到空间下, 此空间同时也会有一个唯一的地址指向这个空间,  此时变量也是指向此内存空间地址

在这里插入图片描述

4、数组的两个小问题

数组是我们在实际开发中用到的比较多的容器, 在使用它的时候, 很可能会遇到如下的两个问题:

  • 1- 数组索引越界异常(ArrayIndexOutOfBoundsException)
产生原因: 访问了数组中不存在的索引
解决方案: 访问数组中存在的索引即可
  • 2- 空指针异常(NullPointerException)
产生原因: 访问了空对象。即: 对象为空, 你还去调用它的一些方法, 肯定不行
解决方案: 给对象赋具体的值即可

5、数组的常见操作

数组是我们在实际开发中用到的比较多的一种容器, 它的常见操作如下:

  • 遍历数组

  • 获取数组的最值(最大值, 或者最小值)

  • 反转数组

package com.itheima;

import java.util.Arrays;

public class Demo02_数组相关操作 {

    public static void main(String[] args) {
        //1. 创建一个数组
        int[] arr1 = {1,5,6,2,8,4,9,10,0};

        //2. 执行相关的操作
        //2.1 遍历数组
        for (int i : arr1) {
            System.out.println(i);
        }

        // 2.2 获取数组最大值 和 最小值
        int maxV = arr1[0];
        int minV = arr1[0];
        for (int i : arr1) {

            if( maxV < i ) {
                maxV = i;
            }
                

            if( minV > i ) {
				minV = i;
            }
        }
        System.out.println("最大值为:" + maxV);
        System.out.println("最小值为:" + minV);

        // 2.3 如何反转数组
        int[] arr2 = new int[arr1.length];
        for(int i = arr1.length -1; i >= 0 ; i--){
            System.out.println(arr1[i]);

            arr2[arr1.length-1-i] = arr1[i];

        }

        System.out.println(Arrays.toString(arr2));
    }

}

package cn.itcast.object;

import java.util.Arrays;

/**
 * 数组演示:定义和基本操作
 */
public class ArrayDemo {
    public static void main(String[] args) {
        /*
            1-定义数组

            Arrays.toString:数组工具类,用来将数组转成字符串形式
         */
        // 动态定义
        int[] arr1 = new int[5];
        int arr2[] = new int[5];
        double[] arr3 = new double[5];
        System.out.println(Arrays.toString(arr1));
        System.out.println(Arrays.toString(arr3));

        // 静态定义
        int[] arr4 = {1,3,5};
        int[] arr5 = new int[]{2,4,6};
        System.out.println(Arrays.toString(arr4));

        // 数组的基本操作
        // 获取对应索引的值
        System.out.println(arr4[0]);
        System.out.println(arr4[1]);
        System.out.println(arr4[2]);
        //System.out.println(arr4[3]);

        // 给数组中某个索引进行赋值操作
        arr4[1] = 6;
        System.out.println(arr4[1]);
        System.out.println(Arrays.toString(arr4));

        // 获取数组的长度
        System.out.println(arr4.length);

        System.out.println("------------------------------");
        // 遍历数组。常规for循环的快捷方式:.for+回车
        for(int i=0;i<arr4.length;i++){
            System.out.println(arr4[i]);
        }

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

        int minValue = Integer.MAX_VALUE;
        int maxValue = Integer.MIN_VALUE;
        // int maxValue = arr4[0];
        // 获取数组的最值(最大值, 或者最小值)
        for(int j=0;j<arr4.length;j++){
            int tmp = arr4[j];

            if(tmp>maxValue){
                maxValue = tmp;
            }

            if(tmp<minValue){
                minValue = tmp;
            }
        }

        System.out.println(minValue);
        System.out.println(maxValue);

        // 反转数组
        int[] newArr = new int[arr4.length];
        for(int j=0;j<arr4.length;j++) {
            newArr[j] = arr4[arr4.length-j-1];
        }
        System.out.println(Arrays.toString(newArr));
    }
}

三、方法(熟悉)

​ Python中的函数, 是将具有独立功能的代码块组织成为一个整体,使其成为具有特殊功能的代码集。Java中也是如此。只不过,Java中的函数也叫方法.

1、定义格式

修饰符 返回值的数据类型 方法名(参数类型 参数名1, 参数类型 参数名2) { //这里可以写多个参数
    //方法体;
    return 具体的返回值;	
}

修饰符: 目前记住这里是固定格式public static

返回值的数据类型: 用于限定返回值的数据类型的.
	注意: 
		1.返回值的数据类型是int类型, 则说明该方法只能返回int类型的整数.
		2.如果方法没有具体的返回值, 则返回值的数据类型要用void来修饰,不能省略.

方法名: 方便我们调用方法.  定义的时候 要遵循小驼峰的命名法

参数类型: 用于限定调用方法时传入的数据的数据类型.
	例如: 参数类型是String类型, 说明我们调用方法时, 只能传入字符串.
        
参数名: 用于接收调用方法时传入的数据的变量. 
    
方法体: 完成特定功能的代码。不建议一个方法的内部代码行数过多。
    
return 返回值: 用来结束方法的, 并把返回值返回给调用者. 
	解释: 如果方法没有明确的返回值, 则return关键字可以省略不写.

注意事项:

1.方法与方法之间是平级关系, 不能嵌套定义.
2.方法的定义和调用没有先后顺序的要求
3.方法自身不会直接运行, 而是需要我们手动调用方法后, 它才会执行, 该过程称为方法调用.
4.方法的功能越单一越好. 
5.定义方法的时候写在参数列表中的参数, 都是: 形参. 
	形参: 形容调用方法的时候, 需要传入什么类型的参数.
6.调用方法的时候, 传入的具体的值(变量或者常量都可以), 叫实参. 
	实参: 调用方法时, 实际参与运算的数据.

示例:

需求一: 编写一个方法, 接收数组参数, 实现遍历数组的功能

需求二: 获取数组最值(例如: 最大值)

package com.itheima;

public class Test10_method {
    // main 方法
    public static void main(String[] args) {

        int[] arr1 = {1,4,6,3,8,10,15};
        // 调用方法
        foreachArr(arr1); // 传入的参数为实参

        // 获取数组中最大值
        int maxNum = getMaxNum(arr1);
        System.out.println("最大值为:"+maxNum);
    }

    // 方法的定义
    public static void foreachArr(int[] arr){ // 定义参数为形参
        // 遍历数组
        for (int e : arr) {
            System.out.println(e);
        }
    }

    // 定义方法: 实现获取数组中最大值
    public static int getMaxNum(int[] arr){
        int max = arr[0];
        for (int e : arr) {
            if(e > max)  max = e;
        }

        return max;
    }

}

2、方法重载overload

补充:重写override

​ 同一个类中, 出现方法名相同, 但是参数列表不同的两个或以上的方法时**称为方法重载. **方法重载与方法的返回值的数据类型无关.

注意: 参数列表不同分为两种情况
1.参数的个数不同.
2.对应参数的数据类型不同.

方法重载的总结:
    只关注方法名称  和  形参列表,与返回值类型没关系
    要求方法名称必须相同,而形参列表不同。这里的不同不包括形参的名称

需求

演示方法的重载

package com.itheima.day02;

public class 方法的重载 {
    public static void main(String[] args) {
        System.out.println(myAdd(1, 2));
        System.out.println(myAdd(1.99, 2.0));
    }

    /*
        方法重载的总结:
            只关注方法名称  和  形参列表,与返回值类型没关系
            要求方法名称必须相同,而形参列表不同。这里的不同不包括形参的名称
     */
    public static int myAdd(int num1,int num2){
        return num1+num2;
    }

    // 这种不叫方法的重载
//    public static int myAdd(int num1,int num2222){
//        return num1+num2222;
//    }

    public static double myAdd(double num1,double num2){
        return num1+num2;
    }
}

四、面向对象(掌握)

​ 和Python一样, Java也是一门以面向对象为编程思想的语言, 也有类, 对象的概念, 并且面向对象的三大特征: 封装, 继承, 多态, 在Java中也都是有的, 接下来, 我们来研究下Java中的面向对象应该如何运用.

1、类的定义与使用

定义类其实就是定义类的成员(成员属性/变量和成员方法)

  • 成员变量:

    • 1- 和以前定义变量是一样的, 只不过位置发生了改变, 写到类中, 方法外
    • 2- 而且成员变量还可以不用赋值, 因为它有默认值.
  • 成员方法:

    • 1- 和以前定义方法是一样的, 只不过把static关键字去掉.
    • 2- 这点先记忆即可, 后面我们再讲解static关键字的用法.

定义类的格式:

public class 类名 {
//成员变量, 私有化, 类似于Python中的 __
//构造方法, 空参, 全参, 类似于Python的魔法方法之 __init__(self)
//getXxx(), setXxx()方法, 用来获取或者设置对象的属性值的
    //成员方法, 就是普通的函数
}

使用类中成员的格式:

1.创建该类的对象, 格式如下: 
 类名 对象名 = new 类名();
2.通过对象名.的形式, 调用类中的指定成员即可, 格式如下: 
 //成员变量
 对象名.成员变量

 //成员方法
 对象名.成员方法(参数列表中各数据类型对应的值...)

需求:

1- 定义手机类Phone.

2- 创建测试类PhoneTest, 在类中定义main方法, 并访问手机类(Phone类)中的成员.

属性: 品牌(brand), 价格(price), 颜色(color)

行为: 打电话(call), 发短信(sendMessage)

非私有方案:

package com.itheima.类的使用;

public class Phone {
    // 成员变量
    String brand;
    double price;
    String color;

    public void call(){
        System.out.println("打电话");
    }

    public void sendMessage(){
        System.out.println("发短信");
    }
}


// 测试类
package com.itheima.类的使用;

public class Demo05_phoneTest {

    public static void main(String[] args) {
        //1. 创建 手机类的对象   构建对象 关键词  new

        Phone phone = new Phone();

        //2. 为成员属性赋值:
        phone.brand = "华为";
        phone.color = "祖母绿";
        phone.price = 19999.0;

        //3. 获取成员属性的值
        System.out.println(phone.brand);
        System.out.println(phone.color);
        System.out.println(phone.price);

        //4. 调用成员方法
        phone.call();
        phone.sendMessage();
    }
}

(推荐)私有化方案:

package com.itheima.类的使用;
/*
    权限修饰符
        public: 公共的  一旦方法 或者 类  成员变量 被标记, 可以在其他类中, 甚至其他的项目中 都可以加载到此内容
        private: 私有的  表示 仅在当前类中可用


 */
public class Phone2 {
    // 成员变量 私有化
    private String brand;
    private double price;
    private String color;

    // 为私有的属性 提供 getter 和 setter方法
    // 快捷键:  alt + ins 键

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void call(){
        System.out.println("打电话");
    }

    public void sendMessage(){
        System.out.println("发短信");
    }
}

// 测试类
package com.itheima.类的使用;

public class Demo06_phone2Test {

    public static void main(String[] args) {
        //1. 创建 手机类的对象   构建对象 关键词  new
        Phone2 phone2 = new Phone2();

        //2. 为成员属性赋值
        phone2.setBrand("三星");
        phone2.setColor("土豪金");
        phone2.setPrice(5888);

        //3. 获取成员属性的值
        System.out.println(phone2.getColor());
        System.out.println(phone2.getBrand());
        System.out.println(phone2.getPrice());

        //4. 调用方法
        phone2.call();
        phone2.sendMessage();
    }
}

2、构造方法

Java中的构造方法类似于Python中的魔法方法之_init_(), 就是用来创建对象的, 捎带着可以给对象的各个成员变量赋值.

大白话:

构造方法就是用来快速对对象的各个属性赋值的. 

格式:

  • 1.构造方法名必须和类名完全一致(包括大小写).
  • 2.构造方法没有返回值类型, 连void都不能写.
  • 3.构造方法没有具体的返回值, 但是可以写return(实际开发, 一般不写 基本没见过写的).
public 类名(参数类型 参数名1, 参数类型 参数名2) {  //这里可以写多个参数.
    //给对象的各个属性赋值即可.
}

演示构造的使用:

package com.itheima.类的使用;

public class Stu {
    // 当不写构造方法的时候, 类会默认提供一个空参的构造, 一旦我们书写了构造方法, 默认的构造就不提供了, 如果需要空参的构造, 必须手动写出来
    // 快捷键: alt + ins
    public Stu() {
    }

    public Stu(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Stu(String name) {
        this.name = name;
    }

    public Stu(int age) {
        this.age = age;
    }

    // 属性: 当创建对象的时候,不管是否有赋值操作, 先默认给成员属性进行初始化操作
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


package com.itheima.类的使用;

public class Demo07_stuTest {

    public static void main(String[] args) {
        //1, 创建Stu对象
        //Stu stu = new Stu("张三",30);
        //Stu stu = new Stu();
        //Stu stu = new Stu(50);
        Stu stu = new Stu("李四");
        //2. 赋值
        //stu.setAge(50);

        //3. 获取值
        System.out.println(stu.getAge());
        System.out.println(stu.getName());


    }
}

相关的注意事项:

1.如果我们没有给出构造方法, 系统将给出一个默认的无参构造供我们使用. 
2.如果我们给出了构造方法, 系统将不再提供默认的构造方法给我们使用. 
	2.1 这个时候, 如果我们还想使用无参构造, 就必须自己提供.
    2.2 建议定义类时,我们给出无参构造, 方便用户调用(实际开发都这么做的).

3- 如果需要将这个类构建为一个工具类, 此时这个类的构造方法必须私有化(不允许用户创建这个类对象)
4- Java中一个类里面能够有多个构造方法

3、封装

封装是面向对象编程思想的三大特征之一, 所谓的封装指的就是隐藏对象的属性和实现细节, 仅对外提供一个公共的访问方式.

记忆:

面向对象的三大特征: 封装, 继承, 多态.

问题一: 怎么隐藏?
答案: 通过private关键字实现.

问题二: 公共的访问方式是什么?
答案: getXxx()和setXxx()方法

可能涉及的相关特殊关键词:

  • 1- private关键字
private是一个关键字, 也是访问权限修饰符的一种, 它可以用来修饰类的成员(成员变量和成员方法).

特点: 被private修饰的内容(成员变量和成员方法)只能在本类中直接使用,外界无法直接访问。

应用场景:
	1.在实际开发中, 成员变量基本上都是用private关键字来修饰的.
	2.如果明确知道类中的某些内容不想被外界直接访问, 都可以通过private来修饰. 
  • 2- this关键字
this代表本类当前对象的引用, 大白话翻译: 谁调用, this就代表谁. 

作用:
	用来解决局部变量和成员变量重名问题的.
    类似于python中 self 关键词

4、继承

​ 多个类中存在相同属性和方法时, 将这些内容抽取到单独的一个类中, 那么这多个类就无需再定义这些属性和行为了, 只要继承那个类即可. 这个关系, 就叫继承, Java中, 类与类之间的继承只能单继承,不能多继承,但是可以多层继承.也就是现实生活中,一个人只有一个父亲,也就是单继承;但是还有爷爷,也就是多层继承。

格式:
public class 类A extends 类B {	//子承父业
    
}

解释:
类A: 叫子类, 或者派生类.
类B: 叫父类, 基类, 或者超类.
我们一般会念做: 子类和父类. 

继承关键字是extends

需求:

  • 1.按照标准格式定义一个人类(Person类), 属性为姓名和年龄.

  • 2.定义老师类(Teacher), 继承自人类, 并在老师类中定义teach()方法.

  • 3.定义学生类(Student), 继承自人类, 并在学生类中定义study()方法.

  • 4.在PersonTest测试类的main方法中, 分别创建老师类和学生类的对象, 并调用各自类中的成员.

person类:
package com.itheima.继承;

public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


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

}

学生类:
package com.itheima.继承;

public class Student extends Person {

    public void study(){

        System.out.println(super.getName()+"学生要上课, 课上不能睡觉......");
    }

}


老师类:
package com.itheima.继承;

public class Teacher extends Person {
    public void  teach(){
        System.out.println(super.getName()+"老师,今年已经"+super.getAge()+"岁了, 依然也要教书......");
    }
}

测试类
package com.itheima.继承;

public class Demo08_PersonTest {

    public static void main(String[] args) {

        //1. 创建 学生类  和 老师类 对象
        Student stu = new Student();

        Teacher teacher = new Teacher();

        //2. 设置成员属性
        stu.setName("张三");
        stu.setAge(20);

        teacher.setName("张教授");
        teacher.setAge(40);

        //3. 获取值, 调用方法
        System.out.println(stu.getAge());
        System.out.println(stu.getName());
        stu.study();
        stu.eat();

        System.out.println(teacher.getAge());
        System.out.println(teacher.getName());
        teacher.teach();
        teacher.eat();
    }
}

子类在继承父类的时候, 可以将父类中公共(public)的方法 和 属性 全部都继承, 如果父类中属性和方法被标记为私有化后, 我们无法继承

说明: 继承的好处和弊端

好处:
    1.提高了代码的复用性.
    2.提高了代码的可维护性.
    3.让类与类之间产生关系, 是多态的前提. 
   
弊端:
	让类与类之间产生了关系, 也就让类的耦合性增强了. 
    解释:
		开发原则: 高内聚, 低耦合.
		内聚: 指的是类自己独立完成某些事情的能力.
		耦合: 指的是类与类之间的关系. 

方法的重写:

​ 子类中出现和父类一模一样的方法时, 称为方法重写. 方法重写要求返回值的数据类型也必须一样

方法名称、形参列表(参数个数、参数顺序、参数数据类型)、方法返回值数据类型都需要一样。另外子类方法的访问范围要大于等于父类的范围

什么时候需要使用方法重写:
	当子类需要使用父类的功能, 而功能主体又有自己独有需求的时候, 就可以考虑重写父类中的方法了, 这样, 即沿袭了父类的功能, 又定义了子类特有的内容. 

需求:

  • 1 定义Phone类, 并在类中定义call(String name)方法.

  • 2 定义NewPhone类, 继承Phone类, 然后重写call(String name)方法.

  • 3 在PhoneTest测试类中, 分别创建两个类的对象, 然后调用call()方法, 观察程序执行结果.

phone类:
package com.itheima.继承;

public class Phone {


    public void call(String name){
        System.out.println(name + "打电话");
    }


}


newPhone类:
package com.itheima.继承;

public class NewPhone extends Phone {

    @Override // 此注解表示是当前这个方法是一个重写的方法(仅仅是标记)
    public void call(String name) {
        super.call(name);
        System.out.println(name+"打电话,并且同时视频聊天");
    }

}

测试类
package com.itheima.继承;

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

        //1. 创建 NewPhone类对象
        NewPhone newPhone = new NewPhone();
        newPhone.call("张三");


        System.out.println("=================");
        Phone phone = new Phone();
        phone.call("李四");

    }
}

注意事项:

1.子类重写父类方法时, 方法声明上要用@Override注解来修饰. 
2.父类中私有的方法不能被重写. 
3.子类重写父类方法时, 访问权限不能更低.

子类可以重写父类中公共的方法, 可以针对父类的方法进行增强

5、多态

多态指的是同一个事物(或者对象)在不同时刻表现出来的不同状态.

例如: 一杯水.

• 常温下是液体.

• 高温下是气体.

• 低温下是固体.

但是水还是那杯水, 只不过在不同的环境下, 表现出来的状态不同.

多态使用的前提条件:
1.要有继承关系.
2.要有方法重写.
3.要用父类引用指向子类对象.

简单理解: 父类接收子类对象 (父类指向子类的引用)

示例:

  • 1 定义动物类Animal, 并在类中定义一个成员方法: eat()

  • 2 定义猫类Cat, 继承Animal类, 并重写eat()方法.

  • 2 定义猫类Dog, 继承Animal类, 并重写eat()方法.

  • 3 在AnimalTest测试类的main方法中, 通过多态的方式创建猫类和狗类对象.

  • 4 通过类对象, 调用eat()方法.

package com.itheima.多态;

public class Animal {

    public void eat(){
        System.out.println("动物都要吃......");
    }

}


package com.itheima.多态;

public class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("狗爱吃骨头......");
    }
}



package com.itheima.多态;

public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫爱吃鱼......");
    }


}


package com.itheima.多态;

public class Demo10_AnimalTest {
    // 多态格式: 父类 = 子类对象
    // 多态特性: 编译看左边, 运行看右边
    public static void main(String[] args) {
        //1. 创建一个猫对象
        Animal cat = new Cat();
        cat.eat();


        //2. 创建一个狗 对象
        Animal dog = new Dog();
        dog.eat();
    }
}

多态的好处和弊端

好处: 提高了程序的扩展性. 

弊端:
父类引用不能访问子类的特有功能. 
问:  那如何解决这个问题呢? 
答:  通过向下转型来解决这个问题. (强制类型转换)

上下转型的方式:

向上转型:
格式
父类型 对象名 = new 子类型();

例如: Animal an = new Cat();

向下转型:
格式
子类型 对象名 = (子类型)父类引用;

例如: Cat c = (Cat)an;

示例:

// 向下转型
Animal animal3 = new Cat();
Cat cat = (Cat) animal3; // 向下转型
Dog dog = (Dog) animal3; // 直接报错(ClassCastException 类型转换异常), 因为本身就不是 Dog类型, 所以无法进行向下转型

cat.seize();
System.out.println(animal3);

说明: 向下转型的目的是为了调用子类中特有的方法

package com.itheima.多态;

public class Demo10_AnimalTest {
    // 多态格式: 父类 = 子类对象
    // 多态特性: 编译看左边, 运行看右边
    public static void main(String[] args) {
        //1. 创建一个猫对象
        Animal cat = new Cat();
        cat.eat();


        //2. 创建一个狗 对象
        Animal dog = new Dog();
        dog.eat();

        //3. 调用 execute 方法
        execute(new Dog());
    }

    public static  void execute(Animal animal){
        animal.eat();

        // 判断, 如果传入的类型是 Dog, 请强转为 dog类型, 调用action方法
        // 关键词: instanceof  类型判断 ,   格式:   对象  instanceof 需要判断类型  返回 True表示是这个类型的对象, 返回Flase表示不是这个类型的对象
        if( animal instanceof Dog ){
            Dog dog = (Dog) animal;
            dog.action();
        }

    }
}

6、两个关键字

  • 1- final关键字
final是一个关键字, 表示最终的意思, 可以修饰类, 成员变量, 成员方法. 
•修饰的类: 不能被继承, 但是可以继承其他的类.   称为 最终类
•修饰的变量: 是一个常量, 只能被赋值一次.   称为 常量
•修饰的方法: 不能被子类重写.   既需要别人调用, 又不想让别人重写内部内容, 需要添加final

需求

  • 1 定义Father类, 并定义它的子类Son.

  • 2 先用final修饰Father类, 看Son类是否还能继承Father类.

  • 3 在Son类中定义成员变量age, 并用final修饰, 然后尝试给其重新赋值, 并观察结果.

  • 4 在Father类中定义show()方法, 然后用final修饰, 看Son类是否能重写该方法.

package com.itheima.两个关键词;
// 如果使用final 修饰类, 此类为最终类, 无法被其他类所继承, 但是可以继承其他类
public /*final */  class Father {
    // 既想让其他用户使用, 又不想让其他用户改写我的函数, 此时可以将函数/方法 使用 final修饰
    public final void show(){
        System.out.println("xxxxxxxxxxxxxxxxxx");
    }

}


package com.itheima.两个关键词;

public class Son extends Father {

    final int AGE = 18;  // 一旦被final所修饰, 当前这个变量 只能赋值 1次  称为常量


    /*@Override
    public void show() {

        System.out.println("xxxxxxx");
    }*/
}


package com.itheima.两个关键词;

public class Demo12_final {

    public static void main(String[] args) {
        Son son = new Son();
        //son.age = 18;

        System.out.println(son.AGE);
    }
}

  • 2- static关键字
static是一个关键字, 表示静态的意思, 可以修饰成员变量, 成员方法. 但是不能修饰class类

特点:
1.随着类的加载而加载. (当class文件被加载到JVM方法区的时候, 被static修饰的成员, 也会直接加载, 直接使用)
2.优先于对象存在.
3.被static修饰的内容, 能被该类下所有的对象共享.
	解释: 这也是我们判断是否使用静态关键字的条件. 
4.可以通过  类名.  的形式调用.也就是你不需要创建类的实例对象

静态方法的访问特点及注意事项

访问特点
	静态方法只能访问静态的成员变量和静态的成员方法.
	简单记忆: 静态只能访问静态. 
注意事项
	1.在静态方法中, 是没有this, super关键字的. 
	2.因为静态的内容是随着类的加载而加载, 而this和super是随着对象的创建而存在. 
 		即: 先进内存的, 不能访问后进内存的. 

需求:

  • 1 定义学生类, 属性为姓名和年龄(静态修饰), 非静态方法show1(),show2(), 静态方法show3(), show4().

  • 2 尝试在show1()方法中, 调用: 姓名, 年龄, show2(), show4()

  • 3 尝试在show3()方法中, 调用: 姓名, 年龄, show2(), show4().

package com.itheima.两个关键词;

public class Student3 {

    String name;
    static int age;



    public  void show1(){ // 在 非静态的方法中, 可以使用静态内容 也可以使用非静态的内容
        System.out.println("我是show1...."+name +"  "+ age);

        show2(); // 调用非静态的方法
        show4(); // 调用静态的方法
    }

    public void show2(){
        System.out.println("我是show2....");
    }

    public static void show3(){ // 在静态方法的中, 可以使用静态的成员, 但是不能使用非静态的成员
        System.out.println("我是show3...."+ age);
        
        //show2();
        
        show4();

    }

    public static void show4(){
        System.out.println("我是show4....");
    }
}

静态代码块: 通过 static 对代码块进行修饰, 修饰后 称为 静态代码块

特点: 随着类的加载而加载, 而且一般只会加载一次

放置的位置: 类中 方法外

package com.itheima.两个关键词;

public class Teacher {
    String name;
    String address;
    int age;

    // 随着类的加载而加载, 而且一般只会加载一次
    // 基于静态代码块, 可以进行初始化的操作。例如:数据库连接的创建
    static{
        System.out.println("上课前, 需要进行备课...");
    }

    public  void teach(){
        System.out.println("老师要上某一阶段的课");
    }
}

范围的修饰符(访问范围由大到小排序):public > protected > 没有修饰符default > private

7、抽象类

​ 回想前面我们的猫狗案例, 提取出了一个动物类, 这个时候我们可以通过Animal an = new Animal(); 来创建动物对象, 其实这是不对的, 因为, 我说动物, 你知道我说的是什么动物吗? 只有看到了具体的动物, 你才知道, 这是什么动物. 所以说, 动物本身并不是一个具体的事物, 而是一个抽象的事物. 只有真正的猫, 狗才是具体的动物.

​ 同理, 我们也可以推想, 不同的动物吃的东西应该是不一样的, 所以, 我们不应该在动物类中给出具体的体现, 而是应该给出一个声明即可. 在Java中, 一个没有方法体的方法应该定义为抽象方法, 而类中如果有抽象方法, 该类必须定义为抽象类。抽象类中不是必须要有抽象方法.

​ **抽象类的使用场景:用来定义大多数子类都具备的规则,只不过具体的实现思路每个子类都是不一样的。**因为抽象类需要在下面创建对应的实现子类。

示例需求:

  • 1- 创建抽象类Animal.
  • 2- 在该类中定义抽象方法eat()
package com.itheima.抽象类;
// 说明: 有抽象方法的类 一定是一个抽象类,  在抽象类中可以有非抽象的方法
//  抽象类 和 抽象 方法 都使用 abstract关键词标注
public abstract class Animal {

    public abstract void eat();

    public void run(){
        System.out.println("xxxxx");
    }

}

package com.itheima.抽象类;

public class Demo01_AnimalTest {
    public static void main(String[] args) {
        // 抽象类, 是无法被实例化的(无法创建对象)
        //Animal animal =  new Animal();

    }
}

抽象类的特点:

抽象类和抽象方法必须用abstract关键字修饰.
抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类
抽象类不能实例化.
    – 那抽象类如何实例化呢?
    – 可以通过多态的方式, 创建其子类对象, 来完成抽象类的实例化. 这也叫: 抽象类多态.
抽象类的子类:
    – 如果是普通类, 则必须重写父抽象类中所有的抽象方法.
    – 如果是抽象类, 则可以不用重写父抽象类中的抽象方法. 

需求:

  1. 定义抽象类Animal , 类中有一个抽象方法eat(), 还有一个非抽象方法sleep().
  2. 尝试在测试类中, 创建Animal类的对象, 并观察结果.
  3. 创建普通类Cat, 继承Animal类, 观察是否需要重写Animal#eat()方法.
  4. 创建抽象类Dog, 继承Animal类, 观察是否需要重写Animal#eat()方法.
package com.itheima.抽象类;
// 说明: 有抽象方法的类 一定是一个抽象类,  在抽象类中可以有非抽象的方法
//  抽象类 和 抽象 方法 都使用 abstract关键词标注
public abstract class Animal {

    public abstract void eat();

    public void sleep(){
        System.out.println("动物都要睡觉...");
    }

}


package com.itheima.抽象类;

public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫吃鱼......");
    }
}


package com.itheima.抽象类;

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头......");
    }
}

package com.itheima.抽象类;

public class Demo01_AnimalTest {
    public static void main(String[] args) {
        // 抽象类, 是无法被实例化的(无法创建对象)
        //Animal animal =  new Animal();

        // 创建实例对象
        Dog dog = new Dog();
        dog.eat();
        dog.sleep();

        Cat cat = new Cat();
        cat.eat();
        cat.sleep();

        // 多态的方式
        Animal animal_1 = new Dog();
        Animal animal_2 = new Cat();

        animal_1.eat();  // 编译看左边, 运行看右边
        animal_1.sleep();

    }
}

8、接口

​ 继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能

​ 所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被训练,只需要这部分猫狗把这些额外功能实现即可。

​ 接口中的内容, 都是抽象的, 一般是用于定义规则 协议

接口的使用场景:接口是一种特殊的抽象类。用来定义规则的,但是这些规则只有少部分类才具备的特点。

接口的特点:

1.接口用interface关键字修饰.
2.类和接口之间是实现关系, 用implements关键字表示.
3.接口不能实例化.
	– 那接口如何实例化呢?
	– 可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态.
4.接口的子类:
	– 如果是普通类, 则必须重写父接口中所有的抽象方法.
	– 如果是抽象类, 则可以不用重写父接口中的抽象方法. 

需求:

1 定义Jumpping接口, 接口中有一个抽象方法jump().

2 定义Cat类, 实现Jumpping接口, 重写jump()方法.

3 在测试类的main方法中, 创建Jumpping接口对象, 并调用其jump()方法

package com.itheima.接口;

public interface Jumpping {
    public  void jump();
}


package com.itheima.接口;

public class Cat implements Jumpping {
    @Override
    public void jump() {
        System.out.println("猫可以钻火圈......");
    }
}


package com.itheima.接口;

public class Demo02_jumppingTest {

    public static void main(String[] args) {
        Jumpping jumpping = new Cat();
        jumpping.jump();
    }

}

类与接口之间的关系

  • 类与类之间: 继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
  • 类与接口之间: 实现关系, 可以单实现, 也可以多实现. 还可以在继承一个类的同时实现多个接口.
  • 接口与接口之间: 继承关系, 可以单继承、多层继承, 也可以多继承.

综合案例:

  1. 已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).
  2. 他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.
  3. 乒乓球教练教如何发球, 篮球教练教如何运球和投篮.
  4. 乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.
  5. 为了出国交流, 跟乒乓球相关的人员都需要学习英语.
package com.itheima.接口综合案例;

public abstract class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public abstract void eat();

}



package com.itheima.接口综合案例;

public abstract class Coach extends Person {

    public abstract void teach();

}

package com.itheima.接口综合案例;

public class BasketballCoach extends Coach {
    @Override
    public void teach() {
        System.out.println("篮球教练教如何运球和投篮");
    }

    @Override
    public void eat() {
        System.out.println("篮球教练喜欢吃鱼肉......");
    }
}


package com.itheima.接口综合案例;

public class PingPangCoach extends Coach implements Language{
    @Override
    public void teach() {
        System.out.println("乒乓球教练教如何发球");
    }

    @Override
    public void eat() {
        System.out.println("乒乓球教练喜欢吃高蛋白视频: 比如 鸡蛋");
    }

    @Override
    public void studyLanguage() {
        System.out.println("学习英语");
    }
}



package com.itheima.接口综合案例;

public abstract class Player extends Person {

    public abstract void study();
}

package com.itheima.接口综合案例;

public class BasketballPlayer  extends Player{
    @Override
    public void study() {
        System.out.println("篮球运动员学习如何运球和投篮......");
    }

    @Override
    public void eat() {
        System.out.println("篮球运动员喜欢吃日料......");
    }
}


package com.itheima.接口综合案例;

public class PingPangPlayer extends Player implements Language {
    @Override
    public void study() {
        System.out.println("乒乓球运动员学习如何发球");
    }

    @Override
    public void eat() {
        System.out.println("乒乓球运动员喜欢吃麻辣烫......");
    }

    @Override
    public void studyLanguage() {
        System.out.println("学习英语");
    }
}


package com.itheima.接口综合案例;

public interface Language {
    public void studyLanguage();
}

9、内部类

​ 类里边还有一个类, 外边那个类叫做外部类, 里边那个类叫做内部类,Java中不允许方法的嵌套定义。

示例:

public class A {
    public class B{
        
    }
}

A: 外部类
B: 内部类

内部类的分类:

  • 1- 成员内部类(了解)
public class A {	//外部类
	public class B{	//成员内部类
        
    }
}
  • 2- 局部内部类(了解)
public class A {	//外部类
    //外部类的成员方法
    public void show() {
        //局部内部类
        class B {
            
        }
    }
}
  • 3- 匿名内部类(重要)

    • 匿名内部类指的就是没有名字的局部内部类.
    • 格式:
    xxx = new 类名或者接口名() {
      //重写类或者接口中所有的抽象方法
    };
    
    • 本质
    匿名内部类就是一个继承了类或者实现了接口的匿名的子类对象.
    
    简单理解:
    	匿名内部类的本质就是一个子类对象. 
    
    • 应用场景
    •当对对象方法(即: 成员方法)仅调用一次的时候.
    •匿名内部类可以作为方法的实参进行传递.
    
    • 案例需求:

      定义Animal抽象类, 该类中有一个抽象方法eat().

      在测试类的main方法中, 通过匿名内部类的形式创建Animal抽象类的子类对象.

      调用Animal类中的eat()方法

    package com.itheima.内部类;
    
    public abstract class Animal {
        public abstract void eat();
    }
    
    
    package com.itheima.内部类;
    
    public class Demo03_AnimalTest {
        // 匿名内部类:  将匿名内部类作为抽象类的子类对象
        public static void main(String[] args) {
            //1. 创建Animal的对象
            // Animal animal = new Animal(); // 抽象类不能实例化对象
            Animal animal = new Animal(){
    
                @Override
                public void eat() {
                    System.out.println("吃东西");
                }
            };
    
            //animal.eat();
            execute(animal);
        }
    
        public static void execute(Animal animal){
            animal.eat();
        }
    }
    
    
    package com.itheima.内部类;
    
    public interface Jumpping {
        public  void jump();
    }
    
    
    package com.itheima.内部类;
    
    public class Demo04_JumppingTest {
        // 匿名内部类:  将匿名内部类作为接口的子类对象
        public static void main(String[] args) {
            // Jumpping jumpping = new Jumpping(); 接口不能创建实例对象
    
            Jumpping jumpping = new Jumpping() {
                @Override
                public void jump() {
                    System.out.println("钻火圈...");
                }
            };
    
            jumpping.jump();
        }
    }
    
    package com.itheima.内部类;
    
    import com.itheima.抽象类.Animal;
    
    public class Cat {
    
    
        public void eat() {
            System.out.println("猫吃鱼......");
        }
    }
    
    
    package com.itheima.内部类;
    
    public class Demo05_CatTest {
        // 匿名内部类, 作为类的子类对象
        public static void main(String[] args) {
            Cat cat = new Cat(){
                @Override
                public void eat() {
                    System.out.println("猫吃猫粮......");
                }
            };
    
            cat.eat();
        }
    }
    
    

    建议: 当接口或者抽象类中的抽象方法在3个(含)以下时,并且只需要使用一次的时候, 就可以考虑使用匿名内部类的形式来创建对象了

五、作业

 作业一: 场景题目: 
	有以下几个类, 分别为 人类  学生类 老师类 , 学生类和老师类需要继承人类
		在人类有以下成员:
			成员属性:  姓名 年龄 性别 地址 生日
			成员方法:  吃饭 跑步
		
		在学生类: 
			需要重写吃饭的方法, 学生爱吃麻辣烫
			属性: 职业: 学生 (固定值)
		
		在教师类:
			需要重写吃饭的方法, 老师爱吃米饭
			属性: 职业: 教师(固定值)
	
	创建一个测试类, 
		创建三个学生类
			分别为: 
				张三   18   男   ...
  				李四   17   女   ...
				王五   19   男   ...
			并将三个学生对象, 放置到数组中
		
		创建三个教师类: 
			分别为: 自己写 随意
		
			并将三个老师对象, 放置到数组中
		
		对学生数组对象, 进行反转操作, 反转后, 通过Arrays将其打印出来
		
		
		对教师数组对象, 采用增强for循环, 遍历打印

提示: 在类中,可以重写一个 toString的方法 此方法可以将对象的数据打印, 而不是打印对象的地址值

http://www.kler.cn/a/566919.html

相关文章:

  • 网络安全技术与应用
  • C++题解(31) 2025顺德一中少科院信息学创新班(四期)考核:U537296 青蛙的距离 题解
  • Tomcat的server.xml配置详解
  • Tomcat10下载安装教程
  • ssh配置 远程控制 远程协作 github本地配置
  • 量子计算 + 药物开发:打开分子模拟的新纪元
  • java面试笔记(二)
  • 版图自动化连接算法开发 00002 ------ 添加一个中间点实现 Manhattan 方式连接两个给定的坐标点
  • Brave 132 编译指南 Android 篇 - 编译准备:系统要求与推荐工具 (三)
  • 苹果iPhone 17 Pro系列将配备12GB内存,AI功能成升级关键
  • 512台无人机!GCBF+如何实现大规模多智能体动态避障的?
  • 单链表删除算法(p=L; j=0;与p=p->next;j=1的辨析)
  • HBuilder X中,uni-app、js的延时操作及定时器
  • 【网络】网络层IP协议
  • Ubuntu22.04安装docker教程
  • 大白话解释负载均衡Nginx是什么 有什么用 怎么用#
  • 力扣hot100刷题——41~50
  • Linux:理解O(1)调度算法的设计精髓
  • 请谈谈 React 中的状态管理,如何使用 Context API 和 Redux 进行状态管理?
  • BMS应用软件开发 — 13 Modbus协议详解