JAVA 数组 + 面向对象
一、数组
1. 数组的基本使用
-
数组的概念: 数组就是用来同时存储多个同类型元素的容器
- JAVA : [1,2,3,4,5] JAVA 是强类型语言, 不能存储其他类型的数据, 要整型都是整型 ;要字符串 都是字符串。
- python [1,2,“curry”,“james”] python 的list列表可以同时存储多个类型的数据。
- 后面会整理一些 数据结构和算法 的文章 后期会发布 大家可以看看。
-
格式:
- 动态初始化: 我们指定长度,由系统给出默认值。
- 格式一: 数据类型[] 数组名 = new 数据类型[长度]; **要求掌握**
- int [] arr = new int [3];
- 堆区:[0,0,0]
- 格式二:数据类型 数组名 [] = new 数据类型[长度];
- int arr [] = new int [3];
- 堆区: [0,0,0]
- 静态初始化: 我们给出初始化值,由系统决定长度。
- 格式一: 数据类型 [] 数组名 = new 数据类型[] {值1,值2,值3.......};
- int [] arr = new int [] {11,22,33,44 ......};
- 堆区: [11,22,33,44,55]
- 格式二: 数据类型 [] 数组名 = {值1,值2,值3.......}; **要求掌握 语法糖**
- int [] arr = {11,22,33,44 .....};
- 堆区:[11,22,33,44,55]
-
格式解释
- 例如: int[] arr = new int[3];
int 数据类型, 表示数组中能存储什么类型的元素. [] 表示它是一个数组. arr 表示数组名, 其实就是一个变量名. new 表示去堆内存申请开辟空间. 3 表示数组的长度, 说明数组中最多只能存储3个整数. -
特点:
- 数组中每个元素都是有下标的,默认从0开始
- 数组中每个元素都是有默认值的。
- 例如:int -> 0,double ->0.0,boolean -> false,String -> null
-
案例: 数组入门
-
- 创建int类型的数组, 用来存储3个元素。
-
- 创建int类型的数组,存储数据11,22,33。
-
-
代码
package demo01_array;
/*
数组入门
1. 创建 int类型的数组 用来存储3个元素
2. 创建 int类型的数组 用来存储 11,22,33
*/
public class Demo01 {
public static void main(String[] args) {
// 创建动态类型数组
// 语法1:数据类型[] 变量名称 = new 数据类型[数组长度]; [掌握]
int [] arr = new int[3];
// 语法2:数据类型 变量名称[] = new 数据类型[数组长度];
int arr1 [] = new int[3];
// 创建静态类型数组
// 语法1:数据类型[] 变量名称 = new 数据类型[]{数据值,.....}
int [] arr2 = new int[]{11,22,33};
// 语法2:数据类型[] 变量名称 = {数据值,.....} 掌握 语法糖
int [] arr3 = {11,22,33};
}
}
2.数组的基本操作.
- 数组的基本格式如下:
数组的基本格式如下:
- 数组名[索引] 根据索引, 获取该值.
- 数组名[索引] = 值; 根据索引, 修改该位置的值.
- 数组名.length 获取数组的长度 [11, 22, 33] 长度3
- 数组名.length - 1 获取数组的最大索 [11, 22, 33] 最大索引:2
- 代码演示
package demo01_array;
/*
数组的基本操作
*/
public class Demo02 {
public static void main(String[] args) {
// 定义数组 默认值[0,0,0]
int [] arr = new int[3];
// 打印数组的元素值
System.out.println(arr[2]); // 0
System.out.println("----------------[华丽分割线]----------------");
// 修改数组元素值
arr[2] = 10;
System.out.println(arr[2]); // 10
System.out.println("----------------[华丽分割线]----------------");
//打印数组长度
System.out.println(arr.length); // 3
System.out.println("----------------[华丽分割线]----------------");
// 打印数组最大索引值
System.out.println(arr.length - 1); // 2
}
}
3. 理解 数组的内存图

public class Demo03 {
//main方法也叫主方法(主函数), 所有的代码都是从这里开始执行的.
public static void main(String[] args) {
int[] arr = new int[3]; //0,0,0
System.out.println(arr[0]); //0
System.out.println(arr); //地址值
}
}
4. 数组时可能会遇到的两个小问题
- 问题一:
- 空指针异常: NullPointerException
- 产生原因: 数组为null, 你还去访问数组中的元素.
- 解决方案: 给数组赋值.
- 问题二:
- 索引越界异常: ArrayIndexOutOfBoundsException
- 产生原因: 你访问了数组中不存在的元素.
- 解决方案: 访问数组中存在的即可.
- 代码演示
package demo01_array;
/**
* 演示 数组空指针 和下标越界异常
*/
public class Demo04 {
public static void main(String[] args) {
//演示 空指针异常: NullPointerException
// 定义数组 [0,0,0,0,0]
int[] arr = new int[5];
// 把数组置空
arr = null;
//访问数组中的元素
System.out.println(arr[1]);
// 演示索引越界异常:
// 产生:ArrayIndexOutOfBoundsException
System.out.println(arr[6]);
}
}
5. 遍历数组
- 步骤
- 定义静态数组
- for循环遍历数组
- 快捷键 itar
- 代码
package demo01_array;
/*
案例: 演示如何遍历数组.
需求:
1. 定义int类型的数组arr, 存储元素11, 22, 33, 44, 55.
2. 通过for循环, 遍历数组.
快捷键:iterator arry ==> itar
*/
public class Demo05 {
public static void main(String[] args) {
//定义静态数组
int [] arr = {11,22,33,44,55};
// for 循环遍历数组元素 快捷键 itar
for (int i = 0; i < arr.length; i++) {
int i1 = arr[i];
System.out.println(i1);
}
}
}
6.如何获取数组元素的最值
- 思路
需求:求数组int[] arr = {5, 15, 2000, 10000, 100, 4000};的最大值.
1.定义数组,记录元素
2.定义一个变量max,记录数组元素的最大值
3.遍历数组,获取每一个元素
4.依次比较两个元素(数组的元素和max) 如果当前元素比max大,就将其赋值给max
5.等待循环结束,max记录的就是最大值
- 细节
1.把谁作为初始化最大值?
假设数组的第一个元素为最值.
2.循环开始的时候, 从哪里开始最合适?
从索引为1的元素开始(第一个值自身和自身不需要比较).
- 代码
package demo01_array;
/*
需求:求数组int[] arr = {5, 15, 2000, 10000, 100, 4000};的最大值.
思路:
// 1.定义数组,记录元素
// 2.定义一个变量max,记录数组元素的最大值
// 3.遍历数组,获取每一个元素
// 4.依次比较两个元素(数组的元素和max) 如果当前元素比max大,就将其赋值给max
// 5.等待循环结束,max记录的就是最大值
*/
public class Demo06 {
public static void main(String[] args) {
// 定义数组
int [] arr = {5, 15, 2000, 10000, 100, 4000};
// 2.定义一个变量max,记录数组元素的最大值
int max = arr[0];
// 3.遍历数组,获取每一个元素 快捷键 itar
for (int i = 0; i < arr.length; i++) {
int i1 = arr[i];
//依次比较两个元素(数组的元素和max)
if (i1 > max ) {
//如果当前元素比max大,就将其赋值给max
max = i1;
}
}
// 等待循环结束,max记录的就是最大值
System.out.println("最大值为: " + max);
}
}
二、方法


下载插件

1.方法入门基本使用
- 方法的概念: 把具有独立功能的代码整合到一起,使其成为 具有特殊功能的代码集
- 方法格式:
// java
修饰符 返回值的数据类型 方法名(数据类型 参数名1,数据类型 参数名2){
方法体;
return 具体的返回值;
}
// python
def funcName(参数1,参数2):
方法体
return 返回值
- 格式解释:
1.修饰符: - 目前理解为固定格式 public static 2.返回值的数据类型 - 指的是方法执行完毕后,返回什么类型的结果 - 如果明确知道方法没有具体的返回值,则返回值类型必须写成 **void** 3.方法名 - 就是方法的名字 要符合 **小驼峰命名法** 方便调用 4.参数列表 - 简称**形参** 指的是调用方法需要传入什么类型的值。 5.方法体 - 就是前面的逻辑代码 (if for ....) 用来完成某些功能的 6.return - ' 主要作用是用来结束方法的,捎带着可以返回方法的执行结果。 ' - 注意事项:
- 方法与方法之间是平级关系,不能嵌套定义。
- 方法只有被调用才能执行。
- 定义方法的时候,写的参数列表叫做 形参
-调用方法需要传入什么类型的值。 - 调用方法是传入的参数 叫做实参
- 指的是实际参与运算的数值
- 方法的功能越单一越好。
单一职责原则
- 方法的好处:
提高代码的复用性
-代码
package dome02_method;
/*
案例: 演示方法入门基本使用
需求1: 定义方法, 计算两个整数的和.
java定义方法语言格式:
修饰符 返回值的数据类型 方法名(数据类型 参数名1, 数据类型 参数名2) {
方法体;
return 具体的返回值;
}
方法的好处: 提高代码的复用性
*/
public class Demo01 {
// 主函数 程序的入口
public static void main(String[] args) {
// 不能在这里定义 不能嵌套定义
// 调用方法: 1.方法名称() 2.传参 3.接受返回值
int sum = getSum(1300, 14);
System.out.println("sum = " + sum);
System.out.println("----------------[华丽分割线]----------------");
// 再次调用,代码复用
int sum1 = getSum(500, 20);
System.out.println("sum1 = " + sum1);
}
/**
* 定义方法 计算两个整数的和.
* @param a 计算的第一个整数
* @param b 计算的第二个整数
* @return 求和结果
* 只实现一件事情:单一职责原则
*/
public static int getSum(int a ,int b){
int sum = a + b;
return sum;
}
}
2. 定义方法实现遍历数组
- 代码
package dome02_method;
/*
案例: 定义方法, 遍历数组.
*/
public class Demo02 {
public static void main(String[] args) {
// 1.定义静态数组
//快速抽取方法的快捷键:ctrl + alt + m
// mac快捷键:option + command + m
int [] arr = {11,22,33,44,55};
printArray(arr);
}
/**
* 定义方法,完成数组遍历
* @param arr 要遍历的数组
* 如果明确知道方法没有具体的返回值, 则返回值类型必须写成: **void**
*/
public static void printArray(int[] arr){
//使用for循环遍历数组 快捷键 itar
for (int i = 0; i < arr.length; i++) {
System.out.println("数组元素的下标 " + i);
System.out.println(arr[i]);
}
}
/* 这是没有返回值的错误写法
public static int printArray(int[] arr){
//使用for循环遍历数组 快捷键 itar
for (int i = 0; i < arr.length; i++) {
System.out.println("数组元素的下标 " + i);
System.out.println(arr[i]);
}
}*/
}
3.定义方法, 获取数组元素的最大值.
- 将代码抽取成方法的快捷键:ctrl+ alt + m
- 代码
package dome02_method;
/*
案例: 定义方法, 获取数组元素的最大值.
*/
public class Demo03 {
public static void main(String[] args) {
// 1.定义数组,记录元素值
int [] arr = {5, 15, 2000, 10000, 100, 4000};
//调用函数 给形参传入实参arr
int max = getMax(arr);
System.out.println("数组最大值 " + max);
}
/**
* 获取数组最大值
* @param arr 传入的数组
* @return 数组中的最大值
*/
public static int getMax(int [] arr){
// 2.定义变量记录最大值
// 已经将数组的第一个元素赋值给了max,后面就不需要和自身比较,所以下面的for循环,下标从1开始
int max = arr[0];
//循环遍历 直接从1开始即可
for (int i = 1; i < arr.length; i++) {
//依次比较两个元素的大小(max比较),如果当前元素比max大,就将该元素赋值给max
if (arr[i] > max) {
//如果当前元素比max大,就将该元素赋值给max
max = arr[i];
}
}
return max;
}
}
5.方法重载
- 方法重载的概念:
-在同一个类中,出现了方法名相同,但是参数列表不同(个数不同 or 对应位置的数据类型不同。) 的两个或者以上的方法时,称为方法重载实例: - getSum(int a ,int b) - getSum(int a ,int b ,int c) - getSum(double a ,double b) - 应用场景
- 用来解决功能相似或者相同 但是方法名不能从重名的问题。
- 实例:
- 定义方法compare(),用来比较连个整型是否相等。
- 要求兼容所有的 整数类型,即(byte, short, int, long)
- 代码
package dome02_method;
/*
需求:
1. 定义方法compare(), 用来比较两个整型数据是否相等.
2. 要求兼容所有的整数类型, 即(byte, short, int, long)
方法重载概念:
同一个类中, 出现**方法名相同**, **但是参数列表不同**(**个数不同** or **对应的数据类型不同**.)的 两个或者以上的方法时, 称为**方法重载**.
*/
/**
* 演示方法重载
*/
public class Demo04 {
public static void main(String[] args) {
//调用方法
//比较int类型
boolean flag1 = compare(10, 20);
System.out.println(flag1);
//比较 short类型
short s1 = 11, s2 = 11;
boolean flag2 = compare(s1 ,s2);
System.out.println(flag2);
//比较byte类型
byte b1 = 38, b2 = 58;
boolean flag3 = compare(b1 ,b2);
System.out.println(flag3);
//比较long类型
long l1 = 8765L ,l2 = 543L;
boolean flag4 = compare(l1 ,l2);
System.out.println(flag4);
}
// 使用方法重载
// int类型
public static boolean compare(int a, int b){
System.out.println("----------------[比较int类型]----------------");
return a == b;
}
// short类型
public static boolean compare(short a, short b){
System.out.println("----------------[比较short类型]----------------");
return a == b;
}
// byte类型
public static boolean compare(byte a ,byte b){
System.out.println("----------------[比较byte类型]----------------");
return a == b;
}
// long类型
public static boolean compare(long a ,long b){
System.out.println("----------------[比较long类型]----------------");
return a == b;
}
}
6. java中方法的参数传递问题
- 需要记忆
' - 形参如果是基本类型,则形参的改变对实参没有任何影响, 因为传递的是: 数值, 也叫值传递. '
' - 形参如果是引用类型, 则形参的改变对实参有直接影响, 因为传递的是: 地址值, 也叫引用传递. '
' - String虽然是引用类型, 但是它作为形参的时候, 用法和基本类型一致, 传的是数值而不是地址值. '
- 代码 java中的基本数据类型 方法参数传递问题–值传递
package dome02_method;
/*
案例1: 演示java中的基本数据类型 方法参数传递问题--值传递
*/
public class Demo05 {
public static void main(String[] args) {
//基本数据类型 值传递
int num = 100;
System.out.println("改变之前: " + num); //改变之前: 100
//调用方法 -- 传入基本数据类型
change(num);
System.out.println("改变之后: " + num); //改变之后: 100
}
public static void change(int num){
//传入的参数进行重新赋值
//新的局部变量 num = 200
num = 200;
}
}
- 代码 java中的参数传递问题 --地址传递
package dome02_method;
/*
演示java中的参数传递问题 --地址传递
*/
public class Demo06 {
public static void main(String[] args) {
// 引用类型作为方法的参数传递
int[] arr = {11, 22, 33};
// 调用change方法修改之前获取数组下标为1的元素
System.out.println("调用change方法之前: " + arr[1]); //调用change方法之前: 22
//调用change方法,传入引用类型数组
change(arr);
// 调用change方法修改之后获取数组下标为1的元素
System.out.println("调用change方法之前:" + arr[1]); //调用change方法之前:100
}
public static void change(int[] arr) {
// 传入的数组参数重新赋值
arr[1] = 100;
}
}
- 对于值传递 和地址传递的解释

三、面向对象
1.面向对象入门
- 面向对象的相关概念
他是一种编程思想,强调的是以对象为基础完成各种操作;吧具有独立功能的代码整合到一起,使其成为具有特殊功能的代码集- 思想特点
- 把复杂的问题简单化
- 更符合人的思考习惯
- 把程序员从执行者变成指挥者
- 总结
- 万物皆对象
- 关键字解释
'类':属性和行为(方法)的集合,是一个抽象的概念。
'对象':类的具体的实现 例如 设计图纸 ---》 汽车
'属性': 也叫成员变量 字段 就是事物的外在特征(名词) 对象属性
'行为':也叫成员方法 就是描述事物能够做什么(动词) 对象方法
- 格式
如何定义类:
public class 类名 {
//属性,名词,全部私有
// 构造方法 空参 全参
// 类比 python中的 __init__ 魔法方法 初始化
//getXXX() setXXX()
//行为方法 动词
}
如何使用类中的成员
1.创建该类的对象。
类名 对象名 = new 类名();
Phone p = new Phone();
2.通过对象名 的方式调用类中的成员。
p.call();
2. 面向对象手机类
- 定义手机类的代码
package demo03_oop;
/*
需求:定义手机类 Phone
属性:品牌(brand),价格(price),颜色(color)
行为:打电话(call),发短信(sendMessage)
*/
/**
* 自定义手机类,也叫:实体类 POJO类
*/
public class Phone {
//属性: 品牌(brand) 价格(price) 颜色(color)
String brand;
double price;
String color;
// 行为 - 成员方法 先不写static
public void call(String name) {
System.out.println("给" + name + "打电话");
}
public void sendMessage(String name) {
System.out.println("给" + name + "发短信");
}
}
- 创建手机对象代码
package demo03_oop;
/*
创建Demo1测试类,在main方法中 创建Phone类的对象,并使用其成员变量
*/
public class Deno01 {
public static void main(String[] args) {
//创建手机类对象
Phone p = new Phone();
// 打印其成员属性和成员方法 注意:成员变量都有默认值
System.out.println("手机品牌:" + p.brand); //手机品牌:null
System.out.println("手机价格:" + p.price); //手机价格:0.0
System.out.println("手机颜色:" + p.color); //手机颜色:null
System.out.println("----------------[华丽分割线]----------------");
//给成员属性赋值
p.brand = "菠萝手机";
p.price = 998;
p.color = "绿色";
//赋值后再次打印手机信息
System.out.println("手机品牌:" + p.brand); //手机品牌:菠萝手机
System.out.println("手机价格:" + p.price); //手机价格:998.0
System.out.println("手机颜色:" + p.color); //手机颜色:绿色
System.out.println("----------------[华丽分割线]----------------");
// 调用Phone 类的成员方法
p.call("郑三炮"); //给郑三炮打电话
p.sendMessage("王二蛋"); //给王二蛋发短信
}
}
3.封装
思考:
到目前为止,我们虽然已经实现了上述的代码
但是我们发现我们目前定义的类,还是有很大的问题,
因为在外界(测试类中) 可以 直接访问类中的属性 这样做是比较危险的
因为用户可能传入一些非法值(举例: p.price = -999.9;)
针对于这种情况, 我们可以用 封装解决.
-
封装概述:
- 封装就是隐藏对象的属性和实现细节,仅对外提供一个公共的访问方式
-
如何隐藏?
- 可以通过
private 关键字实现 被它修饰的内容只能在本类中直接访问。
- 可以通过
-
公共访问的方式是什么?
- 指的是getxxx() 和setxxx() 方法。
-
封装的好处是什么?
- 提高代码的安全性(private保证 ),提高代码的复用性(方法)
-
封装的弊端是什么? 正对于private
- 代码的冗余增加了
-
目前我们在setPrice()方法中是没有做到见名知意的, 只是传入了一个p, 那如何解决这个问题呢?
- 类似于python的self
- 通过 this 关键字解决, 它是用来解决局部变量和成员变量重名问题的.
- this关键字解释: 它表示当前对象的引用, 谁调用, 它就代表谁.


-
封装:定义手机类代码
package demo03_oop;
/**
* 自定义手机类私有化类
*/
public class PhonePrivate {
//品牌
String brand;
//价格
// private 私有变量 外面其他的类无法直接访问
private double price;
// 颜色
String color;
// 定义公共访问私有属性的方法
//给price私有属性 设置值 setXXX
//瑕疵 : 此时的p属性并不能起到 见名知意的效果 修改成price
/*public void setPrice(double p) {
//非法值的判断
if (p > 0) {
price = p;
}
}*/
public void setPrice(double price) {
//用局部变量给成员变量赋值
this.price = price;
}
// 读取price私有属性的值 getXxx
public double getPrice() {
return price;
}
// 行为-成员方法 先不写static
public void call(String name){
System.out.println("给" + name + "打电话");
}
public void sendMessage(String name) {
System.out.println("给" + name + "发短信");
}
}
- 封装:创建使用手机对象代码
package demo03_oop;
/*
创建Demo2测试类,在main方法中 创建PhonePrivate类的对象,并使用其成员变量
*/
public class Demo02 {
public static void main(String[] args) {
//创建PhonePrivate对象
PhonePrivate pp = new PhonePrivate();
//访问对象属性
System.out.println("手机品牌:" + pp.brand);
// 报错:原因price已经私有化了,其他类不能直接访问
//System.out.println("手机价格:" + pp.price);
// 使用公共方法访问属性
System.out.println(pp.getPrice());
System.out.println("手机颜色:" + pp.color);
//给属性赋值
pp.brand = "菠萝手机";
pp.setPrice(-999.99);
pp.color = "绿色";
System.out.println("----------------[华丽分割线]----------------");
System.out.println("手机品牌:" + pp.brand);
// 报错:原因price已经私有化了,其他类不能直接访问
//System.out.println("手机价格:" + pp.price);
// 使用公共方法访问属性
System.out.println(pp.getPrice());
System.out.println("手机颜色:" + pp.color);
}
}
4. this应用和Java中使用变量的规则
- 结论(记忆)
java中使用变量遵循就近原则,局部有就使用,没有就使用本类的成员变量。有就使用, 没有就去父类成员位置找,父类没有就直接报错。- 代码演示
package demo03_oop;
/**
* 定义一个学生类
*/
public class Student {
//成员变量
int age = 23;
//成员方法
public void show(){
//局部变量
int age = 20;
System.out.println(age);
System.out.println(this.age);
}
}
- 代码
package demo03_oop;
/**
* 创建对象调用方法
*/
public class StudentDemo {
public static void main(String[] args) {
Student student = new Student();
//调用方法
student.show();
}
}
5.private和类的构造方法 这是重点
- 需求:
- 目前我们发现,如果给一个对象的私有属性赋值,需要调用setxxx() 逐个设置 ,那能不能在创建对象的时候一次性给所有属性赋值呢?
- 方案:
- 就是java的构造方法 类似于Python中的魔法方法
__init__()初始化方法.
- 就是java的构造方法 类似于Python中的魔法方法
- 构造方法概念:
主要是用来创建对象的,捎带着可以给对象的属性赋值
- 格式
//java构造方法格式:
public 类名(全参) {
}
public 类名(空参) {
}
// 构造方法的重载
// python构造方法
__init__()
特点:
1.构造方法名必须和类名完全一致 包括大小写也一致。
2.构造方法没有返回值,连void都不用写
3.构造方法中可以有return
4.构造方法可以重载
5.如果我们不写构造方法,系统会默认给一个空参构造,如果我们写了 系统就不给了
6.创建对象的格式可以优化为: 类名 对象名 = new 类名(值1, 值2 ,......);
- 定义构造函数学生类代码
- 构造函数的快捷键 alt +insert


- 构造函数的快捷键 alt +insert
- 全参构造 重复上面的第一步 在第二步的时候 看下图

- windows get&set快捷键:alt +insert
- windows get&set快捷键 alt + 回车 光标需要放到类上
- 苹果电脑 get&set快捷键: command + n


- 定义构造函数学生类代码
package demo04_private;
public class Student {
//成员属性全部私有化
private String name;
private int age;
//空参构造
public Student() {
}
//全参构造
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/*
python的构造方法
def __init__(name, age):
self.name = name
self.age = age
*/
// windows get&set快捷键:alt +insert
// windows get&set快捷键 alt + 回车 光标需要放到类上
// 苹果电脑 get&set快捷键: command + n
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 love(){
System.out.println("我爱她");
}
}
- 使用构造函数初始化成员变量
package demo04_private;
/*
案列:java构造函数测试类
*/
public class Demo01 {
public static void main(String[] args) {
// 创建学生对象---使用空参构造函数
Student stu1 = new Student();
//给私有属性赋值
stu1.setName("马佳玉");
stu1.setAge(23);
//获取私有属性值
System.out.println(stu1.getName() + " " + stu1.getAge());
// 调用成员方法
stu1.love();
System.out.println("----------------[华丽分割线]----------------");
//创建学生对象 ---使用全参构造函数
Student stu2 = new Student("马佳玉" ,23);
//给私有属性赋值
//获取私有属性值
System.out.println(stu2.getName() + " " + stu2.getAge());
//调用成员方法
stu2.love();
}
}
6. java中的继承
- 继承概述
- 实际开发中 我们发现好多类中的部分内容是相似或者相同的,每次写很麻烦,针对于这种情况,我们可以把这些相同(相似)的内容抽取出来到一个类中(父类)。
- 然后单独的定义到一个类中,然后让那多个类和这个父类产生关系,这个关系叫做继承,在JAVA中,继承用extends关键字表示
- 格式
'A类继承B类 子承父业'
class A extends B{
' A类 叫做子类 B类 叫做父类 基类 '
}
-
好处:
提高代码的复用性提高代码的可维护性让类与类之间产生关系,是多态的前提
-
弊端:
- 类与类之间的耦合性太强了
- 开发原则:高聚合 低耦合
-
父类代码
package demo05_extends;
/**
* 创建动物基类(父类)
*/
public class Animal {
//属性 全部私有化
private String name;
private int age;
//空参构造函数
public Animal() {
}
// 全参构造函数
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
//属性 get & set方法
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("动物会吃");
}
}
- 子类代码(Cat)
package demo05_extends;
/**
* 创建子类 (猫类) 继承动物类 extends Animal
*/
public class Cat extends Animal{
}
- 使用子类对象
package demo05_extends;
/**
* 使用子类对象
*/
public class Demo01 {
public static void main(String[] args) {
// 创建对象
Cat cat = new Cat();
//给属性赋值 并打印
cat.setName("机器猫");
cat.setAge(3);
System.out.println(cat.getName() + "," + cat.getAge());
//调用对象方法
cat.eat();
}
}
7.继承中的成员特点
- 成员变量
- 就近原则
- 构造方法
- 子空参访问父空参 子全参访问父全参。
- 成员方法:
- 就近原则
- 细节
- 子类只能继承父类的非私有成员(构造方法也不能继承)。
- 为什么会有方法重写呢?
答: 当子类需要沿袭父类的功能,但是功能主体又有自己额外需求的时候,就可以考虑使用方法重写。
- 演示成员变量 —就近原则

- 代码演示
super 访问父类 this 访问自己类成员
package demo05_extends;
public class Cat extends Animal{
// 成员变量
int num = 20;
public void show(){
// 局部变量
int num = 10;
System.out.println(num); // 访问:局部变量
System.out.println(this.num); // 访问:自己类成员变量
System.out.println(super.num); // 访问:父类的成员变量
}
}
- 成员变量就近原则:如果子类全部变量全部注释掉,就近只能访问父类的成员变量

- 演示构造方法 ---- 子空参访问父空参 子全参访问父全参

- 成员方法就近原则

- 代码演示
package demo05_extends;
/*
成员变量:
就近原则
构造方法:
子空参访问父空参 子全参访问父全参
成员方法:
就近原则
细节:
1. 子类只能继承父类的非私有成员(构造方法也不能继承)
2. 为什么会有方法重写?
当子类需要沿袭父类的功能,但是功能主体 又有自己额外需求的时候,就可以考虑使用方法重写
*/
public class Demo02 {
public static void main(String[] args) {
// 成员变量就近原则 没有就往上一级父类中找
// 创建 Cat类对象
Cat cat = new Cat();
//调用show方法
cat.show();
System.out.println("----------------[华丽分割线]----------------");
// 构造方法子空参访问父空参 子全参访问父全参
Cat cat1 = new Cat();
System.out.println(cat1.getName() + "," + cat1.getAge());
System.out.println("----------------[华丽分割线]----------------");
Cat cat2 = new Cat("橘猫", 3);
System.out.println(cat2.getName() + "," + cat2.getAge());
// 成员方法 就近原则
// 猫吃鱼
//如果吧Cat类中的eat方法注释掉 调用父类中的eat 会打印 动物会吃
cat2.eat();
}
}
- Animal类
package demo05_extends;
/**
* 创建动物基类(父类)
*/
public class Animal {
//属性 全部私有化
private String name;
private int age;
int num = 30;
public void show(){
int num = 10;
System.out.println(num);
System.out.println(this.num);
}
//空参构造函数
public Animal() {
System.out.println("Animal空参");
}
// 快捷键:alt + 回车 光标定位到类
// 快捷键:alt + insert
// 全参构造方法
public Animal(String name, int age) {
System.out.println("Animal全参");
this.name = name;
this.age = age;
}
// ------------[属性的get&set方法]------------
//属性 get & set方法
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("动物会吃");
}
}
- Cat类
package demo05_extends;
/**
* 创建子类 (猫类) 继承动物类 extends Animal
*/
public class Cat extends Animal{
// 子类的成员变量
int num = 20;
// Cat全参构造函数
public Cat(String name, int age) {
// 子全参 访问==> 父全参
super(name, age);
}
// Cat空参构造函数
public Cat() {
// 子全参 访问==> 父全参
super();
}
public void show(){
// 局部变量
int num = 10;
// 1.输出局部变量
System.out.println(num);
// 2.子类的成员变量
System.out.println(this.num);
// 3.父类的成员变量
System.out.println(super.num);
}
// 成员方法
public void eat(){
System.out.println("猫吃鱼");
}
}
8.继承重写父类方法 @Override 重写父类的方法的关键字
- 代码
package demo05_extends;
// 手机类 --- 父类
public class Phone {
//打电话
public void call(){
System.out.println("--- 输入手机号码 ---");
System.out.println("--- 嘟嘟嘟嘟---");
}
}
========================【子类NewPhone:演示重写父类方法】=====================
package demo05_extends;
/*
继承父类 并重写父类方法
*/
public class NewPhone extends Phone{
// @Override 重写父类的方法的关键字
@Override
public void call() {
//调用父类的方法
super.call();
System.out.println("手机彩礼:男人就像一朵花,需要人来灌溉他~~~~");
}
}
-========================【演示重写父类方法】=====================
package demo05_extends;
public class Demo03 {
public static void main(String[] args) {
NewPhone newPhone = new NewPhone();
newPhone.call();
/*
* 打印结果:
--- 输入手机号码 ---
--- 嘟嘟嘟嘟---
手机彩礼:男人就像一朵花,需要人来灌溉他~~~~
* */
}
}
9.多态
- polymorphic 英 [,pɒlɪ’mɔːfɪk]
多态概述 :
多态指的是:同一个事物,在不同的时刻表现出来的不同形态。
状态,例如:水(气态 液态 固态)
实例:
Cat cat = new Cat(); //猫类是猫 这个不是多态
Animal an = new Cat(); //猫是动物, 这个是多态
父类引用 =====》 猫的对象
前提:
1.必须有继承或者实现关系。
2.必须父类(父接口)引用指向子类对象。
3.必须有方法重写,不然多态无意义。
多态中的成员方法特点(懵):
成员变量:编译看左,运行看左。
成员方法:编译看左,运行看右。
多态的好处:
父类型可以作为方法的形参类型,这样可以接收其任意的子类对象。
根据多态的成员方法调用规则“编译看左,运行看右” 传入什么对象,就调用谁的方法。
多态的弊端:
父类引用不能直接使用子类的特有成员
如何解决?
向下转型。
Animal an = new Cat(); 向上转型。 double d = 10; 隐转
Cat cat = (Cat)an; 向下转型。 int a = (int)d; 强转
- 代码演示:
========================【Animal父类】========================
package demo06_poly;
/*
Animal 父类
*/
public class Animal {
// 成员变量
int age = 30;
//成员方法
public void eat(){
System.out.println("动物会吃~~~");
}
}
========================【Cat子类】========================
package demo06_poly;
/*
Cat子类
*/
public class Cat extends Animal{
// 成员变量
int age = 20;
//重写父类的eat方法
@Override
public void eat() {
System.out.println("猫吃鱼");
}
// 成员方法
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
========================【多态实现】========================
package demo06_poly;
/*
多态概述: 多态指的是 同一个事物 在不同时刻表现出来的不同形态, 状态. 例如: 水(气体, 液体, 固体)
示例:
Cat c = new Cat(); //猫类是猫, 这个不是多态.
Animal an = new Cat(); //猫是动物, 这个是多态.
父类引用 ==> 猫的对象
前提:
1. 必须有继承或者实现关系.
2. 必须父类(父接口)引用指向子类对象.
3. 必须有方法重写, 不然多态无意义.
多态中的成员方法特点(懵):
成员变量: 编译看左, 运行看左.
成员方法: 编译看左, 运行看右.
*/
public class Demo01 {
public static void main(String[] args) {
//必须父类(父接口)引用指向子类对象
//多态的体现
//左 右
Animal an = new Cat();
//多态中的成员方法特点(懵):
//成员变量: 编译看左, 运行看左.
System.out.println(an.age); //30
//成员方法: 编译看左, 运行看右.
//猫吃鱼
an.eat();
}
}
10.多态的好处
- 父类型 可以作为 方法的形参类型 这样可以接受其任意的子类对象。

- 根据多态的成员方法调用规则“编译看左,运行看右” 传入什么对象,就调用谁的方法。
- 代码
========================【父类】========================
package demo06_poly;
/*
Animal 父类
*/
public class Animal {
// 成员变量
int age = 30;
//成员方法
public void eat(){
System.out.println("动物会吃~~~");
}
}
========================【Cat子类】========================
package demo06_poly;
/*
Cat子类
*/
public class Cat extends Animal{
// 成员变量
int age = 20;
//重写父类的eat方法
@Override
public void eat() {
System.out.println("猫吃鱼");
}
// 成员方法
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
========================【Dog子类】========================
package demo06_poly;
/*
Dog类 子类
*/
public class Dog extends Animal{
//重写父类方法
@Override
public void eat() {
System.out.println("狗吃骨头!!!");
}
}
========================【多态好处】========================
package demo06_poly;
/*
定义个printAnimal方法 传入什么对象 调用对应方法
多态好处:定义方法将形参类型设置成父类类型 接受任何子类对象的传入(多态)
*/
public class Demo02 {
public static void main(String[] args) {
//1.创建Cat类对象
Cat cat = new Cat();
printAnimal(cat);
//2.创建Dog类对象
Dog dog = new Dog();
printAnimal(dog);
}
// 方案1 : 普通写法
/*
public static void printAnimal(Cat cat){
cat.eat();
}
public static void printAnimal(Dog dog){
dog.eat();
}
*/
//方案2: 多态的写法
// 定义方法将形参类型设置成 父类类型 接受任何子类对象的传入 (多态)
//Animal an = new Cat(); 多态
//Animal an = new Dog(); 多态
public static void printAnimal(Animal an){
an.eat();
}
}
11.final关键字的用法.
'final关键字的解释'
关键字 表示最终的意思,可以修饰类 方式 变量。
修饰类的 不能有子类
修饰的方法 是最终方法 子类不能重写
修饰的变量 是一个常量 只能赋值一次
- 代码
public class Demo01 {
public static void main(String[] args) {
final int MAX_VALUE = 30;
//报错 final修饰的变量 是一个常量 只能赋值一次
//MAX_VALUE = 100;
System.out.println(MAX_VALUE);
}
}
======================[父类]==========================
//报错,final修饰类的 不能有子类
// public final class Fu{
public class Fu {
//修饰的方法 是最终方法 子类的不能重写。
//public final void show() {
public void show() {
System.out.println("这是绝密文件");
}
}
=======================[子类]=========================
public class Zi extends Fu{
//重写父类方法
@Override
public void show() {
System.out.println("随便删除");
}
}
12.static的用法
'需要记忆'
1.静态可以将 ' 类名. ' 的方式调用。
2.静态成员可以被该类所有的对象 '共享' ,这也是决定我们用不用静态的最大原因。
3.静态随着类的加载而加载,优先于对象存在。
4.静态只能访问静态。
5.实际开发中一般 public static final 经常一起用。
- 代码:
public class Dome02 {
public static void main(String[] args) {
// 类名,静态属性
System.out.println(Student.girl);
// 报错:name不是静态的 必须 对象名. 的方式调用
// System.out.println(Student.name);
Student stu1 = new Student();
Student stu2 = new Student();
// 静态成员可以被该类所有的对象 共享
System.out.println(stu1.girl);
System.out.println(stu2.girl);
}
}
========================【学生类】========================
public class Student {
String name;
// 实际开发中一般 public static final 经常一起用
public static final String girl = "马佳玉";
//静态方法,只能访问静态成员
//因为非静态成员只有创建对象才会有,而静态是优先于对象存在的。
// 即:先进内存的,不能访问后进内存的。
public static void show(){
//报错 因为非静态成员只有创建对象才会有,而静态是优先于对象存在的。
//System.out.println(name);
System.out.println(girl);
}
}
13.抽象类
抽象类概念:
有抽象方法的类一定是抽象类,抽象用 abstract 修饰。
抽象方法:没有方法体的方法叫抽象方法
特点:
1. 抽象用 abstract 修饰。
2. 抽象类不能直接实例化。
3. 抽象类的子类:
如果是普通类:必须重写父类中所有的抽象方法。
如果是抽象类:可以不用重写。
成员特点:
专业版:变量 常量 构造方法 静态方法 非静态方法,抽象方法
大白话版:比普通类多一种抽象方法,且还可以不写。
- 代码
/*
演示抽象类
*/
public class Demo01 {
public static void main(String[] args) {
//抽象类不能直接实例化
//Animal an = new Animal(); // 报错 动物是动物
// 抽象类多态
Animal an = new Cat();
an.eat();
}
}
==================【动物抽象类】==================
/**
* 创建动物类 抽象类
*/
public abstract class Animal {
// 因为不同的动物吃的内容 不一样 所以该方法不应该有方法体
// 而是由子类重写
public abstract void eat();
}
==================【狗抽象类】==================
// Dog 抽象类
public abstract class Dog extends Animal{
// 如果是抽象类: 可以不用重写父类的抽象方法。 写了不报错
/*
@Override
public void eat() {
System.out.println("狗吃肉!!!");
}
*/
}
==================【猫类】==================
public class Cat extends Animal{
// 如果是普通类: 必须重写父类中所有的抽象方法 否则报错
@Override
public void eat() {
System.out.println("猫吃鱼!!!");
}
}
14. 接口的基本使用
- 思考
扩展:假如部分的猫经过训练 学会了飞 请问 飞这个功能应该定义到哪里?
答案: ' 通过: 接口实现 '
记忆:
抽象类(亲爹):定义整个继承体系的 共性内容 比如:所有的动物都会吃
接口(干爹): 定义整个继承体系的 扩展内容 比如: 猫会飞
- 接口概念
接口:
概念:
比抽象类更加抽象,里面有且只能有抽象方法和常量
特点:
1. 接口用 ' interface ' 修饰。
2. 类和接口之间是实现关系,用 implements 修饰。
3. 接口不能实例化。
4. 接口的子类:
如果是普通类:必须重写父类中所有的抽象方法
如果是抽象类:可以不同重写。
- 代码
/*
演示接口。
*/
public class Demo01 {
public static void main(String[] args) {
//打印常量
System.out.println(Flying.age);
//接口不能实例化
//报错
// Flying flying = new Flying();
// 接口多态
Flying fy = new Cat();
fy.fly();
}
}
==================【Flying接口实现】==================
// 接口用interface 修饰
public interface Flying {
// 只能有常量
public static final int age = 20;
// 只能有抽象方法
public abstract void fly();
}
==================【猫类实现Flying接口】==================
public class Cat implements Flying{
@Override
public void fly() {
System.out.println("猫会飞");
}
}
==================【抽象狗类实现Flying接口】==================
public abstract class Dog implements Flying{
// 抽象类 不重写父类的抽象方法也不会报错
}
15.类和接口的关系
类和接口的关系:
类与类:
继承关系,只能单继承 不能多继承 但是可以多层继承
类与接口:
实现关系 可以单实现 也可以多实现 还可以在继承一个类的同时实现多个接口
接口与接口:
继承关系 可以单继承 也可以多继承
- 代码
==================【A类】==================
/*
类与类:继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
*/
public class A{
}
==================【B类】==================
/*
类与类:继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
*/
public class B extends A{
}
==================【C类】==================
/*
类与类:继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
类与接口:实现关系, 可以单实现, 也可以多实现, 还可以在继承一个类的同时实现多个接口.
*/
public class C extends B implements Inter1, Inter2{
}
==================【Inter1接口】==================
/*
类与接口:实现关系, 可以单实现, 也可以多实现, 还可以在继承一个类的同时实现多个接口.
*/
public interface Inter1 {
}
==================【Inter2接口】==================
public interface Inter2 {
}
==================【Inter3接口】==================
/*
接口与接口:继承关系, 可以单继承, 也可以多继承.
*/
public interface Inter3 extends Inter1, Inter2{
}
16.运动员和教练类案列
案例:运动员和教练
需求:
1. 已知乒乓运动员(PingPangPlayer)和篮球运动员(BasketballPlayer),乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach)。
2. 他们都有姓名和年龄,都要吃饭,但是吃的东西不同。
3. 乒乓球教练叫如何发球 篮球教练叫如何运球和投篮。
4. 乒乓球运动员学习如何发球,篮球运动员学习如何运球和投篮。
5. 为了出国交流,跟乒乓球相关的人员都需要学习英语。
6. 请用所学,模拟该知识。

- 代码实现
==================【Person类】==================
/**
* 父类 抽象类 abstract 抽象关键词
*/
public abstract class Person {
//私有属性 private
private String name;
private int age;
//空参构造
public Person() {
}
//全参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// get & set
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();
}
==================【Player运动员类】==================
/**
* 运动员类
*/
public abstract class Player extends Person{
//子空->父空, 子全 -> 父全
public Player() {
}
public Player(String name, int age) {
super(name, age);
}
// 抽象方法 学习
public abstract void study();
}
==================【Coach类】==================
/**
* 教练类 抽象类
*/
public abstract class Coach extends Person{
//子空->父空, 子全 -> 父全
public Coach() {
}
public Coach(String name, int age) {
super(name, age);
}
//抽象方法 教
public abstract void teach();
}
==================【说英语接口】==================
public interface Speak {
void speakEnglish();
}
==================【乒乓球运动员类】==================
/**
* 乒乓球运动员
*/
public class PingPangPlayer extends Player implements Speak{
public PingPangPlayer() {
}
public PingPangPlayer(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("乒乓球运动员吃烤鸭");
}
@Override
public void study() {
System.out.println("乒乓球运动员学习如何发球");
}
@Override
public void speakEnglish(){
System.out.println("乒乓球运动员学习英语");
}
}
==================【篮球运动员类】==================
/**
* 篮球运动员
*/
public class BasketballPlayer extends Player{
public BasketballPlayer() {
}
public BasketballPlayer(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("篮球运动员,吃鸡腿");
}
@Override
public void study() {
System.out.println("篮球运动员学习如何运球和投篮");
}
}
==================【乒乓球教练类】==================
public class PingPangCoach extends Coach implements Speak{
public PingPangCoach() {
}
public PingPangCoach(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("乒乓球吃饺子");
}
@Override
public void teach() {
System.out.println("乒乓球教练教如何发球");
}
@Override
public void speakEnglish(){
System.out.println("乒乓球教练学习说英语");
}
}
==================【篮球教练类】==================
/**
* 篮球教练
*/
public class BasketballCoach extends Coach{
public BasketballCoach() {
}
public BasketballCoach(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("篮球教练吃混沌");
}
@Override
public void teach() {
System.out.println("篮球教练教如何运球和投篮");
}
}

1万+

被折叠的 条评论
为什么被折叠?



