面向对象
面对对象相关概述详解:
1.什么是面向过程?
它是一种编程思想,强调是以 过程 为基础完成各种操作,每一步都要亲力亲为。
代表语言C语言
2.什么是面向对象?
它是一种编程思想,强调是以 对象 为基础完成各种操作,把事情交给对象做,我们负责管理对象即可。
代表语言Java。
思想特点:
1.把复杂的事情简单化。
2.更符合人们的思考习惯。
3.把程序员从执行者变成指挥者。
- Java语言是用来描述现实世界事物的, 最基本的单位是: 类。
- **类:**是一个抽象的概念, 看不见, 也摸不着, 它是属性和行为的集合.
- **对象:**类的具体 体现和实现.
- 属性:就是用来描述事物外在特征的(名词)也叫成员变量, 和以前定义变量类似, 现在先写到 类中, 方法外, 而且成员变量有默认值.
- 行为:就是用来指事物能够做什么(动词)也叫成员方法,,和以前定义方法类似, 先不写static.
类的实现
1.如何实现一个类?
public class 类名{
//属性:名词,也叫成员变量
//行为:动词,也叫成员方法
}
2.如何使用类中的成员?
类名 对象名 = new 类名();
然后通过 对象.的方式调用即可。
3.例如:
Student s = new Student(); //创建学生对象
s.study(); //学生在学习,即:调用Student#study()方法。
- 案例:学生类
- 用来描述手机的(属性, 行为),像这样的用来描述事物的类叫: 实体类, 也叫: JavaBean类, POJO类.
public class Student {
//属性(成员变量): 姓名, 年龄, 性别
String name; //姓名
int age; //年龄
String sex; //性别
//行为(成员方法): 学习, 吃饭, 睡觉
public void study() {
System.out.println("好好学习, 天天向上!");
}
public void eat() {
System.out.println("为了保持精力, 要按时吃饭.");
}
public void sleep() {
System.out.println("为了保持精力, 要按时睡觉.");
}
-
案例:学生类的测试类
-
概述: 所谓的使用类, 就是使用类中的成员(成员变量和成员方法)
格式: 1. 创建该类的对象. 类名 对象名 = new 类名(); 2. 通过 对象名. 的形式来使用类中的成员. 对象名.成员变量 对象名.成员方法(参数1, 参数2)
-
package com.itheima.demo01_quickstart;
//案例: 学生类的测试类
/*
概述: 所谓的使用类, 就是使用类中的成员(成员变量和成员方法)
格式:
1. 创建该类的对象.
类名 对象名 = new 类名();
2. 通过 对象名. 的形式来使用类中的成员.
对象名.成员变量
对象名.成员方法(参数1, 参数2)
*/
public class StudentTest {
public static void main(String[] args) {
//需求: 使用学生类中的成员.
//1. 创建学生类的对象.
Student s = new Student();
//2. 访问成员变量.
//String name = s.name; //把成员变量name的值, 赋值给局部变量name
System.out.println(s.name); //null
System.out.println(s.age); //0
System.out.println(s.sex); //null
System.out.println("------------------");
//3. 给成员变量赋值
s.name = "刘亦菲";
s.age = 33;
s.sex = "女";
//4. 打印成员变量值.
System.out.println(s.name); //刘亦菲
System.out.println(s.age); //33
System.out.println(s.sex); //女
System.out.println("------------------");
//5. 访问成员方法
s.study();
s.eat();
s.sleep();
}
}
- 案例: 定义手机类
package com.itheima.demo02_phone;
//案例: 定义手机类, 用来描述手机的(属性, 行为), 像这样的用来描述事物的类叫: 实体类, 也叫: JavaBean类, POJO类.
public class Phone {
// 属性: 也叫成员变量, 就是用来描述事物的外在特征的(即: 名词)
String brand; //品牌
int price; //价格
String color; //颜色
// 行为: 打电话(call), 发短信(sendMessage)
//打电话
public void call(String name) { //夯哥
System.out.println("给" + name + "打电话!...");
}
//发短信
public void sendMessage(String name) {
System.out.println("给" + name + "发短信!...");
}
}
- 手机类的测试类
package com.itheima.demo02_phone;
//案例: 手机类的测试类.
public class PhoneTest {
//main方法是程序的主入口, 所有的代码都是从这里开始执行的.
public static void main(String[] args) {
//1. 创建手机类的对象.
Phone p = new Phone();
//2. 设置成员变量值.
p.brand = "华为";
p.price = -5999;
p.color = "黑色";
//3. 打印成员变量值.
System.out.println(p.brand);
System.out.println(p.price);
System.out.println(p.color);
//4. 调用成员方法
p.call("夯哥");
p.sendMessage("夯哥");
}
}
成员变量和局部变量
概述和区别
-
概述:
成员变量: 定义在类中, 方法外的变量.
局部变量: 定义在方法中, 或者方法声明上的变量. -
区别:
- 1)定义位置不同.
成员变量:定义在类中, 方法外的变量.
局部变量:定义在方法中, 或者方法的形参上的变量. - 2)在内存中的存储位置不同.
成员变量: 存储在堆内存.
局部变量: 存储在栈内存. - 3)生命周期不同.
成员变量: 随着对象的创建而存在, 随着对象的消失而消失.
局部变量: 随着方法的调用而存在, 随着方法的调用完毕而消失. - 4)初始化值不同.
成员变量:有默认值.
例如:
String: null
int: 0
double: 0.0
局部变量:没有默认值, 必须先定义, 再赋值, 然后才能使用.
- 1)定义位置不同.
-
案例: 演示成员变量和局部变量的区别
package com.itheima.demo03_variable;
//案例: 演示成员变量和局部变量的区别.
public class VariableDemo {
//成员变量
int x;
public void show() {
//局部变量
//int y; //这样写会报错, 因为局部变量没有默认值.
int y = 20;
System.out.println(x); //10
System.out.println(y); //20
}
}
- 案例: 测试类, 用来演示局部变量和成员变量不同的
package com.itheima.demo03_variable;
//案例: 测试类, 用来演示局部变量和成员变量不同的.
public class VariableDemoTest {
public static void main(String[] args) {
//需求: 调用VariableDemo#show()方法.
//1. 创建VariableDemo类的对象.
VariableDemo vd = new VariableDemo();
//2. 调用show()方法.
vd.show();
}
}
封装
private关键字
-
概述:
它是一个访问权限修饰符, 表示私有的意思,可以修饰类的成员(成员变量和成员方法). -
特点:
被它修饰的内容, 只能在本类中直接使用. -
结论:
- 封装就是隐藏对象的属性和实现细节, 仅对外提供一个公共的访问方式.
-
应用场景:
1.实际开发中,所有的属性都要私有化,即:用private修饰。
2.实际开发中,我们也会把那些不需要外界直接访问的内容也会用private修饰。 -
定义学生类 (JavaBean类, 实体类, POJO类)
package com.itheima.demo04_student;
//定义学生类(JavaBean类, 实体类, POJO类)
public class Student {
//属性, 也叫成员变量, 即: 名词.
String name; //姓名.
private int age; //年龄
//针对于被private修饰的变量, 需要对外提供一个公共的访问方式.
//设置变量age的值.
public void setAge(int a) {
//针对于用户录入的值a, 我们可以判断
if (a >= 0 && a <= 200) {
//合法年龄, 就设置.
age = a;
}
}
//获取变量age的值.
public int getAge() {
return age;
}
//行为, 也叫成员方法, 即: 动词.
public void show() {
System.out.println(name + "..." + age);
}
}
- 案例: 学生类的测试类
package com.itheima.demo04_student;
//案例: 学生类的测试类
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生类的对象.
Student s = new Student();
//2. 设置成员变量值.
s.name = "刘亦菲";
/*
下述的代码, 用户是可以直接访问 age成员变量的, 这样做比较危险,
因为用户可以给该变量设置一些非法值, 这样我们的程序就有可能出问题,
针对于这种情况, 我们可以通过 private 关键字解决.
当我们给类的成员变量加上private修饰后, 我们发现一个新问题:
外界居然无法直接访问 被private修饰的变量了, 该如何解决呢?
只需要对外提供一个公共的访问方式即可, 让可以可以操作变量.
1. 可以设置变量的值.
2. 可以获取变量的值.
*/
//s.age = -33;
//以下为: 采用封装后的代码.
//设置年龄
s.setAge(-33);
//获取年龄
System.out.println(s.getAge());
//3. 打印成员变量值.
/*System.out.println(s.name);
System.out.println(s.age);*/
//System.out.println(s); //打印地址值.
s.show();
}
}
- 定义学生类, 用来演示"标准"的类的定义
package com.itheima.demo05_student;
//定义学生类, 用来演示"标准"的类的定义
/*
实际开发中, 如非必要, 成员变量全部用private修饰, 其他全部用public修饰.
*/
public class Student {
//属性, 成员变量, 全部用private修饰.
private String name; //姓名
private int age; //年龄
//getXxx(), setXxx()
//设置姓名
public void setName(String n){
name = n;
}
//获取姓名
public String getName() {
return name;
}
//设置年龄
public void setAge(int a) {
//这里可以做判断, 但是不用做, 因为数据从前端传过来的时候
//就是已经校验过的, 合法的数据.
age = a;
}
//获取年龄
public int getAge() {
return age;
}
//行为, 成员方法, 全部用public修饰.
//学习
public void study() {
System.out.println("键盘敲烂, 月薪过万!");
}
//吃饭
public void sleep() {
System.out.println("为了保持精力,要按时休息!");
}
}
- 案例: 学生类的测试类, 用来演示"标准"的类的定义
package com.itheima.demo05_student;
//案例: 学生类的测试类, 用来演示"标准"的类的定义
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生类的对象.
Student s = new Student();
//2. 设置属性.
s.setName("刘亦菲");
s.setAge(-33);
//3. 打印属性.
System.out.println(s.getName());
System.out.println(s.getAge());
//4. 调用方法.
s.study();
s.sleep();
}
}
this关键字:
-
概述:
代表本类当前对象的引用, 即: 谁调用, this就代表谁. -
作用:
用来解决局部变量和成员变量重名问题的. -
记忆: 使用变量的原则
使用变量遵循"就近原则", 局部位置有就使用, 没有就去本类的成员位置找,
有就使用, 本类没有还会去父类中找. -
学生类, 用来演示this关键字的
package com.itheima.demo06_this;
//学生类, 用来演示this关键字的.
public class Student {
//成员变量
int x = 10;
public void method() {
//局部变量
int x = 20;
System.out.println(this.x); //10
System.out.println(x); //20
}
}
- 学生类的测试类
package com.itheima.demo06_this;
//学生类的测试类
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生类的对象.
Student s = new Student();
//2. 调用Student#method()
s.method(); //this.x -> s.x 10, 20
System.out.println("-----------");
//3. 升级版演示: 谁调用, this就代表谁.
Student s2 = new Student();
s2.x = 100;
s2.method(); //this.x -> s2.x 100, 20
}
}
- 定义学生类, 用来演示"标准版的JavaBean类的编写
package com.itheima.demo07_student;
//定义学生类, 用来演示"标准版的JavaBean类的编写"
public class Student {
//属性, 成员变量, 全部私有.
private String name; //姓名
private int age; //年龄
//getXxx(), setXxx()
//设置姓名
public void setName(String name) {
this.name = name;
}
//获取姓名
public String getName() {
//return this.name; //就近原则.
return name; //就近原则, 局部没有, 就去本类的成员位置找.
}
//设置年龄
public void setAge(int age) {
this.age = age;
}
//获取年龄
public int getAge() {
return age;
}
//行为, 成员方法
public void study() {
System.out.println("键盘敲烂, 月薪过万!");
}
public void sleep() {
System.out.println("为了保持精力学习, 一定要保证充足的睡眠!");
}
}
- 案例: 学生类的测试类
package com.itheima.demo07_student;
//案例: 学生类的测试类
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生对象.
Student s = new Student();
//2. 设置属性.
s.setName("刘亦菲");
s.setAge(33);
//3. 打印属性.
System.out.println(s.getName());
System.out.println(s.getAge());
//4. 调用方法.
s.study();
s.sleep();
}
}
构造方法
-
作用:
就是用来创建对象的, 捎带着可以给对象的各个属性赋值.
大白话解释:就是用来实现, 创建对象的同时, 给该对象的各个成员变量赋值. -
特点:
-
构造方法名必须和类名完全一致, 包括大小写.
-
构造方法没有具体的返回值,返回值的类型、void都不能写.
-
构造方法没有具体的返回值, 但是可以写return;因为return是用来结束方法的, 构造方法也算方法, 所以可以有return.
-
构造方法可以重载.
-
实际开发中,如非必要,建议都要写:空参,全参构造。
-
-
注意事项
- 如果我们不给构造方法, 系统会默认给一个空参构造.
- 如果我们给了构造方法, 系统就不给了.
package cn.itcast.javase.面向对象;
public class Student {
private String name;
private int age;
public Student(){
System.out.println("空参");
return;
}
public Student(String name,int age){
this.age = age;
this.name = name;
}
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;
}
}
- 学生类的测试类
- setXxx( ): 用来修改指定对象的指定属性值的, 不会创建新对象.
- 构造方法:
用来创建对象的, 捎带着可以给对象的各个属性赋值,
重复调用构造方法, 会创建新对象.
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
Student s2 = new Student();
s2.setName("刘亦菲");
s2.setAge(33);
System.out.println(s2.getName() + " " + s2.getAge()); //刘亦菲 33
Student s3 = new Student("李四", 23); //调用构造方法并给值
System.out.println(s3.getName() + " " + s3.getAge()); //李四 23
}
}
标准的类的定义和使用
标准类的定义格式
public class 类名{
//属性, 全部私有
//构造方法, 空参, 全参.
//getXxx(), setXxx()
//行为, 成员方法.
}
- 定义一个标准的学生类, 即: JavaBean类, 也叫POJO类.
package com.itheima.demo09_student;
//定义一个标准的学生类, 即: JavaBean类, 也叫POJO类.
public class Student {
//属性, 全部私有
private String name; //姓名
private int age; //年龄
//构造方法, 空参, 全参.
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//getXxx(), setXxx()
//关于姓名
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//关于年龄
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
//行为, 成员方法.
public void study() {
System.out.println("键盘敲烂, 月薪过万!");
}
}
- 学生类的测试类
package com.itheima.demo09_student;
//案例: 学生类的测试类
public class StudentTest {
public static void main(String[] args) {
//1. 测试空参构造.
//1.1 创建对象.
Student s = new Student();
//1.2 设置属性值.
s.setName("刘亦菲");
s.setAge(33);
//1.3 打印属性值.
System.out.println("姓名: " + s.getName());
System.out.println("年龄: " + s.getAge());
//1.4 调用方法
s.study();
System.out.println("-------------------");
//2. 测试全参构造.
//2.1 创建对象, 直接给对象的各个属性赋值.
Student s2 = new Student("赵丽颖", 31);
//2.2 打印属性值.
System.out.println("姓名: " + s2.getName());
System.out.println("年龄: " + s2.getAge());
//2.3 调用方法
s2.study();
}
}
继承
继承概述与案例
-
概述:
- 实际开发中, 我们发现好多类中的部分内容是相似的, 每次写很麻烦, 于是我们就想着能不能优化这个问题。
- 针对于这种情况, 我们可以把这些相似的内容抽取出来, 然后单独的放到一个类中, 然后让 多个类(子类)和这个类(父类)产生关系, 这个关系就叫 继承。
- Java继承用中,继承用关键字 extends 表示。
-
格式
-
public class 子类 extends 父类 { }
-
好处:
- 提高了代码的复用性.
- 提高了代码的可维护性.
- 让类与类之间产生关系, 是多态的前提.
-
弊端:让类与类之间产生关系, 也就让类的耦合性增强了.
开发原则: 高内聚, 低耦合.
大白话解释:
内聚: 指的是类自己独立完成某些事情的能力.
耦合: 指的是类与类之间的关系.
接口(干爹)的出现降低了类与类之间的耦合性
- 人类, 在这里充当的角色是父类.
public class Person { //ctrl + 字母H: 查看类的继承关系树.
//属性
private String name;
private int age;
//构造方法, 如果我们不写, 系统会默认加一个: 空参构造.
//getXxx(), setXxx()
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("人要吃饭");
}
public void sleep() {
System.out.println("人要睡觉");
}
}
- 老师类
package com.itheima.demo02_extends;
//案例: 老师类
public class Teacher extends Person {
//老师类独有的功能: 讲课
public void teach() {
System.out.println("老师要讲课!");
}
}
- 学生类
package com.itheima.demo02_extends;
//案例: 学生类
public class Student extends Person {
//学生类独有的功能: 学习
public void study() {
System.out.println("好好学习, 天天向上!");
}
}
- 测试类
package com.itheima.demo02_extends;
//测试类
public class PersonTest {
public static void main(String[] args) {
//1. 测试老师类
Teacher t = new Teacher();
//属性
//从Person类继承.
t.setName("刘亦菲");
t.setAge(33);
System.out.println(t.getName() + "..." + t.getAge());
//方法
t.eat(); //从Person类继承.
t.sleep(); //从Person类继承.
t.teach(); //本类的独有功能.
//2. 测试学生类, 留给你自己写.
Student s = new Student();
s.setName("李四");
s.setAge(32);
System.out.println(s.getName() + " " + s.getAge());
s.study();
s.teach();
s.eat();
s.sleep();
}
}
Java中的继承关系特点
结论:
- 在Java中, 类与类之间只能单继承, 不能多继承.
- 在Java中, 类与类之间可以多层继承.
- 案例:
// 爷爷类
public class GrandFather {
public void grandFatherSay() {
System.out.println("爷爷都是从孙子过来的. ");
}
}
// 爸爸类
public class Father extends GrandFather {
public void fatherSay() {
System.out.println("爸爸都是从儿子过来的");
}
}
// 儿子类
public class Son extends Father {
public void sonSay() {
System.out.println("son...");
}
}
// 儿子测试类
public class SonTest {
public static void main(String[] args) {
//1. 创建Son类对象.
Son s = new Son();
//2. 调用Son类中成员方法
s.sonSay(); //Son类本身的方法.
s.fatherSay(); //从Father类中继承过来的.
s.grandFatherSay(); //从GrandFather类中继承过来的.
}
}
继承关系中的成员特点
成员变量特点
“就近原则”
使用变量遵循"就近原则", 局部位置有就使用, 没有就去本类的成员位置找,
有就使用, 没有就去父类的成员位置找, 有就使用, 没有就报错.
这里不考虑父类的父类这种情况,因为会一直找下去,直至Object类,如果还没有,就报错。
super关键字简介:
概述:
它表示当前对象的父类的内存空间标识,可以理解为:父类对象的引用,但是严格意义上它不是。
super和this的区别
1.本质不同
this: 代表本类当前对象的引用。
super: 代表本类当前对象的父类的内存空间标识
2.用法不同
this.成员变量 调用的本类的变量
super.成员变量 调用的是父类的成员变量
this(值1,值2....) 访问的是本类的构造方法
super(值1,值2...) 访问的是父类的构造方法
this.成员方法名(值1,值2.....) 访问的是本类的成员方法
super.成员方法名(值1,值2.....) 访问的是父类的成员方法
案例:
//父类
public class Father {
int age = 30; //父类的成员变量
}
//子类
public class Son extends Father{
int age = 20; //本类的成员变量.
public void show() {
int age = 10; //局部变量
System.out.println(age); //10
System.out.println(this.age); //20
System.out.println(super.age); //30
}
}
//测试类
public class FatherTest {
public static void main(String[] args) {
//1. 创建Son类对象.
Son s = new Son();
//2. 调用show()方法
s.show();
}
}
构造方法的特点
- 结论
1. 子类中所有的构造方法的第一行默认都有一个 super() 去访问父类的空参构造,为什么这样设计?
用于子类对象访问父类数据前, 对父类数据进行初始化.
大白话解释: 即每一个构造方法的第一行都有一个: super()
2. 为什么默认访问的是空参,而不是带参或者全参构造?
所有的类都直接或者间接继承自Object类, 它里面只有一个空参构造,Object类是所有类的父类.
3. 父类没有空参构造怎么办?
方式1:可以通过 super(参数)的形式访问父类的带参构造.
方式2:也可以this(参数)的形式访问本类的其他构造.
但是这样做比较麻烦, 所以我们建议, 永远手动给出空参构造.
4.实际开发中的做法:
子类的空参构造 -> 父类的空参构造
子类的全参构造 -> 父类的全参构造
- 父类
package cn.itcast.javase.继承;
public class Father {
// public Father() {
super(); //Object类的
// System.out.println("Father类的 空参构造 1");
// }
public Father(String name,int age){
super(); //Object类的
System.out.println("Father类的 全参构造 2");
}
}
- 子类
package cn.itcast.javase.继承;
public class Son extends Father {
public Son() {
// super(); //初始化父类成员的
super("王五", 23);
System.out.println("Son类的 空参构造 3");
}
public Son(String name, int age) {
// super(); //初始化父类成员的
// super(name, age);
this();
System.out.println("Son类的 全参构造 4");
}
}
- 测试类
package cn.itcast.javase.继承;
/**
* @author YULIANG
*/
public class FatherTest {
public static void main(String[] args) {
Son son = new Son();
System.out.println("------------");
Son s2 = new Son("李四", 12);
}
}
成员方法的特点
- 特点:
- 继承关系中, 调用成员方法时, 也遵循"就近原则", 本类中有, 就直接调用,
本类中没有, 就去父类查找, 有就调用, 没有就报错.
- 继承关系中, 调用成员方法时, 也遵循"就近原则", 本类中有, 就直接调用,
//父类
public class Father {
public void method(){
System.out.println("Father method ...");
}
}
//子类
public class Son extends Father {
public void method() {
System.out.println("Son method...");
}
}
//测试类
public class FatherTest {
public static void main(String[] args) {
Son son = new Son();
son.method();
}
}
方法重写
-
概述
- 子类出现和父类一模一样的方法时, 称为:方法重写.
- 方法重写要求返回值的数据类型也必须一致.
-
应用场景
- 当子类需要沿袭父类的功能,但是功能主体又有自己额外需求的时候,就可以考虑使用方法重写了。
- 这样沿袭了父类的功能,也加入了自己独有的功能。
-
注意事项:
-
- 子类重写父类方法时, 要用 @Override 注解修饰.
-
- 父类的私有方法,子类无法重写.
-
- 进行方法重写时,子类方法的访问权限 不能低于 父类方法的访问权限。
public > protected > 默认 > private
-
-
父类
public class Phone {
public void call(String name) {
System.out.println("给" + name + "打电话");
}
}
- 子类
public class NewPhone extends Phone {
//重写Phone类的call()方法。
@Override
public void call(String name) {
//沿袭父类的功能
super.call(name);
//加入自己独有的需求
System.out.println("给" + name + "发彩信");
}
}
- 测试类
public class PhoneTest {
public static void main(String[] args) {
NewPhone p = new NewPhone();
p.call("李四");
}
}
继承案例
- 人类
package com.itheima.demo08_exercise;
//父类, 里边定义的是整个继承体系的: 共性内容.
public class Person {
//属性.
private String name;
private int age;
//构造方法.
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//getXxx(), setXxx()
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.demo08_exercise;
//老师类
public class Teacher extends Person{
//属性.
//构造方法, 子类的空参访问父类的空参, 子类的全参访问父类的全参.
public Teacher() {
super();
}
public Teacher(String name, int age) {
super(name, age);
}
//getXxx(), setXxx(), 从父类继承.
//行为, 这里可以定义本类独有的行为.
//重写父类的eat()方法
@Override
public void eat() {
System.out.println("老师喝牛肉汤!...");
}
//加入老师类独有的功能
public void teach() {
System.out.println("老师要激情高涨的讲课, 帮助学员实现高薪就业!...");
}
}
- 学生类
package com.itheima.demo08_exercise;
//学生类
public class Student extends Person{
//属性.
//构造方法, 子类的空参访问父类的空参, 子类的全参访问父类的全参.
public Student() {
super();
}
public Student(String name, int age) {
super(name, age);
}
//getXxx(), setXxx(), 从父类继承.
//行为, 这里可以定义本类独有的行为.
//重写父类的eat()方法
@Override
public void eat() {
System.out.println("学生吃牛肉!...");
}
//加入学生类独有的功能
public void study() {
System.out.println("键盘敲烂, 月薪过万!...");
}
}
- 测试类
package com.itheima.demo08_exercise;
public class PersonTest {
public static void main(String[] args) {
//1. 测试老师类, 空参构造.
//1.1 创建对象.
Teacher t1 = new Teacher();
//1.2 给属性赋值.
t1.setName("张三");
t1.setAge(20);
//1.3 打印属性值.
System.out.println(t1.getName() + " " + t1.getAge());
//1.4 调用方法
t1.eat();
t1.teach();
System.out.println("-------------------------");
//2. 测试老师类, 全参构造.
//2.1 创建对象, 并给属性赋值.
Teacher t2 = new Teacher("李四", 23);
//2.2 打印属性值.
System.out.println(t2.getName() + " " + t2.getAge());
//2.3 调用方法
t2.eat();
t2.teach();
System.out.println("-------------------------");
//1. 测试学生类, 空参构造.
//1.1 创建对象.
Student s1 = new Student();
//1.2 给属性赋值.
s1.setName("王五");
s1.setAge(23);
//1.3 打印属性值.
System.out.println(s1.getName() + " " + s1.getAge());
//1.4 调用方法
s1.eat();
s1.study();
s1.teach();
System.out.println("-------------------------");
//2. 测试学生类, 全参构造.
//2.1 创建对象, 并给属性赋值.
Student s2 = new Student("赵六", 42);
//2.2 打印属性值.
System.out.println(s2.getName() + " " + s2.getAge());
//2.3 调用方法
s2.eat();
s2.study();
s2.teach();
}
}
多态
概述
- 同一个事物(或者对象)在不同时刻表现出来的不同状态, 形态.
前提条件:
-
- 要有继承(或者实现)关系.
-
- 要有方法重写,不然多态毫无意义.
-
- 要有父类引用(或者父接口)指向子类对象.
成员访问特点
-
**成员变量:**编译看左,运行看左
- 编译期间检查左边的类型****是否有该变量,有则编译通过,没有则编译报错。
- 运行期间具体用的是左边类中的该变量。
-
**成员方法:**编译看左,运行看右
- 编译期间检查左边的类型是否有该方法,有则编译通过,没有则编译报错。
- 运行期间具体用的是右边类中的 该方法。
总结:
只有成员方法是编译看左,运行看右,其他都是编译运行看左,
因为只有成员方法有方法重写。
- 案例
//父类
public class Animal {
int age = 20;
public void eat() {
System.out.println("动物要吃饭");
}
}
//子类
public class Cat extends Animal {
int age = 30;
@Override
public void eat() {
System.out.println("猫要吃鱼");
}
}
//测试类
public class AnimalTest {
public static void main(String[] args) {
//猫是猫,这个是 自己(本类)指向自己(本类的对象),不是多态
Cat c = new Cat();
c.eat();
System.out.println("-----------------");
//Cat c2 = new Animal(); //动物是猫,这句话是错误的
//猫是动物,这个才是父类引用指向子类对象,叫:多态
Animal an = new Cat();
//多态访问成员变量:编译看左,运行看左
System.out.println(an.age);
//多态访问成员方法:编译看左,运行看右
an.eat();
}
}
多态的好处与弊端
-
好处:提高了代码的扩展性.
-
弊端: 父类引用不能直接使用子类的特有成员.
如何解决上述的问题?
通过向下转型解决,
即: 多态形式的创建对象的操作 -> 转变成 普通的创建对象的操作.
示例:
Animal an = new Cat(); 向上转型,猫 -> 动物 double d = 10; 隐式类型转换
Cat c = (Cat)an; 向下转型,动物 -> 猫 int a = (int)d; 强制类型转换
演示向上转型和向下转型
//父类, 动物类
public class Animal {
public void eat() {
System.out.println("动物要吃");
}
}
//子类, 猫类
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼!");
}
public void catchMouse() {
System.out.println("猫会抓老鼠!....");
}
}
//动物类案例测试类.
public class AnimalTest {
public static void main(String[] args) {
//1 多态形式的创建猫类对象
Animal an = new Cat();
//2. 演示多态的弊端.
an.eat(); //编译看左 运行看右.
//3. 升级功能: 尝试通过多态版的 猫类对象, 调用猫类中独有的 catchMouse()功能.
//an.catchMouse(); //这样做不行, 因为an是Animal动物类的引用, 我们不能说 动物会抓老鼠
//4. 通过向下转型, 把 多态版的 猫类对象 -> Cat类型的猫类对象.
Cat c = (Cat)an; //引用类型的: 向下转型, 即: 大 -> 小.
c.catchMouse();
//int a = (int)10.3; 基本类型的: 强制类型转换, 即: 大 -> 小.
}
}
猫狗案例(多态版)
- 动物类
//父类, 动物类
public 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 eat() {
System.out.println("动物要吃饭!");
}
}
- 狗类
//子类: 狗类
public class Dog extends Animal{
//构造方法
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
//成员方法
//重写Animal#eat()
@Override
public void eat() {
System.out.println("狗吃肉");
}
//定义自己独有的行为
public void lookHome() {
System.out.println("狗会看家!");
}
}
- 猫类
//子类: 猫类
public class Cat extends Animal{
//构造方法
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
//成员方法
//重写Animal#eat()
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//定义自己独有的行为
public void catchMouse() {
System.out.println("猫会抓老鼠");
}
}
- 测试类
//测试类:
public class AnimalTest {
public static void main(String[] args) {
//1. 通过多态的方式测试 狗类的空参对象.
//1.1 创建对象.
Animal an = new Dog();
//1.2 设置属性
an.setAge(23);
an.setName("旺财");
//1.3 打印属性
System.out.println(an.getAge() + " " + an.getName());
//1.4 调用方法
an.eat();
/* 1.5 调用狗类的独有的方法, 需要向下转型, 因为多态的弊端是:
父类引用不能直接使用子类的特有成员.*/
Dog an2 = (Dog) an;
an2.lookHome();
System.out.println("---------------------------");
//2. 通过多态的方式测试 狗类的全参对象.
//2.1 创建对象, 并设置属性
Dog d1 = new Dog("哮天犬", 450);
//2.2 打印属性
System.out.println(d1.getAge() + " " + d1.getName());
//2.3 调用方法
d1.eat();
//2.4 调用狗类的独有的方法.
d1.lookHome();
}
}
多态在实际开发中的应用
- 多态在生产环境具体的用法如下
- 父类型可以作为方法的形参类型,这样可以接收其任意的子类对象,根据调用成员方法的规则(编译看左,运行看右)
- 实现:传入什么类型的子类对象,就调用其对应的的成员方法
//父类
public class Animal {
int age = 30;
public void eat() {
System.out.println("动物要吃饭!");
}
}
//子类
public class Dog extends Animal {
int age = 25;
@Override
public void eat() {
System.out.println("狗吃骨头");
}
//自己独有的行为
public void lookHome() {
System.out.println("狗会看家");
}
}
//子类
public class Cat extends Animal {
int age = 20;
@Override
public void eat(){
System.out.println("猫吃鱼!");
}
public void catchMouse(){
System.out.println("猫会抓老鼠");
}
}
//测试类
public class Demo02 {
public static void main(String[] args) {
Cat c = new Cat();
printAnimal(c);
Dog d = new Dog();
printAnimal(d);
}
public static void printAnimal(Animal an) {//Animal an = new Dog();
//根据多态访问成员方法的规则: 编译看左, 运行看右.
an.eat();
}
}
instanceof关键字
-
概述:
- 它是一个关键字,用来判断 指定的引用(对象) 是否是 某一个类型的对象.
-
格式:
- 引用(对象) instanceof 数据类型 //判断
-
例如
-
Cat c = new Cat(); c instanceof Cat -> true c instanceof Dog -> false
-
案例:
//测试类
public class Demo02 {
public static void main(String[] args) {
Cat c = new Cat();
printAnimal(c);
Dog d = new Dog();
printAnimal(d);
}
public static void printAnimal(Animal an) {
an.eat();
//判断传入的是否是猫类
if (an instanceof Cat){
//走到这里, 说明是猫类对象, 向下转型, 然后调用方法即可.
Cat c = (Cat)an;
c.catchMouse();
}else if (an instanceof Dog){
//走到这里, 说明是狗类对象, 向下转型, 然后调用方法即可.
Dog d = (Dog)an;
d.lookHome();
}
/*
虽然我们用instanceof关键字解决了判断an是哪种具体的子类对象这个问题,但是又带来一个新的问题。
即:当需求变化的时候(又有子类加入的时候),我们还需要修改源码,和十大黄金开发原则之
“对修改关闭,对扩展开放”相违背,即:需求变化的时候,建议我们加东西,而不是改目前的源码。
可以通过 抽象工厂方法设计模式解决,即:每一种子类,都创建与其对应的工厂类。需求变化的时候,我们只要加代码即可,不需要修改源码。*/
}
}
final关键字
- 概述:final是一个关键字, 表示最终的意思, 可以修饰类, 成员变量, 成员方法.
- 修饰的类: 表示最终类,不能被别的类继承, 但是可以继承其他的类.
- 修饰的变量: 表示常量, 只能被赋值一次.
- 修饰的方法: 表示最终方法,子类可以继承,但不能被子类重写.
//父类
//public final class Father extends Object(){ Father类不能被继承。
public class Father {
public final void method(){
System.out.println("绝密文件,不能动");
}
}
//子类
public class Son extends Father{
/* @Override
public void method() {
System.out.println("删除文件");
}*/
}
//测试类
public class FatherTest {
public static void main(String[] args) {
final int a = 10;
//a = 20; //报错,常量只能赋值一次,值不能修改
System.out.println(a);
Son s = new Son();
s.method();
}
}
演示自定义常量的细节
-
请问怎么理解"final修饰的变量是一个常量, 其值只能赋值一次这个问题" ?
- final修饰的变量如果是基本类型,则:数值不能改变。
- final修饰的变量如果是引用类型,则:地址值不能改变,里面的属性值可以变化。
-
final修饰的变量如果是成员变量,则必须手动赋值,不能用默认值为什么?
- 成员变量默认都是有默认值的
- final修饰的变量只能赋值一次,不能重复赋值
- 如果final修饰的变量采用了变量的默认值,此时用户就无法手动再修改值了,需要用户手动给值,即:final修饰的成员变量没有默认值。
public class Father {
}
//子类
public class Son extends Father{
int age;
// final int num; 报错
final int num = 0; //必须手动给值
}
//测试类
public class Demo02 {
public static void main(String[] args) {
//1. 演示 如果修饰的基本类型的常量: 是数值不能发生变量.
final int a = 10;
//a = 20; //这样写会报错.
System.out.println(a);
System.out.println("-----------------------");
//2. 演示: 如果修饰的引用类型的常量: 地址值不能发生变化,
// 但是该对象的属性值可以发生变化.
final Son s = new Son();
s.age = 18;
System.out.println(s.age); //18
//3.演示final修饰的变量如果是成员变量,则必须手动赋值,不能用默认值
System.out.println(s.num); //20
}
}
static关键字
- 概述
- 它是一个关键字, 表示静态的意思, 可以修饰成员变量和成员方法.
- 特点
- 随着类的加载而加载.
- 优先于对象存在.
- 被static修饰的内容, 能被该类下所有的对象所共享.
- 静态内容可以被 类名. 的形式直接调用,也可以被 对象名. 的形式调用,推荐使用前者。
//学生类
public class Student {
String name;
int age;
static String graduateFrom;
public void show() {
System.out.println(name + "..." + age + "..." + graduateFrom);
}
}
//测试类
public class StudentTest {
public static void main(String[] args) {
//类名. 的形式调用
Student.graduateFrom = "武软";
System.out.println(Student.graduateFrom);
Student s = new Student();
s.age = 23;
s.name = "李四";
s.show();
System.out.println(s.age + " " + s.name);
Student s3 = new Student();
s3.name = "高圆圆";
s3.age = 35;
Student.graduateFrom = "传智学院";
s3.show();
}
}
静态方法的注意事项
- 判断是否使用静态的最大的依据是:看该成员是否被该类下所有的对象所共享,如果是,就可以虑使用静态。
- 静态只能访问静态,即:静态方法只能访问 静态方法和静态变量。
- 因为静态是优先于非静态内容存在的,先进内存的不能访问后进内存的。
- 非静态方法可以访问所有成员(非静态变量 和 方法, 静态变量 和 方法)
- 在静态方法中, 是没有this, super关键字的。因为它们只有创建对象才会有,而静态是优先于对象存在的
- 实际开发中,static 一般和 public 、final 相结合使用。
总结:先进内存的不能访问后进内存的。
//学生类
public class Student {
String name = "刘亦菲"; //非静态成员变量
static int age = 33; //静态的成员变量
public void show1() {
System.out.println(name);
System.out.println(age);
//this.show2(); 标准写法
show2();
//Student.show3(); 标准写法
show3(); //因为是访问本类的静态成员方法, 所以可以省略类名不写.
show4();
System.out.println("show1方法 非静态方法");
}
public void show2() {
System.out.println("show2方法 非静态方法");
}
public static void show3() {
//System.out.println(name); //非静态成员变量
System.out.println(age); //静态成员变量
//this.show2(); //非静态方法
Student.show4(); //静态方法
System.out.println("show3方法 静态方法");
}
public static void show4() {
System.out.println("show4方法 静态方法");
}
}
//测试类
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
//s.show1();
//结论: 非静态方法可以访问所有成员(非静态变量和方法, 静态变量和方法)
//s.show3(); 这样写不报错, 只是不推荐.
Student.show3(); //静态方法只能访问静态成员
}
}
抽象类
概述:
-
- 没有方法体的方法, 叫抽象方法, 用abstract修饰.
-
- 有抽象方法的类一定是抽象类, 抽象类也用 abstract修饰.
特点:
-
- 抽象类和抽象方法都用abstract关键字修饰.
-
- 抽象类中不一定有抽象方法, 但是有抽象方法的类一定是抽象类.
-
-
抽象类不能实例化.
那么抽象类如何实例化呢?
通过 抽象类多态 实现。
-
-
-
抽象类的子类:
如果是普通类, 则必须重写父类的所有的抽象方法.
如果是抽象类, 则可以不用重写父类的所有抽象方法.
-
//父类, 动物类
public abstract class Animal {
//1.类中有一个抽象方法eat(), 还有一个非抽象方法sleep().
public abstract void eat();
public void sleep() {
System.out.println("动物要睡!");
}
}
//子类, 猫类
//抽象类的子类如果是抽象类, 则可以不用重写父类的所有抽象方法.
//public abstract class Cat extends Animal{
//抽象类的子类如果是普通类, 则必须重写父类的所有的抽象方法.
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼!");
}
}
//测试类
public class AnimalTest {
public static void main(String[] args) {
//1. 演示: 抽象类不能实例化.
//Animal an = new Animal(); 这样写会报错.
//2. 抽象类可以通过创建其子类对象的形式, 来完成抽象类的初始化.
//抽象类多态
Animal an = new Cat();
}
}
抽象类的成员特点
-
**结论:**抽象类中可以有 变量, 常量, 构造方法, 非静态方法,静态方法,抽象方法。
就是比普通类多一种抽象方法,而且抽象方法还可以不写。
-
问题一:思考: 既然抽象类不能实例化, 那要构造方法有什么用?
-
用于子类对象访问父类数据前, 对父类数据进行初始化.
-
问题二:抽象类中的抽象方法和非抽象方法的作用是什么?
- 抽象方法:强制要求子类必须完成某些事情.
- 非抽象方法:让子类继承, 提高代码的复用性.
//父类, 表示老师类.
public abstract class Teacher {
//属性.
private String name;
private int age;
//构造方法
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
//getXxx(), setXxx()
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 teach();
}
//子类, 基础班老师
public class BasicTeacher extends Teacher{
//构造方法
public BasicTeacher() {
}
public BasicTeacher(String name, int age) {
super(name, age);
}
//重写Teacher#teach()
@Override
public void teach() {
System.out.println("基础班老师讲: JavaSE");
}
}
//子类, 就业班老师
public class WorkTeacher extends Teacher{
//构造方法
public WorkTeacher() {
}
public WorkTeacher(String name, int age) {
super(name, age);
}
//重写Teacher#teach()
@Override
public void teach() {
System.out.println("就业班老师讲: JavaEE, Linux, Hadoop...");
}
}
//测试类
public class TeacherTest {
public static void main(String[] args) {
//1. 测试基础班老师, 空参.
//抽象类多态版
Teacher b1 = new BasicTeacher();
b1.setAge(23);
b1.setName("李四");
System.out.println(b1.getAge() + " " + b1.getName());
b1.teach();
//2. 测试基础班老师, 全参.
Teacher b2 = new BasicTeacher("王五",45);
System.out.println(b2.getAge() + " " + b2.getName());
b2.teach();
}
}
接口
接口简介
- 概述
- 它是一种比抽象类更加抽象的存在,里面有且只能有常量和抽象方法(JDK1.8以前)。
- (jdk1.8以后)接口可以写 静态方法 和 默认方法,静态方法直接写,默认方法要用 default修饰。
- 特点
- 接口用interface关键字修饰.
- 类和接口之间是实现关系, 用implements关键字表示.
- 接口不能实例化.
- 那接口如何实例化呢?
- 可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态.
- 那接口如何实例化呢?
- 接口的子类:
- 如果是普通类, 则必须重写父接口中所有的抽象方法.
- 如果是抽象类, 则可以不用重写父接口中的抽象方法.
//猫类
public class Cat implements Jumpping {
@Override
public void jump() {
System.out.println("猫会跳高");
}
public void catchMouse() {
System.out.println("猫会抓老鼠");
}
}
//接口
public interface Jumpping {
public abstract void jump();
}
//测试类
public class CatTest {
public static void main(String[] args) {
Cat c = new Cat();
c.catchMouse();
c.jump(); //这个方法, 是Cat从Jumpping接口中实现过来的.
System.out.println("------------------");
//测试接口多态
Jumpping jm = new Cat();
jm.jump();
//向下转型
Cat c2 = (Cat)jm;
c2.catchMouse();
}
}
成员特点:
//即:接口中能写什么,不能写什么
- JDK1.8以前:
- 接口中有且只能有 常量 和 抽象方法,原因如下:
- 变量有默认修饰符:public、static、final
- 方法有默认修饰符:public、abstract
- 接口中有且只能有 常量 和 抽象方法,原因如下:
- JDK1.8以后:
- 接口可以写 静态方法 和 默认方法了,静态方法直接写,默认方法要用 default修饰。
public interface Myinterface {
//常量
//public static final int age = 20;
int age = 20; //简写格式
//抽象方法
//public abstract void eat();
void eat(); //简写格式
public static void show() {
System.out.println("静态方法,JDK1.8新特性");
}
public default void method() {
System.out.println("非静态方法(默认方法),JDK1.8新特性");
}
}
类与接口之间的关系
-
类与类:继承关系,只能单继承,不能多继承,但可以多层继承。
-
类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
-
接口与接口:继承关系,可以单继承,也可以多继承。
抽象类与接口的区别
-
1.成员特点的区别
- 抽象类:变量、常量、构造方法、静态方法,非静态方法、抽象方法。
- 接口:常量、静态方法、非静态方法(默认方法)、抽象方法。
-
2.关系特点的区别
-
类与类:继承关系,只能单继承,不能多继承,但可以多层继承。
-
类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
-
接口与接口:继承关系,可以单继承,也可以多继承。
-
-
3.设计理念的区别
- 抽象类:定义的是整个继承体系的 共性内容。
- 接口:定义的是整个个继承体系的 扩展内容。
运动员和教练案例
细节:
1.分析的时候 从具体到抽象
2.写代码的时候 从抽象到具体
-
需求:
- 已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).
- 他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.
- 乒乓球教练教如何发球, 篮球教练教如何运球和投篮.
- 乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.
- 为了出国交流, 跟乒乓球相关的人员都需要学习英语.
-
人类,抽象类
package com.itheima.demo11_coach;
//人类
public abstract class Person {
//属性:姓名,年龄
private String name;
private int age;
public Person() {
}
public Person(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 abstract void eat();
}
- 运动员类,抽象类,继承Person类。
package com.itheima.demo11_coach;
//运动员类,抽象类,继承Person类。
public abstract class Player extends Person {
//构造方法:子空 -> 父空, 子全 -> 父全
public Player() {
}
public Player(String name, int age) {
super(name, age);
}
//特有的行为
public abstract void study();
}
- 教练类,抽象类,继承Person类。
package com.itheima.demo11_coach;
//教练类,抽象类,继承Person类。
public abstract class Coach extends Person {
//构造方法:子空 -> 父空, 子全 -> 父全
public Coach() {
}
public Coach(String name, int age) {
super(name, age);
}
//特有的行为
public abstract void teach();
}
- 接口
package com.itheima.demo11_coach;
//接口,实现说英语的功能
public interface Speak {
//表示具有 说英语的功能,因为是接口,所以 public abstract 可以省略
// public abstract void speakEnglish();
void speakEnglish();
}
- 篮球运动员类,继承运动员类
package com.itheima.demo11_coach;
//篮球运动员类,继承运动员类
public class BasketballPlayer extends Player {
//构造方法:子空 -> 父空, 子全 -> 父全
public BasketballPlayer() {
}
public BasketballPlayer(String name, int age) {
super(name, age);
}
//重写Person#eat()
@Override
public void eat() {
System.out.println("篮球运动员吃 牛肉 喝羊奶");
}
//重写Player#study()
@Override
public void study() {
System.out.println("篮球运动员学习 运球 投篮");
}
}
- 乒乓球运动员类,继承运动员类,实现讲英语接口
package com.itheima.demo11_coach;
//乒乓球运动员类,继承运动员类,实现讲英语接口
public class PingPnagPlayer extends Player implements Speak{
//构造方法:子空 -> 父空, 子全 -> 父全
public PingPnagPlayer() {
}
public PingPnagPlayer(String name, int age) {
super(name, age);
}
//重写Person#eat()
@Override
public void eat() {
System.out.println("乒乓球运动员吃 羊肉 喝牛奶");
}
//重写Player#study()
@Override
public void study() {
System.out.println("乒乓球运动员练习 打乒乓球");
}
//重写Speak#speakEnglish()
@Override
public void speakEnglish() {
System.out.println("乒乓球运动员 学习讲英语");
}
}
- 乒乓球教练类,继承教练类,实现讲英语接口
package com.itheima.demo11_coach;
//乒乓球教练类,继承教练类,实现讲英语接口
public class PingPnagCoach extends Coach implements Speak {
//构造方法:子空 -> 父空, 子全 -> 父全
public PingPnagCoach() {
}
public PingPnagCoach(String name, int age) {
super(name, age);
}
//重写Person#eat()
@Override
public void eat() {
System.out.println("乒乓球运动员吃 羊肉 喝牛奶");
}
//重写Player#teach()
@Override
public void teach() {
System.out.println("乒乓球运动员练习 打乒乓球");
}
//重写Speak#speakEnglish()
@Override
public void speakEnglish() {
System.out.println("乒乓球运动员 学习讲英语");
}
}
- 篮球教练类,继承教练类
package com.itheima.demo11_coach;
//篮球教练类,继承教练类
public class BasketballCoach extends Coach {
//构造方法:子空 -> 父空, 子全 -> 父全
public BasketballCoach() {
}
public BasketballCoach(String name, int age) {
super(name, age);
}
//重写Person#eat()
@Override
public void eat() {
System.out.println("篮球教练吃 牛肉 喝羊奶");
}
//重写Coach#teach()
@Override
public void teach() {
System.out.println("篮球教练教 运球 投篮");
}
}
- 测试类
package com.itheima.demo11_coach;
public class Demo01 {
public static void main(String[] args) {
//测试乒乓球运动员
//抽象类多态
Person p1 = new PingPnagPlayer("马龙", 32);
Player p2 = new PingPnagPlayer("马龙", 32);
//接口多态
Speak s = new PingPnagPlayer("马龙", 32);
//标准写法 自己接收自己
PingPnagPlayer p3 = new PingPnagPlayer("马龙", 32);
System.out.println(p3.getName() + " " + p3.getAge());
p3.eat();
p3.study();
p3.speakEnglish();
System.out.println("----------------------------");
//测试乒乓球教练
//抽象类多态
Person pp1 = new PingPnagCoach("刘国梁", 45);
Coach pp2 = new PingPnagCoach("刘国梁", 45);
//接口多态
Speak s2 = new PingPnagCoach("刘国梁", 45);
//标准写法 自己接收自己
PingPnagCoach pp3 = new PingPnagCoach("刘国梁", 45);
System.out.println(pp3.getName() + " " + pp3.getAge());
pp3.eat();
pp3.teach();
pp3.speakEnglish();
}
}
包
概述:
-
包就是文件夹,在Java中用 package 关键字修饰,包名要全部小写, 多级包之间用 . 隔开,一般是公司的域名反写。
-
包就是对 类 做分类管理的
-
定义包的格式:
- package 包名1.包名2.包名3…; //包名根据需求可以写多级.
如何分包:
- 按照模块分: //了解
- com.itheima.student //包
- AddStudent.java //类
- DeleteStudent.java
- …
- com.itheima.teacher //包
- AddTeacher.java //类
- …
- com.itheima.student //包
- 按照操作分: //了解
- com.itheima.add //包
- AddStudent.java //类
- com.itheima.delete //包
- DeleteStudent.java //类
- com.itheima.add //包
- 实际开发分包法: //掌握
- com.itheima.controller //控制层,负责和浏览器交互的
- com.itheima.service //业务层,负责在controller 和 dao层之间协调业务的
- com.itheima.dao //数据访问层,负责和数据库交互的
- com.itheima.pojo //存储所有的JavaBean类
- com.itheima.utils //存储所有工具类
导包:
-
格式:
-
import 包名1.包名2.包名3.*; import 包名1.包名2.包名3.类名;
-
-
示例:
-
import java.util.Scanner; //只导入Scanner一个类, 更推荐 import java.util.*; //导入java.util包下所有的类和接口
-
注意事项:
- java.lang包下的类可以直接使用, 无需导入, 如果使用其他包下的类, 则必须先导包.
- 用public修饰的类叫: 公共类, 也叫顶级类, 在一个.java文件中, 顶级类只能有一个, 且必须和文件名一致.
package com.itheima.demo11_coach;
import java.util.Date;
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
//需求1:不用导包,如何调用指定的类呢? 了解。
//包名 + 类名 = 全类名
//java.util.Scanner sc = new Scanner(System.in);
//需求2:导包的思路
//Scanner sc = new Scanner(System.in);
//需求3:如果某两个不同的包下都有相同的类,此时就要用到 全类名写法了。
Date d1 = new Date();
//可以写全类名
java.sql.Date d2 = new java.sql.Date(10L);
}
}
**面试题:**在一个 .java文件中,package,import,class 三者之间有无顺序关系?
-
有,先写package,且一个.java文件中,package语句只能有一个。
-
再写 **import:**表示导包,它是写在package和class之间的,根据需求可以写多个。
-
最后写 **class:**表示修饰类,一个.java文件中可以写多个,但是建议只写一个。
-
细节
- 被public 修饰的类叫 公共类,也叫顶级类,在一个.java文件中,公共类只能有一个,且该类名必须和文件名一致。
四大权限修饰符
测试的结论图:
private | 默认 | protected | public | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一个包中的类(无关类或者子类) | √ | √ | √ | |
不同包下的类(子类) | √ | √ | ||
不同包下的类(无关类) | √ |
结论:
-
四大访问权限修饰符的范围从大到小分别是: public > protected > 默认 > private
-
在实际开发中, 如非必要, 一般都是属性全部用private修饰, 其它都用public修饰
-
四大访问权限修饰符各自的作用分别如下:
private: 强调的是给 自己 使用的
默认: 强调的是给 同包下的类 使用的
protected: 强调的是给 子类 使用的
public: 强调的是给 大家 使用的