day02_Java基础
- 创业
- 2025-09-20 04:57:01

文章目录 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关键字修饰. 抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类 抽象类不能实例化. – 那抽象类如何实例化呢? – 可以通过多态的方式, 创建其子类对象, 来完成抽象类的实例化. 这也叫: 抽象类多态. 抽象类的子类: – 如果是普通类, 则必须重写父抽象类中所有的抽象方法. – 如果是抽象类, 则可以不用重写父抽象类中的抽象方法.需求:
定义抽象类Animal , 类中有一个抽象方法eat(), 还有一个非抽象方法sleep().尝试在测试类中, 创建Animal类的对象, 并观察结果.创建普通类Cat, 继承Animal类, 观察是否需要重写Animal#eat()方法.创建抽象类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(); } }类与接口之间的关系
类与类之间: 继承关系, 只能单继承, 不能多继承, 但是可以多层继承.类与接口之间: 实现关系, 可以单实现, 也可以多实现. 还可以在继承一个类的同时实现多个接口.接口与接口之间: 继承关系, 可以单继承、多层继承, 也可以多继承.综合案例:
已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.乒乓球教练教如何发球, 篮球教练教如何运球和投篮.乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.为了出国交流, 跟乒乓球相关的人员都需要学习英语. 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的方法 此方法可以将对象的数据打印, 而不是打印对象的地址值day02_Java基础由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“day02_Java基础”
上一篇
软件工程---软件测试