面向对象
你懂面向对象的奥义吗?你能接收面向对象的奥义吗?你的行为准则能按面向对象来吗?你真的可以接收自己面向对象的处事方式吗?
就是不必亲历亲为,做到开箱即用
类和对象
面向对象和面向过程编程思想
编程思想其实就是编程思路,我们开发中2种经典的编程思想就是面向过程编程思想和面向对象编程思想.
- 面向过程编程思想:强调的是过程,必须清楚每一个步骤,然后按照步骤一步一步去实现
- 面向对象编程思想:强调的是对象, 通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
举例对比2种编程思想
洗衣服:
- 面向过程:把衣服脱下来–>找一个盆–>放点洗衣粉–>加点水–>浸泡10分钟–>揉一揉–>清洗衣服–>拧干–>晾起来
- 面向对象: 把衣服脱下来–>给女朋友去洗
吃饭
- 面向过程: 买菜—>洗菜—>切菜—->炒菜—>吃
- 面向对象: 找个饭店–>20块钱
java程序上的区别:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class Test { public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50};
for (int i = 0; i < arr.length; i++) { int e = arr[i]; if (i == 0) { System.out.print("[" + e + ", "); } else if (i == arr.length - 1) { System.out.println(e + "]"); } else { System.out.print(e + ", "); } }
System.out.println("==================================");
System.out.println(Arrays.toString(arr)); } }
|
类的概述
类的概述
- 类是用来描述一类具有共同属性和行为事物的统称。所以其实类在客观世界里是不存在的,是抽象的,只是用来描述数据信息的。
- 手机类—描述手机
- 人类—-描述人
类的组成
- 属性:该类事物的状态信息,在类中通过成员变量来体现(类中方法外的变量)
- 行为:该类事物有什么功能,在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)
举例
- 手机类
- 人类:
- 属性: 姓名,年龄,性别….
- 行为:吃饭,睡觉,…..
对象的概述
对象的概念
- 对象是类的一个实例(并不是你的女朋友哈),具体存在的,看得见摸得着的,并且具备该类事物的属性和行为
- 对象的属性:对象的属性具有特定的值
- 对象的行为:对象可以操作的行为
举例
- 对象: 你手上拿的这台手机
- 属性:华为、1999。 对象的属性具体的值,类中的属性没有具体的值
- 行为:使用打电话功能,使用发短信功能。对象可以使用行为
类和对象的关系
类是对一类具有共同属性和行为的事物的统称,是抽象的
对象是一类事物的具体实例,看得见,摸的着的,真实存在的实体,是具体的
类是对象的抽象,对象是类的实体
类的定义
1 2 3 4 5 6 7 8 9 10
| public class 类名 { 数据类型 变量名1; 数据类型 变量名2; ... 方法; 去掉static }
|
举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Phone {
String brand;
double price;
public void call(String phoneNum){ System.out.println("正则给"+phoneNum+"打电话..."); }
public void sendMessage(String phoneNum,String message){ System.out.println("正在给"+phoneNum+"发送短信,短信内容是:"+message); } }
|
对象的创建和使用
创建对象的格式:
类名 对象名 = new 类名();
- 类其实就是对象的数据类型,类是引用数据类型
- 例: Phone p1 = new Phone (); 创建了一个手机对象(Phone类的对象)
对象的使用
- 访问成员变量
- 获取成员变量的值: 对象名.成员变量名
- 给成员变量赋值: 对象名.成员变量名=值;
- 访问成员方法
案例演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| public class Phone {
String brand;
double price;
public void call(String phoneNum){ System.out.println("正在给"+phoneNum+"打电话..."); }
public void sendMessage(String phoneNum,String message){ System.out.println("正在给"+phoneNum+"发送短信,短信内容是:"+message); }
public int show(String str){ System.out.println("有参数有返回值的方法:"+str); return 100; } }
public class Test { public static void main(String[] args) {
Phone p1 = new Phone(); p1.brand = "华为"; p1.price = 999.8;
System.out.println(p1.brand); System.out.println(p1.price);
p1.call("10086"); p1.sendMessage("10086","请问一下联通的客服电话号码是多少?");
System.out.println("=============================="); p1.show("张三");
int res = p1.show("李四"); System.out.println("res:"+res);
System.out.println(p1.show("java"));
} }
|
学生对象-练习
需求
- 首先定义一个学生类,然后定义一个学生测试类,在学生测试类中通过对象完成成员变量和成员方法的使用
分析
- 定义学生类
- 测试类
- 创建main方法,在main 方法中创建学生对象
- 使用学生对象访问成员变量和访问成员方法
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class Student {
String name;
int age;
public void study(){ System.out.println("学生正在学习Java..."); }
public void doHomeWork(){ System.out.println("学生正在做作业敲代码..."); } }
public class Test { public static void main(String[] args) { Student stu = new Student();
stu.name = "冰冰"; stu.age = 18; System.out.println(stu.name+","+stu.age);
stu.study(); stu.doHomeWork();
} }
|
成员变量默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class Student {
String name;
int age;
double score; char c; }
public class Test { public static void main(String[] args) {
Student stu = new Student(); System.out.println(stu.name); System.out.println(stu.age); System.out.println(stu.score); System.out.println("="+stu.c+"="); } }
|
单个对象内存图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class Student {
String name;
int age;
public void study(){ System.out.println("学生正在学习Java..."); }
public void doHomeWork(){ System.out.println("学生正在做作业敲代码..."); } }
public class Test { public static void main(String[] args) { Student stu = new Student(); System.out.println(stu);
stu.name = "冰冰"; stu.age = 18; System.out.println(stu.name+","+stu.age);
stu.study(); stu.doHomeWork(); } }
|
字节码文件会被加载到方法区。堆内存中的存的是成员方法的地址,通过地址找到方法区的方法。
多个对象内存图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| public class Student {
String name;
int age;
public void study(){ System.out.println("学生正在学习Java..."); }
public void doHomeWork(){ System.out.println("学生正在做作业敲代码..."); } }
public class Test { public static void main(String[] args) { Student stu1 = new Student(); System.out.println(stu1);
stu1.name = "冰冰"; stu1.age = 18; System.out.println(stu1.name+","+stu1.age);
stu1.study(); stu1.doHomeWork();
System.out.println("==========================");
Student stu2 = new Student();
System.out.println(stu2.name+","+stu2.age); stu2.study();
} }
|
绘制内存图
注意:
- 多个对象在堆内存中,都有不同的内存划分,成员变量存储在各自对象的内存区域中,成员方法多个对象共用的一份
- 凡是new就会重新在堆区开辟一块新空间
- 对象和对象之间的关系是相互独立的
多个变量指向相同对象内存图
查看程序案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class Student {
String name;
int age;
public void study(){ System.out.println("学生正在学习Java..."); }
public void doHomeWork(){ System.out.println("学生正在做作业敲代码..."); } } public class Test { public static void main(String[] args) { Student stu1 = new Student();
stu1.name = "冰冰"; stu1.age = 18; System.out.println(stu1.name + "," + stu1.age);
stu1.study();
System.out.println("============================"); Student stu2 = stu1;
System.out.println(stu2.name + "," + stu2.age); stu2.study(); } }
|
绘制内存图
注意点:
- 当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)
- 只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据。
- 引用类型传递的是地址值
成员变量和局部变量的区别
- 类中位置不同:成员变量(类中方法外)局部变量(方法内部或方法声明上)
- 内存中位置不同:成员变量(堆内存)局部变量(栈内存)
- 生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而存在,随着方法的调用完毕而消失)
- 初始化值不同:成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Car { String color;
public void drive(){ int speed = 80; System.out.println("汽车正在以"+speed+"迈的速度行驶..."); } }
public class Test {
public static void main(String[] args) { Car car = new Car(); car.drive(); } }
|
封装
private关键字
private的含义
- 概述: private是一个权限修饰符,代表最小权限。
- 特点:
- 可以修饰成员变量和成员方法。
- 被private修饰后的成员变量和成员方法,只在本类中才能访问。
private的使用格式
1 2 3 4 5 6 7
| private 数据类型 变量名 ;
private 返回值类型 方法名(参数列表){ 代码 }
|
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class Student {
private String name;
private int age;
private void study(){ System.out.println("正在学习java"); }
public void show(){ System.out.println(name+","+age); } }
public class Test { public static void main(String[] args) {
Student stu1 = new Student();
} }
|
为什么要对属性进行封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class Student {
String name;
int age; }
public class Test { public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "冰冰"; stu1.age = -18; System.out.println(stu1.name + "," + stu1.age);
} }
|
set和get方法
set和get方法的介绍
set和get方法的书写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| public class Student {
private String name;
private int age;
public void setName(String s){ name = s; }
public void setAge(int a){ if (a < 0 || a > 150){ age = -1; System.out.println("您的数据不合法!"); }else{ age = a; } } public String getName(){ return name; }
public int getAge(){ return age; } }
public class Test { public static void main(String[] args) {
Student stu1 = new Student();
stu1.setName("冰冰"); stu1.setAge(-18); System.out.println(stu1.getName()+","+stu1.getAge());
} }
|
this关键字
问题
我们发现 setXxx
方法中的形参名字并不符合见名知意的规定,那么如果修改与成员变量名一致,是否就见名知意了呢?代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| public class Student { private String name; private int age;
public void setName(String name) { name = name; }
public void setAge(int age) { age = age; } }
|
经过修改和测试,我们发现新的问题,成员变量赋值失败了。也就是说,在修改了setXxx()
的形参变量名后,方法并没有给成员变量赋值!这是由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无法访问到成员变量,从而赋值失败。所以,我们只能使用this关键字,来解决这个重名问题。
this的含义和使用
- 使用
this
修饰方法中的变量,解决成员变量被隐藏的问题,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| public class Student {
private String name;
private int age;
public void setName(String name){ this.name = name; }
public void setAge(int age){ if (age < 0 || age > 150){ this.age = -1; System.out.println("您的数据不合法!"); }else{ this.age = age; } } public String getName(){ return name; }
public int getAge(){ return age; } }
public class Test { public static void main(String[] args) {
Student stu1 = new Student();
stu1.setName("冰冰"); stu1.setAge(-18); System.out.println(stu1.getName()+","+stu1.getAge());
Student stu2 = new Student(); stu2.setName("空空");
} }
|
小贴士:方法中只有一个变量名时,默认也是使用 this
修饰,可以省略不写。
this内存原理
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| public class Test { public static void main(String[] args) {
Student stu1 = new Student();
stu1.setName("冰冰"); stu1.setAge(-18); System.out.println(stu1.getName()+","+stu1.getAge());
Student stu2 = new Student(); stu2.setName("空空"); System.out.println(stu2.getName()+","+stu2.getAge());
} }
public class Student {
private String name;
private int age;
public void setName(String name){ this.name = name; }
public void setAge(int age){ if (age < 0 || age > 150){ this.age = -1; System.out.println("您的数据不合法!"); }else{ this.age = age; } } public String getName(){ return name; }
public int getAge(){ return age; } }
|
封装概述
封装概述
- 是面向对象三大特征之一(封装,继承,多态)
- 是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的
封装原则
- 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
- 例如:成员变量使用private修饰,提供对应的getXxx()/setXxx()方法
封装好处
- 通过方法来控制成员变量的操作,提高了代码的安全性
- 把代码用方法进行封装,提高了代码的复用性
构造方法
构造方法是一种特殊的方法,主要是完成对象的创建和对象数据的初始化
格式
1 2 3 4 5 6 7 8 9
| 修饰符 类名(){ }
修饰符 类名(参数列表){ }
|
特点:
- 构造方法的写法上,方法名与它所在的类名相同
- 构造方法没有返回值,所以不需要返回值类型,甚至不需要void
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public class Student {
private String name;
private int age;
public Student(){ System.out.println("空参方法"); }
public Student(String name,int age){ this.name = name; this.age = age; }
public String getName(){ return name; }
public int getAge(){ return age; } }
public class Test { public static void main(String[] args) {
Student stu1 = new Student(); System.out.println(stu1.getName()+","+stu1.getAge());
Student stu2 = new Student("冰冰",18); System.out.println(stu2.getName()+","+stu2.getAge());
} }
|
注意事项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| public class Student {
private String name;
private int age;
public Student(){
} public Student(String name,int age){ this.name = name; this.age = age; }
public Student(String name){ this.name = name; }
public Student(int age){ this.age = age; }
public void setAge(int age){ this.age = age; }
public int getAge(){ return age; } }
public class Test { public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student("冰冰",18); Student stu3 = new Student("冰冰",18);
System.out.println(stu2.getAge()); stu2.setAge(19); System.out.println(stu2.getAge()); stu2.setAge(20); System.out.println(stu2.getAge());
} }
|
小结
1 2 3 4 5 6 7 8
| 构造方法的注意事项: - 构造方法的创建 - 如果没有定义构造方法,系统将给出一个默认的无参数构造方法 - 如果定义了构造方法,系统将不再提供默认的构造方法 - 构造方法只能给属性赋值一次,不能重复赋值,可以谁有set方法给属性重复赋值 - 构造方法可以重载,既可以定义参数,也可以不定义参数。 - 定义构造方法的时候,不要写返回值,连void都不能有 - 定义构造方法的时候,构造方法名和类名一定要一致
|
标准类制作
标准类的组成
JavaBean
是 Java语言编写类的一种标准规范。符合JavaBean
的类,要求类必须是公共的,属性使用private修饰,并且具有无参数的构造方法,提供用来操作成员变量的set
和get
方法。
1 2 3 4 5 6 7 8 9
| public class ClassName{ }
|
案例演示
- 需求:定义标准学生类,要求分别使用空参和有参构造方法创建对象,空参创建的对象通过setXxx赋值,有参创建的对象直接赋值,并通过show方法展示数据。
- 示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class Student {
private String name;
private int age;
public Student() { }
public Student(String name, int age) { this.name = name; this.age = 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 show(){ System.out.println(name+","+age); }
}
|
API
什么是API
API (Application Programming Interface) :应用程序编程接口。Java API是一本程序员的字典
,是JDK中提供给我们使用的类的说明文档。这些类将底层的代码实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可。所以我们可以通过查询API的方式,来学习Java提供的类,并得知如何使用它们。
- API其实就是jdk中核心类库的说明文档
- 对于jdk中的核心类库只需要知道如何使用,无须关心他是如何实现的
使用步骤
- 打开API帮助文档。
- 点击显示,找到索引,看到输入框。
- 你要找谁?在输入框里输入,然后回车。
- 看包。java.lang下的类不需要导包,其他需要。
- 看类的解释和说明。
- 看构造方法。
- 看成员方法。
演示API的使用
找到索引选项卡中的输入框
在输入框中输入Random
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public class Test { public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入年龄:"); int age = sc.nextInt(); System.out.println("年龄:"+age);
System.out.println("请输入姓名:"); String name = sc.next(); System.out.println("姓名:"+name);
} }
|
对象的内存图
注意点:
- 只要是new对象就会在堆区开辟一块独立的空间
- 只要调用方法,方法就会被加载进栈
- 只要方法执行完毕,方法就会被弹栈
匿名对象
什么是匿名对象:就是指”没有名字”的对象。
1 2 3 4 5 6
| 有名字的对象: Student stu = new Student(); stu.show(); stu.study(); 匿名对象: new Student();
|
特点:匿名对象只能使用一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class Test { public static void main(String[] args) {
Student stu1 = new Student("热巴",18); stu1.show(); stu1.show();
System.out.println("=================================="); new Student("热巴",18).show(); new Student("热巴",18).show();
System.out.println("=================================="); Student stu2 = new Student("热巴",18); method1(stu2); method1(new Student("热巴",18));
System.out.println("=================================="); Student stu3 = method2(); stu3.show();
}
public static void method1(Student stu){ stu.show(); }
public static Student method2(){
return new Student("丽颖",18); }
}
|
继承
如果满足 is a的时候,可以考虑时候继承
继承概述
为什么要有继承
现实生活中,为什么要有继承?
程序中为什么要有继承?
继承的含义
继承:在java中指的是“一个类”可以“继承自”“另一个类”。 “被继承的类”叫做: 父类/超类/基类,”继承其他类的类”叫做:子类。继承后,“子类”中就“拥有”了“父类”中所有的成员(成员变量、成员方法)。 “子类就不需要再定义了”。
继承的好处
- 提高代码的复用性(减少代码冗余,相同代码重复利用)。
- 使类与类之间产生了关系。
继承的格式
通过 extends
关键字,可以声明一个子类继承另外一个父类,定义格式如下:
1 2 3 4 5 6 7
| class 父类 { ... }
class 子类 extends 父类 { ... }
|
需要注意:Java是单继承的,一个类只能继承一个直接父类,并且满足is-a的关系,例如:Dog is a Animal, Student is a Person
继承的演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| 人类: public class Person { String name; int age; public void eat(){ System.out.println("吃东西..."); }
public void sleep(){ System.out.println("睡觉..."); } } 老师类: extends 人类 public class Teacher extends Person { double salary; public void teach(){} } 学生类: extends 人类 public class Student extends Person{
} Dog: extends 人类 public class Dog extends Person{
} 测试: public class Test { public static void main(String[] args) { Teacher t = new Teacher(); System.out.println(t.name); System.out.println(t.age); t.eat(); t.sleep(); } }
|
继承后成员访问规则
继承后构造方法的访问规则
构造方法不能被继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Fu { Fu(){} Fu(String name,int age){} }
class Zi extends Fu{
}
public class Test { public static void main(String[] args) {
} }
|
继承后私有成员的访问规则
继承后非私有成员的访问规则
方法重写
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class Fu{ public void method(){ System.out.println("Fu method"); } } class Zi extends Fu{
@Override public void method() { System.out.println("Zi method"); }
public void show(){ System.out.println("Zi show"); } } public class Test { public static void main(String[] args) {
Zi zi = new Zi(); zi.method(); } }
|
注意事项
方法重写是发生在子父类之间的关系。
子类方法重写父类方法,返回值类型、方法名和参数列表都要一模一样。
子类方法重写父类方法,必须要保证权限大于等于父类权限。
- 访问权限从大到小: public protected (默认) private
使用@Override注解,检验是否重写成功,重写注解校验!
- 建议重写方法都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!
使用场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| class Fu{ public void sport(){ System.out.println("Fu 运动的方式跑步"); }
public void run(){ System.out.println("Fu 第1圈"); System.out.println("Fu 第2圈"); System.out.println("Fu 第3圈"); } }
class Zi extends Fu{ @Override public void sport() { System.out.println("Zi 运动的方式游泳"); }
@Override public void run() { super.run();
System.out.println("Zi 第4圈"); System.out.println("Zi 第5圈"); System.out.println("Zi 第6圈"); System.out.println("Zi 第7圈"); System.out.println("Zi 第8圈"); System.out.println("Zi 第9圈"); System.out.println("Zi 第10圈"); } }
public class Test { public static void main(String[] args) {
Zi zi = new Zi(); zi.sport(); zi.run();
} }
|
this和super关键字
this和super关键字的介绍
- this:存储的“当前对象”的引用;
- this可以访问:本类的成员属性、成员方法、构造方法;
- super:存储的“父类对象”的引用;
- super可以访问:父类的成员属性、成员方法、构造方法;
this关键字的三种用法
super关键字的三种用法
小结
this关键字的三种用法:
this可以访问本类的成员变量: this.成员变量 一般用来区分同名的成员变量和局部变量
this可以访问本类的成员访问: this.成员方法名(实参);
this可以访问本类的构造方法:
空参构造: this();
有参构造: this(实参);
注意:
1.只能在本类的构造方法中使用this调用其他构造方法
2.在本类的构造方法中使用this调用其他构造方法,必须放在该构造方法的第一行,否则会报错
3.两个构造方法不能使用this同时相互调用
1 2 3 4 5 6 7 8 9 10 11 12
| - ```java super关键字的三种用法: super可以访问父类的成员变量: super.成员变量 一般用来区分父子类中同名的成员变量 super可以访问父类的成员方法: super.成员方法(实参); 一般用来在子类中访问父类的成员方法 super可以访问父类的构造方法: 空参构造: super(); 有参构造: super(实参); 注意: 1.子类的构造方法默认会调用父类的空参构造方法 2.super访问父类的构造方法,可以用来初始化从父类继承过来的属性 3.在子类的构造方法中,使用super调用父类的构造方法,必须放在子类构造方法的第一行
|
super的注意事项
super访问成员变量和成员方法: 优先去父类中找,如果有就直接使用,如果没有就去爷爷类中找,如果有,就用,依次类推…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Ye{ int num = 10; public void method(){ System.out.println("Ye method"); } } class Fu extends Ye{ int num = 100; public void method(){ System.out.println("Fu method"); } } class Zi extends Fu{ int num = 1000; public void show(){ System.out.println(super.num); super.method(); } }
public class Test { public static void main(String[] args) {
Zi zi = new Zi(); zi.show(); } }
|
子类的构造方法默认会调用父类的空参构造方法,如果父类中的没有空参构造方法,只定义了有参构造方法,会编译报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| class Fu1{ public Fu1(){ System.out.println("Fu1 空参构造"); }
public Fu1(int num){ System.out.println("Fu1 有参构造"); } }
class Zi1 extends Fu1{ public Zi1(){ }
public Zi1(int num){ } }
class Person{ private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public void show(){ System.out.println(name+","+age); } }
class Student extends Person{ public Student(String name,int age){ super(name,age); } }
public class Test2 { public static void main(String[] args) {
Student stu = new Student("张三", 18); stu.show();
} }
|
子类构造方法中使用super调用父类的构造方法,是为了在创建子类对象的时候,初始化从父类继承过来的属性
继承体系对象的内存图
继承的特点
- Java只支持单继承,不支持多继承。但是可以多层继承,java中所有类都是直接或者间接继承Object,所有类都是Object类的子类
1 2 3 4 5 6 7 8 9 10 11 12 13
| class A { } class B { } class C1 extends A { } class C2 extends A, B { }
|
- 一个类只能有一个父类,但可以有多个子类。
1 2 3 4 5 6 7 8 9 10
| class A { } class C1 extends A { } class C2 extends A { }
|
- 可以多层继承。
1 2 3 4 5 6 7 8 9
| class A { } class B extends A { } class C extends B { }
|
补充: 顶层父类是Object类。所有的类默认继承Object,作为父类。
class A {} 默认继承Object类 直接继承Object类
class B extends A{} B的父类就是A,但是A的父类是Object类 间接继承Object类
java中所有类都是直接或者间接继承Object,所有类都是Object类的子类
抽象类
抽象类的概述和定义
抽象类的概述
- 概述: 使用abstract关键字修饰的类就是抽象类
- 特点: 这种类不能被创建对象,它就是用来做父类的,被子类继承的
抽象类的定义
格式:
1 2 3
| 修饰符 abstract class 类名{ }
|
例如:
1 2 3
| public abstract class Person{
}
|
抽象类中的成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public abstract class Animal { private String name; private int age; public Animal(){
} public Animal(String name,int age){ this.name = name; this.age = 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 show(){ System.out.println(name+","+age); }
}
public class Test { public static void main(String[] args) {
} }
|
抽象方法的概述和定义
抽象方法的概述
- 没有方法体,使用abstract修饰的方法就是抽象方法
抽象方法的定义
1 2 3
| 修饰符 abstract 返回值类型 方法名(形参列表); 例如: public abstract void work();
|
抽象方法的作用: 强制要求子类重写的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| public abstract class Animal { private String name; private int age; public Animal(){
} public Animal(String name, int age){ this.name = name; this.age = 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 show(){ System.out.println(name+","+age); }
public abstract void eat();
}
public class Dog extends Animal { @Override public void eat() { System.out.println("狗吃骨头..."); } }
package com.itheima.demo14_抽象方法的概述和定义;
public class Cat extends Animal {
@Override public void eat() { System.out.println("猫吃鱼..."); } }
public class Test { public static void main(String[] args) {
Dog d = new Dog(); d.eat();
Cat c = new Cat(); c.eat(); } }
|
抽象类的注意事项
- 抽象类不能被创建对象,就是用来做“父类”,被子类继承的。
- 抽象类不能被创建对象,但可以有“构造方法”——为成员变量初始化。
- 抽象类中可以没有抽象方法,但抽象方法必须定义在抽象类中
- 子类继承抽象类后,必须重写抽象类中所有的抽象方法,否则子类必须也是一个抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| abstract class Animal{ private String name; private int age;
public Animal() { }
public Animal(String name, int age) { this.name = name; this.age = age; }
public void show(){ System.out.println(name+","+age); }
} class Dog extends Animal{ public Dog() { super(); }
public Dog(String name, int age) { super(name, age); } }
abstract class Person{ public abstract void eat(); public abstract void drink();
}
class Student extends Person{
@Override public void eat() { }
@Override public void drink() { } }
abstract class Teacher extends Person{ @Override public void eat() { } }
public class Test { public static void main(String[] args) {
Dog d = new Dog("旺财", 2); d.show(); } }
|
模板设计模式
设计模式概述
- 设计模式就是解决一些问题时的固定思路,也就是代码设计思路经验的总结。
模板设计模式概述
- 针对某些情况,在父类中指定一个模板,然后根据具体情况,在子类中灵活的具体实现该模板
1 2 3 4 5 6 7 8 9
| public abstract class Person{ public void sleep(){ System.out.println("两眼一闭,就睡觉..."); } public abstract void eat(); }
|
- 抽象类体现的就是模板设计思想,模板是将通用的东西在抽象类中具体的实现,而模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求
模板模式的实现步骤
- 定义抽象父类作为模板
- 在父类中定义”模板方法”— 实现方法(通用模板)+抽象方法(填充模板)
- 子类继承父类,重写抽象方法(填充父类的模板)
- 测试类:
- 创建子类对象,通过子类调用父类的“实现的方法”+ “子类重写后的方法” e
案例演示
假如我现在需要定义新司机和老司机类,新司机和老司机都有开车功能,开车的步骤都一样,只是驾驶时的姿势有点不同,新司机:开门,点火,双手紧握方向盘,刹车,熄火
,老司机:开门,点火,右手握方向盘左手抽烟,刹车,熄火
。那么这个时候我们就可以将固定流程写到父类中,不同的地方就定义成抽象方法,让不同的子类去重写
分析:
- 司机类
- 开车方法: 确定实现–通用模板
- 姿势方法: 不确定实现–填充模板
- 新司机类继承司机类,重写姿势方法
- 老司机类继承司机类,重写姿势方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public abstract class Driver { public void driveCar(){ System.out.println("开门"); System.out.println("点火"); ziShi(); System.out.println("刹车"); System.out.println("熄火"); }
public abstract void ziShi(); }
|
现在定义两个使用模板的司机:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class NewDriver extends Driver { @Override public void ziShi() { System.out.println("双手紧握方向盘"); } }
public class OldDriver extends Driver { @Override public void ziShi() { System.out.println("右手握方向盘左手抽烟"); } }
|
编写测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Test {
public static void main(String[] args) { NewDriver d1 = new NewDriver(); d1.driveCar();
OldDriver d2 = new OldDriver(); d2.driveCar(); }
}
|
运行效果
可以看出,模板模式的优势是,模板已经定义了通用架构,使用者只需要关心自己需要实现的功能即可!非常的强大!
final关键字
final: 不可改变。可以用于修饰类、方法和变量。
- 类:被修饰的类,不能被继承。
- 方法:被修饰的方法,不能被重写。
- 变量:被修饰的变量,就只能赋值一次,不能被重新赋值。
修饰类
格式如下:
1 2 3 4 5 6 7 8 9
| 修饰符 final class 类名 { } 例如: public final class FinalClassFu { } public class FinalClassZi { }
|
查询API发现像 public final class String
、public final class Math
、public final class Scanner
等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。
修饰方法
格式如下:
1 2 3
| 修饰符 final 返回值类型 方法名(参数列表){ }
|
重写被 final
修饰的方法,编译时就会报错。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class FinalMethodFu { public final void show(){
} } public class FinalMethodZi extends FinalMethodFu {
}
|
修饰变量
局部变量——基本类型
基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。代码如下:
1 2 3 4 5 6 7
| public class FinalDemo1 { public static void main(String[] args) { final int NUM = 10; } }
|
局部变量——引用类型
引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改,代码如下:
1 2 3 4 5 6 7 8 9
| public class FinalDemo2 { public static void main(String[] args) { final Student stu = new Student("张三",18); stu.setAge(19); } }
|
成员变量
成员变量涉及到初始化的问题,初始化方式有两种,只能二选一:
显示初始化;
1 2 3
| public class FinalVariable { final int NUM1 = 10; }
|
构造方法初始化。
1 2 3 4 5 6 7 8 9
| public class FinalVariable { final int NUM2; public FinalVariable(int NUM2){ this.NUM2 = NUM2; } public FinalVariable(){ this.NUM2 = 10; } }
|
被final修饰的常量名称,一般都有书写规范,所有字母都大写。
static关键字
之前咋们写main方法的时候,使用过了一个static关键字,接下来我们来学习一下static关键字
static关键字概述
static是一个静态修饰符关键字,表示静态的意思,可以修饰成员变量和成员方法以及代码块。
static关键字的使用
static修饰成员变量
当 static
修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。
定义格式
静态成员变量的访问方式
1 2
| 对象名.静态成员变量名; 不推荐 类名.静态成员变量名; 推荐
|
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class Person { String name; static String country;
public Person() { }
public Person(String name, String country) { this.name = name; this.country = country; } }
public class Test { public static void main(String[] args) { Person p1 = new Person("张三", "中国"); System.out.println(p1.name+","+p1.country);
System.out.println("=======================");
Person p2 = new Person(); System.out.println(p2.name+","+p2.country);
System.out.println("=======================");
System.out.println(Person.country); } }
|
static修饰成员方法
被static修饰的方法会变成静态方法,也称为类方法,该静态方法可以使用类名直接调用。
格式
1 2 3
| 修饰符 static 返回值类型 方法名 (参数列表){ }
|
访问方式
1 2
| 对象名.方法名(实参); 类名.方法名(实参); 推荐
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Person { public void method1(){ System.out.println("Person method1..."); }
public static void method2(){ System.out.println("Person method2..."); } } public class Test { public static void main(String[] args) {
Person p = new Person(); p.method2();
Person.method2();
} }
|
静态方法调用的注意事项:
- 静态方法中不能出现this关键字
- 静态方法中只能直接访问静态成员变量和静态成员方法
- 静态方法中不能直接访问非静态成员变量和非静态成员方法
- 非静态方法中可以直接访问一切成员变量和成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| public class ChinesePeople { String name; static String country;
public void method1(){ System.out.println("非静态 method2方法"); }
public void method2(){ System.out.println(name); System.out.println(country); method1(); method4();
System.out.println("非静态 method2方法"); }
public static void method3(){
System.out.println("静态成员变量:"+country); method4();
System.out.println("非静态 method3方法"); }
public static void method4(){ System.out.println("非静态 method4方法"); } }
public class Test { public static void main(String[] args) {
ChinesePeople.method3();
}
}
|
以后开发中static的应用
概述
以后的项目中,通常会需要一些“全局变量”或者“全局的工具方法”,这些全局变量和方法,可以单独定义在一个类中,并声明为static(静态)的,可以很方便的通过类名访问
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class Utils { public static final int WIDTH = 800; public static final int HEIGHT = 800;
public static int getArrayMax(int[] arr){ int max = arr[0]; for (int i = 0; i < arr.length; i++) { if(arr[i] > max){ max = arr[i]; } } return max; } }
public class Test { public static void main(String[] args) {
System.out.println(Utils.width); System.out.println(Utils.height);
int[] arr = {23,34,545,56}; System.out.println(Utils.getArrayMax(arr)); } }
|
小结
1 2 3 4 5 6 7 8 9 10 11
| static修饰成员方法: 格式: 在返回值类型前面加static关键字 使用: 类名.静态方法名(实参); 注意事项: 1.静态方法中不能出现this 2.静态方法中只能直接访问静态成员变量和成员方法 3.非静态方法中可以直接访问一切成员变量和成员方法 static修饰成员变量: 格式: static 数据类型 变量名; 使用; 类名.静态成员变量名 特点; 被static修饰的变量会被该类的所有对象共享
|
接口
概述
引用数据类型除了类其实还有接口,接下来学习接口的概述
概述: 接口是Java语言中的一种引用类型,是方法的”集合”,所以接口的内部主要就是定义方法,包含常量,抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(jdk9)。
接口的定义,它与定义类方式相似,但是使用 interface
关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。
public class 类名{}–>.class
public interface 接口名{}->.class
引用数据类型:数组,类,接口。
接口的使用,它不能创建对象,但是可以被实现(implements
,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
小结
- 接口是java语言中的一种引用数据类型
- 接口中的成员:
- 常量(jdk7及其以前)
- 抽象方法(jdk7及其以前)
- 默认方法和静态方法(jdk8额外增加)
- 私有方法(jdk9额外增加)
- 定义接口使用interface关键字—接口编译后产生class文件
- 接口不能创建对象,需要使用实现类实现接口(类似于继承),实现接口的类叫做实现类(子类)
定义格式
格式
1 2 3 4 5 6 7
| public interface 接口名称 { }
|
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public interface IA { public static final int NUM1 = 10; int NUM2 = 20;
public abstract void method1(); void method2();
public default void method3(){ System.out.println("默认方法 method3"); }
public static void method4(){ System.out.println("静态方法 method4"); } private static void method5(){ System.out.println("私有静态方法 method5"); }
private void method6(){ System.out.println("私有非静态方法 method6"); } }
|
实现接口
实现概述
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements
关键字。
实现格式
接口中成员的访问特点
接口中成员访问特点概述
1 2 3 4 5 6
| 接口中成员的访问特点: 接口中的常量: 主要是供接口直接使用 接口中的抽象方法: 供实现类重写的 接口中的默认方法: 供实现类继承的(实现类中可以直接调用,实现类对象也可以直接调用) 接口中的静态方法: 只供接口直接调用,实现类继承不了 接口中的私有方法: 只能在接口中直接调用,实现类继承不了
|
案例演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| public interface IA { public static final int NUM = 10;
public abstract void method1();
public default void method2(){ System.out.println("IA 接口中的默认方法method2"); }
public static void method3(){ System.out.println("IA 接口中的静态方法method3"); }
private void method4(){ System.out.println("IA 接口中的私有方法method4"); }
private static void method5(){ System.out.println("IA 接口中的私有方法method5"); } }
public class Imp implements IA { @Override public void method1() { System.out.println("实现类重写IA接口中的抽象方法"); }
@Override public void method2() { System.out.println("实现类重写IA接口中的默认方法"); }
}
public class Test { public static void main(String[] args) {
System.out.println(IA.NUM);
Imp imp = new Imp();
imp.method1();
imp.method2();
IA.method3(); } }
|
小结
- 接口中成员访问特点:
- 常量:主要是供接口名直接访问
- 抽象类:就是用来给实现类重写的
- 默认方法:只供实现类重写或者实现类对象直接调用
- 静态方法:只供接口名直接调用
- 私有方法:只能在本接口中调用
多实现时的几种冲突情况
公有静态常量的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| interface A{ public static final int NUM1 = 10; } interface B{ public static final int NUM1 = 20; public static final int NUM2 = 30; } class Imp implements A,B{
} public class Test { public static void main(String[] args) {
System.out.println(Imp.NUM2); } }
|
公有抽象方法的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| interface A{ public abstract void method(); } interface B{ public abstract void method(); } class Imp implements A,B{ @Override public void method() { System.out.println("实现类重写"); } } public class Test { public static void main(String[] args) {
} }
|
公有默认方法的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| interface A{ public default void method(){ System.out.println("A 接口的默认方法method"); } } interface B{ public default void method(){ System.out.println("B 接口的默认方法method"); } } class Imp implements A,B{ @Override public void method() { System.out.println("实现类重写的默认方法"); } } public class Test { public static void main(String[] args) {
Imp imp = new Imp(); imp.method(); } }
|
公有静态方法的冲突
私有方法的冲突
小结
1 2 3 4 5 6
| 多实现时的几种冲突情况: - 公有静态常量的冲突:实现类不继承冲突的常量 - 公有抽象方法的冲突:实现类只需要重写一个 - 公有默认方法的冲突:实现类必须重写一次最终版本 - 公有静态方法的冲突:静态方法是直接属于接口的,不能被继承,所以不存在冲突 - 私有方法的冲突:私有方法只能在本接口中直接使用,不存在冲突
|
接口和接口的关系
接口与接口之间的关系
接口多继承接口的冲突情况
公有静态常量的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| interface A{ public static final int NUM1 = 10; } interface B{ public static final int NUM1 = 20; public static final int NUM2 = 30; } interface C extends A,B{
} public class Test { public static void main(String[] args) {
System.out.println(C.NUM2); } }
|
公有抽象方法冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| interface A{ public abstract void method(); } interface B{ public abstract void method(); } interface C extends A,B{
} class Imp implements C{ @Override public void method() { System.out.println("实现接口的抽象方法"); } }
public class Test { public static void main(String[] args) {
Imp imp = new Imp(); imp.method(); } }
|
公有默认方法的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| interface A{ public default void method(){ System.out.println("A 接口中的默认方法method"); } } interface B{ public default void method(){ System.out.println("B 接口中的默认方法method"); } }
interface C extends A,B{
@Override public default void method() { System.out.println("重写父接口中的method方法"); } }
class Imp implements C{
}
public class Test { public static void main(String[] args) {
Imp imp = new Imp(); imp.method(); } }
|
公有静态方法和私有方法
- 不冲突,因为静态方法是直接属于接口的,只能使用本接口直接访问,而私有方法只能在接口中访问,也没有冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| interface A{ public static void method(){ System.out.println("A 接口的静态方法method"); } } interface B{ public static void method(){ System.out.println("B 接口的静态方法method"); } } interface C extends A,B{ } public class Test { public static void main(String[] args) {
} }
|
小结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| - 接口与接口之间的关系: 继承关系 单继承: A接口继承B接口 多继承: A接口同时继承B接口,C接口,... 多层继承: A接口继承B接口,B接口,继承C接口 格式: public interface 接口名 extends 接口名1,接口名2,...{ }
- 接口多继承时的冲突情况 - 公有静态常量的冲突:子接口无法继承父接口中冲突的常量 - 公有抽象方法的冲突:子接口只会继承一个有冲突的抽象方法 - 公有默认方法的冲突:子接口中必须重写一次有冲突的默认方法(注意要加default) - 公有静态方法和私有方法的冲突: 不冲突,因为静态方法是直接属于接口的,只能使用本接口直接访问,而私有方法只能在接口中访问,也没有冲突
面试题: 实现类重写接口中的默认方法,不需要加default 子接口重写父接口中的默认方法,必须加default
|
实现类继承父类又实现接口时的冲突
父类和接口的公有静态常量的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Fu{ public static final int NUM1 = 10; public static final int NUM2 = 100; } interface A{ public static final int NUM1 = 20;
} class Zi extends Fu implements A{
} public class Test { public static void main(String[] args) {
System.out.println(Zi.NUM2);
} }
|
父类和接口的抽象方法冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| abstract class Fu{ public abstract void method(); } interface A{ public abstract void method(); } class Zi extends Fu implements A{ @Override public void method() { System.out.println("Zi 重写有冲突的抽象方法"); } } public class Test { public static void main(String[] args) {
Zi zi = new Zi(); zi.method(); } }
|
父类和接口的公有默认方法的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Fu{ public void method(){ System.out.println("Fu 类中的默认方法method"); } } interface A{ public default void method(){ System.out.println("A 接口中的默认方法method"); } } class Zi extends Fu implements A{
} public class Test { public static void main(String[] args) {
Zi zi = new Zi(); zi.method(); } }
|
父类和接口的公有静态方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Fu{ public static void method(){ System.out.println("Fu 类中的静态方法method"); } } interface A{ public static void method(){ System.out.println("A 接口中的静态方法method"); } } class Zi extends Fu implements A{ } public class Test { public static void main(String[] args) {
Zi.method(); } }
|
父类和接口的私有方法
小结
1 2 3 4 5 6
| 实现类继承父类又实现接口时的冲突: - 公有静态常量的冲突:子类无法继承有冲突的常量 - 公有抽象方法的冲突:子类必须重写一次有冲突的抽象方法 - 公有默认方法的冲突:优先访问父类的 - 公有静态方法的冲突:只会访问父类的静态方法 - 私有方法的冲突: 不存在冲突
|
抽象类和接口的练习
需求
通过实例进行分析和代码演示抽象类和接口的用法。
1、举例:
犬: —抽象父类
行为:吼叫;吃饭;
缉毒犬:继承犬类,实现缉毒接口
行为:吼叫;吃饭;缉毒;
缉毒接口:
缉毒
- 如果一个父类中的某个方法,所有子类都有不同的实现,那么该方法就应该定义成抽象方法,所以该父类就是抽象类 (父类一般都是抽象类)
- 如果某个功能是一个类额外增加的,那么就可以把这个额外的功能定义到接口中,再这个类去实现
分析
由于犬分为很多种类,他们吼叫和吃饭的方式不一样,在描述的时候不能具体化,也就是吼叫和吃饭的行为不能明确。当描述行为时,行为的具体动作不能明确,这时,可以将这个行为写为抽象行为,那么这个类也就是抽象类。
可是有的犬还有其他额外功能,而这个功能并不在这个事物的体系中 , 例如 : 缉毒犬。缉毒的这个功能有好多种动物都有 , 例如 : 缉毒猪 , 缉毒鼠。我们可以将这个额外功能定义接口中 ,让缉毒犬继承犬且实现缉毒接口 , 这样缉毒犬既具备犬科自身特点也有缉毒功能。
- 额外的功能—> 在接口中定义,让实现类实现
- 共性的功能—> 在父类中定义,让子类继承
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public abstract class Dog { public abstract void houJiao(); public abstract void eat(); }
public interface JiDu { public abstract void jiDu(); }
public class JiDuDog extends Dog implements JiDu{ @Override public void houJiao() { System.out.println("缉毒犬找到了毒品,开始吼叫,汪汪汪...."); }
@Override public void eat() { System.out.println("缉毒之前,开始吃骨头..."); }
@Override public void jiDu() { System.out.println("吃完东西后,开始使用鼻子查找毒品...."); } }
public class Test { public static void main(String[] args) { JiDuDog jd = new JiDuDog(); jd.eat(); jd.jiDu(); jd.houJiao(); } }
|
小结
- 额外的功能—> 在接口中定义,让实现类实现
- 如果可以确定的通用功能,使用默认方法
- 如果不能确定的功能,使用抽象方法
- 共性的功能—> 在父类中定义,让子类继承
- 如果可以确定的通用功能,使用默认方法
- 如果不能确定的功能,使用抽象方法
新JDK接口使用思路:
多态
概述
多态是继封装、继承之后,面向对象的第三大特性。
生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
定义
- 多态: 是指同一行为,对于不同的对象具有多个不同表现形式。
- 程序中多态: 是指同一方法,对于不同的对象具有不同的实现.
前提条件【重点】
- 继承或者实现【二选一】
- 父类引用指向子类对象\接口引用指向实现类对象【格式体现】
- 方法的重写【意义体现:不重写,无意义】
实现多态
多态的体现:父类的引用指向它的子类的对象:
1 2
| 父类类型 变量名 = new 子类对象; 变量名.方法名();
|
父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Animal{ public void eat(){ System.out.println("吃东西"); } }
class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); } }
class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼..."); } }
public class Test1 { public static void main(String[] args) { Animal anl = new Dog(); anl.eat();
Animal anl1 = new Cat(); anl1.eat(); } }
|
多态时访问成员的特点
- 多态时成员变量的访问特点
- 多态时成员方法的访问特点
- 非静态方法:编译看左边,运行看右边
- 简而言之:编译的时候去父类中查找方法,运行的时候去子类中查找方法来执行
- 静态方法:编译看左边,运行看左边
- 简而言之:编译的时候去父类中查找方法,运行的时候去父类中查找方法来执行
- 注意:多态的情况下是无法访问子类独有的方法
除了非静态方法是编译看父类,运行看子类,其余都是看父类
演示代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Animal{ int num = 10; public void method1(){ System.out.println("Animal 非静态method1方法"); } public static void method2(){ System.out.println("Animal 静态method2方法"); } } class Dog extends Animal{ int num = 20;
public void method1(){ System.out.println("Dog 非静态method1方法"); }
public static void method2(){ System.out.println("Dog 静态method2方法"); } }
public class Test { public static void main(String[] args) { Animal anl = new Dog(); System.out.println(anl.num);
anl.method1(); anl.method2(); } }
|
多态的表现形式
普通父类多态
1 2 3 4 5 6 7
| public class Fu{} public class Zi extends Fu{} public class Demo{ public static void main(String[] args){ Fu f = new Zi(); } }
|
抽象父类多态
1 2 3 4 5 6 7
| public abstract class Fu{} public class Zi extends Fu{} public class Demo{ public static void main(String[] args){ Fu f = new Zi(); } }
|
父接口多态
1 2 3 4 5 6 7
| public interface A{} public class AImp implements A{} public class Demo{ public static void main(String[] args){ A a = new AImp(); } }
|
多态的应用场景
变量多态 —–> 意义不大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } } public class Test { public static void main(String[] args) { Animal anl = new Dog(); anl.eat();
anl = new Cat(); anl.eat(); } }
|
形参多态—-> 常用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } } public class Test { public static void main(String[] args) { Dog d = new Dog(); method(d);
System.out.println("===============================");
Cat c = new Cat(); method(c); }
public static void method(Animal anl){ anl.eat(); }
}
|
返回值多态—> 常用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } } public class Test { public static void main(String[] args) { Animal anl = method(); anl.eat(); }
public static Animal method(){ return new Cat(); }
public static Animal method1(){ if (1==1){ return new Animal(); }else if (2==2){ return new Dog(); }else{ return new Cat(); } } }
|
多态的好处和弊端
好处
弊端
- 多态的情况下,无法访问子类独有的方法或者成员变量,因为多态成员访问的特点是,编译看父类
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); }
public void lookHome(){ System.out.println("狗在看家..."); } } public class Test { public static void main(String[] args) {
Animal anl = new Dog(); anl.eat(); } }
|
引用类型转换
向上转型
子类类型向父类类型向上转换的过程,这个过程是默认的。
向下转型
父类类型向子类类型向下转换的过程,这个过程是强制的。
1 2
| Aniaml anl = new Cat(); Cat c = (Cat)anl;
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); }
public void lookHome(){ System.out.println("狗在看家..."); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼..."); } }
class Person{} public class Test { public static void main(String[] args) {
Animal anl = new Dog();
Dog dog = (Dog)anl;
System.out.println("===================================");
} }
|
instanceof关键字
向下强转有风险,最好在转换前做一个验证 :
格式:
1 2 3 4 5 6 7
| 变量名 instanceof 数据类型 如果变量属于该数据类型,返回true。 如果变量不属于该数据类型,返回false。
if( anl instanceof Cat){ Cat c = (Cat)anl; }
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); }
public void lookHome(){ System.out.println("狗在看家..."); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼..."); } } public class Test { public static void main(String[] args) {
Animal anl = new Cat();
if (anl instanceof Dog){ Dog d = (Dog)anl; }
System.out.println("正常结束"); } }
|
小结
1 2 3 4 5 6 7 8 9 10 11 12
| 引用类型转换: 向上转型:子类类型向父类类型向上转换的过程,这个过程是默认\自动的。 向下转型:父类类型向子类类型向下转换的过程,这个过程是强制\手动的。 格式: 子类类型 对象名 = (子类类型)父类类型的变量; 注意: 1.向下转型的时候:右边父类类型的变量一定要指向要转型的子类类型的对象 2.不管是向上转型还是向下转型,一定满足父子类关系或者实现关系
instanceof关键字: if(变量名 instanceof 数据类型){} 如果变量属于该数据类型,返回true。 如果变量不属于该数据类型,返回false。
|
解决多态的弊端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); }
public void lookHome(){ System.out.println("狗在看家..."); } } public class Test { public static void main(String[] args) {
Animal anl = new Dog(); anl.eat();
if (anl instanceof Dog){ Dog d = (Dog)anl; d.lookHome(); }
System.out.println("正常结束"); } }
|
多态的应用场景综合案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class Animal{ public void eat(){ System.out.println("吃东西..."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); }
public void lookHome(){ System.out.println("狗在看家..."); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼..."); } public void catchMouse(){ System.out.println("猫抓老鼠..."); } } public class Test { public static void main(String[] args) { Dog d = new Dog(); method(d);
System.out.println("==========================");
Cat c = new Cat(); method(c); }
public static void method(Animal anl){ anl.eat(); if (anl instanceof Dog){ Dog d = (Dog)anl; d.lookHome(); }
if (anl instanceof Cat){ Cat c = (Cat)anl; c.catchMouse(); }
} }
|
内部类
什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
成员内部类
定义格式:
1 2 3 4 5
| class 外部类 { class 内部类{
} }
|
在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类Car
中包含发动机类Engine
,这时,Engine
就可以使用内部类来描述,定义在成员位置。
代码举例:
1 2 3 4 5
| class Car { class Engine {
} }
|
访问特点
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
创建内部类对象格式:
1
| 外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
|
访问演示,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| public class Body {
public void methodW1(){ Heart bh = new Heart(); System.out.println(bh.numN); bh.methodN1(); }
private int numW = 100;
private void methodW2(){ System.out.println("外部类的成员方法 methodW2"); }
public class Heart{ int numN = 10;
public void methodN1(){ System.out.println("内部类的成员方法 methodN1"); }
public void methodN2(){ System.out.println(numW); methodW2(); } }
}
public class Test { public static void main(String[] args) {
Body.Heart bh = new Body().new Heart(); System.out.println(bh.numN); bh.methodN1();
System.out.println("======================="); Body b = new Body(); b.methodW1();
System.out.println("======================="); bh.methodN2();
} }
|
匿名内部类
是内部类的简化写法。它的本质是一个带具体实现的
父类或者父接口的
匿名的
子类对象。
代码一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| abstract class Animal{ public abstract void eat(); } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); } } public class Test { public static void main(String[] args) {
Dog d = new Dog(); d.eat();
System.out.println("=========================="); Animal anl = new Animal() { @Override public void eat() { System.out.println("匿名内部类"); } }; anl.eat(); } }
|
代码二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| interface A{ public abstract void show(); } class Imp implements A{ public void show(){ System.out.println("实现类实现show方法"); } } public class Test { public static void main(String[] args) {
Imp imp = new Imp(); imp.show();
System.out.println("=============================="); A a = new A() { @Override public void show() { System.out.println("匿名内部类"); } }; a.show(); } }
|
小结:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 对于类: 概述:本质其实就是一个类的匿名子类的对象 格式: new 类名(){ 实现抽象方法 }; 对于接口: 概述:本质是一个接口的匿名实现类的对象 格式: new 接口名(){ 实现抽象方法 }; 匿名内部类作用:就是用来简化代码的,没有其他的功能 使用场景: 如果方法的形参类型为抽象类或者接口类型,那么为了简化代码,可以直接传入该抽象类或者接口的匿名内部类
|
补充
1 2 3 4 5 6 7 8
| new Imp().show(); new A() { @Override public void show() { System.out.println("匿名内部类"); } }.show();
|
引用类型使用
实际的开发中,引用类型的使用非常重要,也是非常普遍的。我们可以在理解基本类型的使用方式基础上,进一步去掌握引用类型的使用方式。基本类型可以作为成员变量、作为方法的参数、作为方法的返回值,那么当然引用类型也是可以的。在这我们使用两个例子 , 来学习一下。
类名作为方法参数和返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class Person{ public String name; public int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public void show(){ System.out.println(name+","+age); } } public class Test { public static void main(String[] args) {
Person p = new Person("冰冰",18); method1(p); System.out.println("========================================="); Person person = method2(p); person.show(); }
public static void method1(Person p){ p.show(); }
public static Person method2(Person p){ p.age = 20; return p; } }
|
抽象类作为方法参数和返回值
- 抽象类作为形参:表示可以接收任何此抽象类的”子类对象”作为实参;
- 抽象类作为返回值:表示”此方法可以返回此抽象类的任何子类对象”;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| abstract class Animal{ public abstract void eat(); } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); } } public class Test { public static void main(String[] args) { method1(new Dog());
System.out.println("========================"); method1(new Animal() { @Override public void eat() { System.out.println("匿名内部类的方式..."); } });
System.out.println("========================"); Dog d = (Dog)method2(); }
public static void method1(Animal anl){ anl.eat(); }
public static Animal method2(){ return new Dog(); } }
|
接口作为方法参数和返回值
- 接口作为方法的形参:【同抽象类】
- 接口作为方法的返回值:【同抽象类】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| interface A{ void show(); } class Imp implements A{ public void show(){ System.out.println("实现类的方式实现show方法"); } } public class Test { public static void main(String[] args) { method1(new Imp());
System.out.println("===================");
method1(new A() { @Override public void show() { System.out.println("匿名内部类的方式实现show方法"); } });
System.out.println("===================");
Imp imp = (Imp) method2();
}
public static void method1(A a){ a.show(); }
public static A method2(){ return new Imp(); } }
|
类名作为成员变量
我们每个人(Person)都有一个身份证(IDCard) , 为了表示这种关系 , 就需要在Person中定义一个IDCard的成员变量。定义Person类时,代码如下:
1 2 3 4
| class Person { String name; int age; }
|
使用String
类型表示姓名 , int
类型表示年龄。其实,String
本身就是引用类型,我们往往忽略了它是引用类型。如果我们继续丰富这个类的定义,给Person
增加身份证号 , 身份证签发机关等属性,我们将如何编写呢?这时候就需要编写一个IDCard类了
修改Person类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Person{ String name; int age; IdCard idCard;
public Person(String name, int age, IdCard idCard) { this.name = name; this.age = age; this.idCard = idCard; } } class IdCard{ String idNum; String address;
public IdCard(String idNum, String address) { this.idNum = idNum; this.address = address; } } public class Test { public static void main(String[] args) { IdCard idCard = new IdCard("440330200010101919","广东省深圳市宝安区公安局"); Person p = new Person("张三",18,idCard); System.out.println(p.name+","+p.age+","+p.idCard.idNum+","+p.idCard.address); } }
|
类作为成员变量时,对它进行赋值的操作,实际上,是赋给它该类的一个对象。同理 , 接口也是如此 , 例如我们笔记本案例中使用usb设备。在此我们只是通过小例子 , 让大家熟识下引用类型的用法 , 后续在咱们的就业班学习中 , 这种方式会使用的很多。
抽象类作为成员变量
- 抽象类作为成员变量——为此成员变量赋值时,可以是任何它的子类对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| abstract class Pet{ String name;
public Pet(String name) { this.name = name; } } class Dog extends Pet{
public Dog(String name) { super(name); } } class Person{ String name; int age; Pet pet;
public Person(String name, int age, Pet pet) { this.name = name; this.age = age; this.pet = pet; } } public class Test { public static void main(String[] args) { Pet pet = new Dog("旺财"); Person p = new Person("张三",18,pet); System.out.println(p.name); System.out.println(p.age); System.out.println(p.pet.name);
} }
|
接口作为成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| abstract interface Pet{
} class Dog implements Pet{
} class Person{ String name; int age; Pet pet;
public Person(String name, int age, Pet pet) { this.name = name; this.age = age; this.pet = pet; } } public class Test { public static void main(String[] args) { Pet pet = new Dog(); Person p = new Person("张三",18,pet); System.out.println(p.name); System.out.println(p.age); System.out.println(p.pet);
} }
英雄: name,皮肤,法术(接口)
|
小结
1 2 3 4 5 6 7 8
| - 类名作为方法参数和返回值:可以直接传入该类的对象;返回该类的对象 - 抽象类作为方法参数和返回值:只能传入该类的子类对象;返回该类的子类对象 - 接口作为方法参数和返回值:只能传入该接口的实现类对象;返回该接口的实现类对象 传递的都是地址值,返回的也是地址值 - 类作为成员变量 : 赋该类的对象 - 抽象类作为成员变量 ; 赋该类的子类对象 - 接口作为成员变量 : 赋该接口的实现类对象
|
权限修饰符
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,
- public:公共的
- protected:受保护的
- (空的):默认的
- private:私有的
不同权限的访问能力
|
public |
protected |
(空的) |
private |
同一类中 |
√ |
√ |
√ |
√ |
同一包中(子类与无关类) |
√ |
√ |
√ |
|
不同包的子类 |
√ |
√ |
|
|
不同包中的无关类 |
√ |
|
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| 包:com.nbchen.demo9_权限修饰符 public class AAA { public void method1(){} protected void method2(){} void method3(){} private void method4(){}
public void method(){ method1(); method2(); method3(); method4(); } } public class Test { public static void main(String[] args) { AAA a = new AAA(); a.method1(); a.method2(); a.method3(); } }
包:com.nbchen.demo10_权限修饰符 public class Zi extends AAA { public void show(){ method1(); method2(); } } public class Test { public static void main(String[] args) { AAA a = new AAA(); a.method1(); } }
|
可见,public具有最大权限。private则是最小权限。
编写代码时,如果没有特殊的考虑,建议这样使用权限:
成员变量使用private
,隐藏细节。
构造方法使用 public
,方便创建对象。
成员方法使用public
,方便调用方法。
代码块
构造代码块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 格式: {} 位置: 类中,方法外 执行: 每次在调用构造方法的时候,就会执行 使用场景: 统计创建了多少个该类对象
例如: public class Person{ { 构造代码块执行了 } }
public class Test { public static void main(String[] args) {
Person p1 = new Person(); Person p2 = new Person(); } }
|
静态代码块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| 格式:static{} 位置: 类中,方法外 执行: 当类被加载的时候执行,并只执行一次 使用场景: 例如加载驱动,这种只需要执行一次的代码就可以放在静态代码块中
public class Person { static { System.out.println("Person 静态代码块"); }
{ System.out.println("Person 构造代码块"); }
public Person(){ System.out.println("Person 构造方法"); } }
public class Test {
public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person();
} }
|
局部代码块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 格式:{} 位置: 方法中 执行: 调用方法,执行到局部代码块的时候就执行 使用场景: 节省内存空间,没有多大的意义 例如: public class Test { public static void main(String[] args) {
System.out.println("开始"); { int num1 = 10; System.out.println("局部代码块"); }
System.out.println("结束"); } }
|