Day09课堂笔记
标签(空格分隔): java基础
多态
- 多态:事物的多种形态
- 多态的前提条件是什么?
1,要有继承关系(extends关键字,让类和类之间产生关系)
2,要有方法重写(子父类中,出现一模一样的方法,返回值可以是子父类)
3,父类的引用指向了子类对象(父类引用 ? 父类类名 对象名(引用) 子类对象 : new 子类类名()) 书写在测试类中
举例:
class Father { //父类
String name;
public void show(){
System.out.println("父类的方法");
}
}
class Son extends Father{ //子类 这是第一个条件
//这是第二个条件
public void show(){
System.out.println("子类的方法");
}
}
class Test{
public static void main(String[] args){
//第三个条件
Father f = new Son();
}
}
多态中成员变量的访问特点是什么?
特点: 编译看左边 ,运行看左边 (左边:父类 右边:子类)
举例 Father f = new Son();
//这是多态,左边指的是父类 右边指的是子类
Son s = new Son();
//这不是多态
成员变量: 子父类中存在一模一样的成员变量的时候,这个时候去访问,就有编译看左边,运行看左边的特点
举例
class Father { //父类
String name = "父类";
}
class Son extends Father{ //子类 这是第一个条件
String name = "子类";
}
class Test{
public static void main(String[] args){
Father f = new Son();
System.out.println(f.name); //子父类中都有的成员变量
}
}
注意:这种写法开发中不用,只是说明有这个特点
多态中成员方法的访问特点
编译看左边,运行看右边
如果说,父类里面没有这个方法,而子类中有,这个时候如果我用父类的引用调用子类的对象的时候,会怎样? 报错
如果说,父类里面有这个方法,而子类并没有重写,这个时候用父类的引用调用这个方法,又会怎样?
如果没有方法重写,你如果达到了继承和父类引用指向子类对象,这也是多态一种,但是没有意义!
class Demo_Duotai {
public static void main(String[] args) {
//如果没有方法重写,这样就失去多态的意义
Father f = new Son();
//编译看左边,运行看右边
f.show();
Son s = new Son();
s.show();
}
}
class Father
{
public void show(){
System.out.println("父类的show方法");
}
}
class Son extends Father
{
//子类实际上是有,这个方法是从父类里面继承过来的
}
多态中静态成员方法的访问特点
- 编译看父类(左边),运行的时候也是看父类(左边)
多态中三个成员访问特点总结
区别 | 编译 | 运行 |
---|---|---|
成员变量 | 左边(父类) | 左边父类 |
普通成员方法 | 左边(父类) | 右边(子类) |
静态成员方法 | 左边(父类) | 左边 |
多态中父类的引用调用子类的特有方法出现编译的问题
思考:如何解决? 在使用的时候,父类的引用调用子类特有方法调用不了.
class Demo3_SuperMan {
public static void main(String[] args) {
//第三个条件 父类的引用指向子类对象 格式: 父类 对象名 = new 子类()
Person p = new SuperMan(); //父类引用指向子类对象,超人提升为了人
//父类引用指向子类对象就是向上转型
System.out.println(p.name);
p.谈生意();
//在我们使用子类的方法时候,发现了一个多态的问题,问题是子类的方法如果不是重写了父类的,父类里面没有这个方法,编译报错,没法通过
//这个时候怎么才能让这个编译通过呢? 解决方法?
p.fly(); //编译看左边(父类) ,问题是父类没有fly方法 编译报出以下错误:Demo3_SuperMan.java:8: 错误: 找不到符号
}
}
class Person { // 父类
String name = "John";
public void 谈生意() { //第二个条件 父类有谈生意方法
System.out.println("谈生意");
}
}
class SuperMan extends Person { //子类 多态:第一个条件 要有继承关系
String name = "superMan";
public void 谈生意() { //第二个条件满足 有方法重写
System.out.println("谈几个亿的大单子"); ///方法体可以不一样
}
public void fly() {
System.out.println("飞出去救人");
}
}
向上转型和向下转型
向上转型:父类的引用指向了子类对象 Father f = new Son();
向下转型的前提:必须要有向上转型
向下转型:格式 子类 对象名 = (子类类名)父类的引用Son s = (Son)f;
你会怎么想?
通过观察,我们发现了一个问题,其实来来去去无非调用的都是子类的方法,这个时候其实我们可以直接创建一个子类对象出来,直接调用方法,根本不需要用父类的引用指向子类对象,然后再用父类转型回子类调用子类特有方法.
思考?为什么要这么做?
多态的好处和弊端分别是什么?
多态的好处:提高代码扩展性
应用场景:在调用方法的时候,作为参数传递,这个时候我们可以节省书写代码演示好处
案例(非常非常非常重要)
class Demo4_Animal {
public static void main(String[] args) {
//需求: 让你调用猫类的吃方法 和狗类的吃方法
//需求改变:让你调用1000个猫的吃方法,和多个狗的吃方法
//解决方法:如果要调用同样的方法 这个时候,我想 能否帮我封装一个方法出来,我只要给你传对象,你就帮我调用方法
//需求升级:调用猪鸭鹅鸡羊牛.......的吃方法
/*Cat c1 = new Cat()
c1.eat();
Cat c2= new Cat()
c2.eat();
Cat c3 = new Cat()
c3.eat();
Cat c1 = new Cat()
c1.eat();
Cat c2= new Cat()
c2.eat();
Cat c3 = new Cat()
c3.eat();
Cat c1 = new Cat()
c1.eat();
Cat c2= new Cat()
c2.eat();
Cat c3 = new Cat()
c3.eat();
Cat c1 = new Cat()
c1.eat();
Cat c2= new Cat()
c2.eat();
Cat c3 = new Cat()
c3.eat();
...*/
show(new Cat());
show(new Cat());
show(new Cat());
show(new Dog());
show(new Dog());
show(new Dog());
show(new Zhu());
show(new Zhu());
show(new Zhu());
show(new Ya());
show(new Ya());
show(new Ya());
}
//自从用了方法之后啊,我们发现,不用不断的创建对象,然后一个个调用eat方法,现在的好处是:直接把这个对象放进去方法,就可以帮我直接调用eat方法,我们就不需要手动去调用eat方法
//没用多态前
/*
public static void show(Cat c){
c.eat();
}
public static void show(Dog d){
d.eat();
}
public static void show(Zhu z){
z.eat();
}
public static void show(Ya y){
y.eat();
}
public static void show(Niu z){
z.eat();
}
public static void show(Ji y){
y.eat();
}*/
//用了多态后
public static void show(Animal a){
a.eat(); //都是为了调用公用的方法,也就是重写方法
}
//如果把狗强转成猫就会出现类型转换异常,ClassCastException
public static void method(Animal a) { //当作参数的时候用多态最好,因为扩展性强
//关键字 instanceof 判断前边的引用是否是后边的数据类型
if (a instanceof Cat) {
Cat c = (Cat)a;
c.eat();
c.catchMouse();
}else if (a instanceof Dog) {
Dog d = (Dog)a;
d.eat();
d.lookHome();
}else {
a.eat();
}
}
}
/*
* A:多态的好处
* a:提高了代码的维护性(继承保证)
* b:提高了代码的扩展性(由多态保证)
* B:案例演示
* 多态的好处
* 可以当作形式参数,可以接收任意子类对象
* C:多态的弊端
* 不能使用子类的特有属性和行为。
*/
class Animal {
public void eat() { //第二个 方法
System.out.println("动物吃饭");
}
}
class Cat extends Animal { //第一个条件 继承
public void eat() { //方法重写
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal { //第一个条件 符合继承要求
public void eat() { //第二个条件 方法的重写
System.out.println("狗吃肉");
}
public void lookHome() {
System.out.println("看家");
}
}
class Zhu extends Animal { //第一个条件 符合继承要求
public void eat() { //第二个条件 方法的重写
System.out.println("猪吃米");
}
public void sleep() {
System.out.println("睡觉");
}
}
class Ya extends Animal { //第一个条件 符合继承要求
public void eat() { //第二个条件 方法的重写
System.out.println("鸭吃鸭粮...");
}
public void sleepWithSomeBody() {
System.out.println("陪动物睡觉");
}
}
抽象类
抽象类的特点有哪些?
什么是抽象类 用abstract关键字修饰的类就是抽象类
1,抽象类里面 可以有抽象方法 也可以没有抽象方法
2,如果这个类有抽象方法那么这个必然是抽象类/接口
3,抽象方法没有方法体 public abstract void eat();
4,抽象类是不能实例化,也就是说不能直接new对象,如果要new对象怎么办?只能用父类的引用指向子类的对象.
5,如果一个类继承了抽象类,那么这个类要么是抽象类,要么就重写抽象类里面的所有抽象方法
abstract class Animal{
public abstract void sleep();
}
举例
class Cat extends Animal{
//继承了抽象类,就必须把这个抽象类里面的抽象方法重写
public void sleep(){
System.out.println("这是猫的睡觉方式");
}
}
这个方法体谁来实现? 子类来实现
- 抽象类中的成员特点是什么?
- 成员变量:可以是变量或者常量
- 构造方法: 有,给子类进行初始化
成员方法 : 可以是普通成员方法或者抽象的成员方法
抽象方法的作用是什么?
强制子类重写这个方法
猫狗类案例
⦁ 思考:一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
可以,目的:不让你直接new 这个类的对象,只能让你new它子类对象
abstract class Demo{
}
抽象类abstract关键字不能和什么关键字共存?
static final private
关于接口
接口: 其实就是一种规则 java 里interface表示接口
广义角度:规则,举例 USB接口,符合USB2.0规范
开发中说法:书写接口:书写功能模块,对外提供访问方式
接口用哪个关键字表示?
interface 定义接口的关键字
类实现接口用哪个关键字?
implements 实现的关键字
interface Inter{ //接口名也是标识符,你自己起的名字
//抽象方法...
}
class Demo implements Inter{
//把接口的抽象方法全部实现
}
接口的成员特点是什么?
成员变量:只能是常量,不能是变量,并且是静态的,公共的,最终的
默认 public static final
构造方法:没有
成员方法:只能是的抽象成员方法 public abstract ,如果不写就默认给你加上
举例:
interface Inter{
//手动给出
public static final String name = "xxx";
String name = "yyy"; //系统也默认给你写上
//方法
public abstract void add(); //手动书写 public abstract
void remove(); //系统也默认给你书写上
}
类与类,类与接口,接口与接口的关系分别是什么?
类和类 :继承关系,只能单继承,不能多继承 ,用extends关键字
类和接口:实现关系,implements关键字 ,可以多实现
接口和接口:继承,可以多继承,用extends关键
举例
interface A{
}
//正确书写
interface B extends A{
}
//错误书写
interface B implements A{
}
//正确书写
interface C extends A,B{ //接口支持多继承
}
接口和抽象类的区别
区别 | 接口 | 抽象类 |
---|---|---|
成员变量 | 常量 | 变量/常量 |
构造方法 | 没有 | 有,给子类初始化 |
成员方法 | 抽象 | 抽象/抽象 |
设计理念 | like a,像什么的一种,一般作为扩展功能 | is a 是什么的一种,一般就是继承共性功能 |
现在要求: 怎么写一个接口,怎么用一个类去实现一个接口?用什么关键字!
案例 (非常非常重要)
class Test1_Animal {
public static void main(String[] args) {
Cat c = new Cat("加菲",8);
c.eat();
c.sleep();
JumpCat jc = new JumpCat("跳高猫",3);
jc.eat();
jc.sleep();
jc.jump();
}
}
/*
* A:案例演示
* 动物类:姓名,年龄,吃饭,睡觉。
* 猫和狗
* 动物培训接口:跳高
*/
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 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 abstract void eat(); //吃饭
public abstract void sleep(); //睡觉
}
interface Jumping { //跳高的接口
public void jump();
}
class Cat extends Animal {
public Cat() {} //空参构造
public Cat(String name,int age) {//有参构造
super(name,age);
}
public void eat() {
System.out.println("猫吃鱼");
}
public void sleep() {
System.out.println("侧着睡");
}
}
class JumpCat extends Cat implements Jumping {
public JumpCat() {} //空参构造
public JumpCat(String name,int age) {//有参构造
super(name,age);
}
public void jump() {
System.out.println("猫跳高");
}
}