当前位置: 首页 > news >正文

把网站扒下来以后怎么做全网引擎搜索

把网站扒下来以后怎么做,全网引擎搜索,中国移动智慧社区,google play目录 抽象抽象的概念抽象方法和抽象类的格式抽象方法和抽象类的使用抽象方法和抽象类的注意事项● 练习1. 写一个父类图形类,其中有方法,功能计算面积为抽象方法。2. 抽象类继承。判断对错,没错的分析运行结果3. 发红包,群内用户类作为父类,有…

目录

  • 抽象
    • 抽象的概念
    • 抽象方法和抽象类的格式
    • 抽象方法和抽象类的使用
    • 抽象方法和抽象类的注意事项
    • ● 练习
      • 1. 写一个父类图形类,其中有方法,功能计算面积为抽象方法。
      • 2. 抽象类继承。判断对错,没错的分析运行结果
      • 3. 发红包,群内用户类作为父类,有收红包方法,群主类作为子类有发红包的方法
  • 接口
    • 接口的定义基本格式
    • 接口的使用
      • 接口的1.常量定义和使用
      • 接口的2.抽象方法定义
      • 接口的3.默认方法定义
      • 默认方法的使用
      • 接口的4.静态方法定义
      • 接口的5.私有方法定义(接口内使用)(静态+非静态)
      • 私有方法使用
    • 继承父类并实现多个接口
    • ● 练习
      • 1. 写一个实现类D 实现两个接口A,B,继承一个父类C
  • 多态
    • 多态的格式与使用
    • 多态中成员变量的使用特点
    • 多态中成员方法的使用特点
    • 使用多态的好处
    • 对象的向上转型,向下转型
    • ● 练习
      • 1. 多态中成员方法调用,判断以下输出
      • 2. 多态中成员变量,判断对错或结果
      • 3. 多态中,成员方法间接访问成员变量。判断对错或结果
      • 4. 接口,多态综合练习,接口的基本使用,对象的上下转型,以及接口作为方法的参数。

抽象

抽象的概念

例如父类是一个图形,有一个计算面积的方法。而子类是三角形,正方形,圆形等。计算面积的方法各不相同,父类的计算面积方法就是一个抽象方法。
即如果父类当中的方法不确定如何进行{}方法体实现,那么这就应该是一个抽象方法。

抽象方法和抽象类的格式

public abstract class Fu{public abstract void eat();
}

抽象方法: 就是加上abstract关键字,然后去掉大括号,分号结束
抽象类:抽象方法所在的类必须是抽象才行。在class之前写上abstract即可
抽象类中也可以写普通方法

抽象方法和抽象类的使用

  1. 不能直接new抽象类对象
  2. 必须用一个子类继承抽象父类
  3. 子类必须覆盖重写抽象父亲当中所有的抽象方法。除非子类也是抽象类
    覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号{}
  4. 创建子类对象进行使用

抽象方法和抽象类的注意事项

Alt + Enter在子类继承红线处,自动重写父的抽象方法体

  1. 抽象类不能创建对象,编译报错。
    只能创建其非抽象子类的对象
  2. 抽象类中,可以有构造方法(要实现方法体),是供子类创建对象时,初始化父类成员使用的。
    因为子类构造中默认有super();或者自己指定,所以父类构造器中初始化变量就可以执行。
  3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类
  4. 抽象类中的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

● 练习

1. 写一个父类图形类,其中有方法,功能计算面积为抽象方法。

  • 子类:正方形,三角形,圆形。分别重写其抽象方法为自己类的计算面积方法。

A:

public abstract class Graphics {public abstract double area();
}
public class Square extends Graphics{double length;double width;public Square(int length, int width){this.length = length;this.width = width;}@Overridepublic double area() {return length * width;}
}
public class Circle extends Graphics{double diameter;public Circle(double diameter){this.diameter = diameter;}@Overridepublic double area() {return Math.PI * diameter * diameter;}
}
public class Triangle extends Graphics{double high;double bottom;public Triangle(double high, double bottom){this.high = high;this.bottom = bottom;}@Overridepublic double area() {return (high * bottom) / 2;}
}
public class MainTest{public static void main(String[] args) {Square sq1 = new Square(3, 5);Triangle tr1 = new Triangle(6, 8);Circle ci1 = new Circle(8);System.out.println(sq1.area());System.out.println(tr1.area());System.out.println(ci1.area());}
}

2. 抽象类继承。判断对错,没错的分析运行结果

public abstract class A{public A(){sout("A的构造");    }public abstract void eat();public abstract void sleep();
}
public class B extends A{public B(){sout("B的构造");}@Overridepublic void eat(){sout("B吃东西");}@Overridepublic void sleep(){sout("B睡觉");}
}
public class C extends A{
}
public abstract class D{public void sleep(){sout("D睡觉");}
}
public class MainTest{public static void main(String[] args) {A a = new A();B b = new B();b.eat();D d = new D();d.sleep();  }
}

A:

public class C extends A{ A是抽象类,C没有实现A全部的抽象方法,所以必须是抽象类
}
public class MainTest{public static void main(String[] args) {A a = new A(); 抽象类不可以new对象B b = new B();//正确,因为B实现了抽象父类A的所有抽象方法b.eat();D d = new D();//错,抽象类不可以new● d.sleep();  }
}

结果

A的构造
B的构造
B吃东西

3. 发红包,群内用户类作为父类,有收红包方法,群主类作为子类有发红包的方法

① 群主的一笔金额,从群主的余额中扣除,平均分成n等份,让成员领取。
② 成员领取后,保存到成员余额中
优化:③ 该类每自动生成一个对象,就自动赋值id编号,随人数增加
A:
分析:

  • 发红包方法,参数发多少份,发多少钱。返回一个ArrayList<Integer>,把要发的钱平均分成n份,剩的余额自动存到最后一个红包。
  • 收红包方法参数就是这个List集合,随机的在集合里选一个下标元素收红包。为啥要用这个集合,主要是收了红包以后要在集合里把自己收的那一份删除。
  • 优化思考①:怎么快速把红包加到这些群成员的余额,建立一个群成员类的ArrayList<Member>集合,循环调用每个群成员对象的收红包方法。
  • 优化思考②:让红包不是均等,而是随机分配金额,最小的红包不为0即可。
public class Member {static int idCount = 0;int id;int balance;public Member(){idCount++;this.id = idCount;}public Member(int balance){this.balance = balance;idCount++;this.id = idCount;}public static int getIdCount() {return idCount;}public int getId() {return id;}public int getBalance() {return balance;}void setBalance(int balance){this.balance = balance;}public void receive(ArrayList<Integer> redList){int size = redList.size();int random = (int)(Math.random() * size);//double范围[0,size) [0,size-1]Random r = new Random();int random2 = r.nextInt(size);//int范围[0,size)this.balance += redList.get(random);redList.remove(random);//直接删除这一位,list长度--。}public void show(){System.out.println("----------------------");System.out.println("群成员的id:" + this.id);System.out.println("余额:" + this.balance);}
}

群主类属于特殊的成员类

public class Leader extends Member{public Leader(int balance){this.balance = balance;}public Leader(){}public ArrayList<Integer> send(int count, int money){if(money > getBalance()){System.out.println("余额不足,请重新设置红包金额");return null;}ArrayList<Integer> redList = new ArrayList<>();//分配红包过程,因为都是整数,如果每份都是小数的话,取整。把剩下的放到最后一个红包即可int ave = money / count;int last = money - (ave * count);for (int i = 0; i < count; i++) {redList.add(ave);}int size = redList.size();redList.set(size - 1, redList.get(size - 1) + last);setBalance(getBalance() - money);return redList;}}
// for test
public class MainTest {public static void main(String[] args) {//System.out.println("请依次输入,群主,成员1");Leader l1 = new Leader(3456);Member m1 = new Member(0);Member m2 = new Member(0);Member m3 = new Member(0);ArrayList<Integer> redList = l1.send(3, 50);m1.receive(redList);m2.receive(redList);m3.receive(redList);l1.show();m1.show();m2.show();m3.show();}
}
----------------------
群成员的id:1
余额:3406
----------------------
群成员的id:2
余额:16
----------------------
群成员的id:3
余额:18
----------------------
群成员的id:4
余额:16

优化:随机金额红包,一个群里的成员全部自动抢红包。

把属性balance极其getter,setter,子类balance的有参构造,send返回值类型,receive参数从int改为double。
想要控制double小数点后位数,用printf输出,printf("%.2f",num);

	public void receive(ArrayList<Double> redList){int size = redList.size();int random = (int)(Math.random() * size);//double范围[0,size) [0,size-1]//不推荐random2生成的随机数,经常不够随机//Random r = new Random();//int random2 = r.nextInt(size);//int范围[0,size)this.balance += redList.get(random);redList.remove(random);//直接删除这一位,list长度--。}public void show(){System.out.println("----------------------");System.out.println("群成员的id:" + this.id);System.out.printf("余额:" + "%.2f", this.balance);System.out.println();}
	public ArrayList<Double> send(int count, double money){if(money > getBalance()){System.out.println("余额不足,请重新设置红包金额");return null;}ArrayList<Double> redList = new ArrayList<>();//红包最小金额设置0.1,最大是总金额的0.6,反正就是比一半多一点double min = 0.1;double max = money * 0.6;double last = money;//最后剩余的Random r = new Random();for (int i = 0; i < count - 1; i++) {double num = r.nextDouble()*(max - min) + min;//0.0 ~ 1.0 -> 0.0 ~ max - min -> min ~ maxlast -= num;redList.add(num);}redList.add(last);setBalance(getBalance() - money);return redList;}
----------------------
群成员的id:1
余额:3388.11
----------------------
群成员的id:2
余额:2.70
----------------------
群成员的id:3
余额:59.58
----------------------
群成员的id:4
余额:5.62

接口

接口的定义基本格式

接口就是多个类的公共规范。接口是一种引用数据类型,最重要的内容就是其中的抽象方法。

public interface 接口名称{//接口内容
}

换成了关键字interface之后,编译生成的字节码文件仍然是: .java -> .class
如果Java7,那么接口中可以包含的内容有:

  1. 常量
  2. 抽象方法(只定义,不实现)
    如Java8,额外包含
  3. 默认方法
  4. 静态方法
    Java9,额外包含
  5. 私有方法

接口的使用

1.接口不能直接使用,必须有一个“实现类”来“实现”该接口

public class 实现类名称 implements 接口名称{//……
}

2.接口的实现类必须覆盖重写(实现) 接口中所有的抽象方法
实现:去掉abstract 关键字,加上方法体大括号
3.创建实现类的对象,进行使用。
建议:实现类名:接口名 + Impl
注意:如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类就必须是抽象类。(因为抽象方法所在的类必为抽象类)

以下[括号内]关键字意为可省略的,不写也依然存在的意思

接口的1.常量定义和使用

接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。其实就是接口的常量

[public] [static] [final] 数据类型 常量名称 = 数据值

final:一旦赋值,不可以修改

1.接口当中的常量,可以省略public static final,但不写也是默认有
2.接口当中的常量,必须进行赋值,不能不赋值
复习:
类中成员变量,数组,有默认值。局部变量没有默认值,没赋值不可使用

访问时,接口名.常量名;

public static final int NUM_OF_MY_CLASS = 12;

3.接口中常量的名称,使用完全大写的字母,下划线分隔(推荐命名规则)

接口的2.抽象方法定义

[public] [abstract] 返回值类型 方法名称(参数列表);

注意:
1.接口中的抽象方法,修饰符必须是两个固定的关键字,[public] [abstract] (不可以private等)
2.这两个关键字修饰符,可以选择性地省略。(都不写,也默认是抽象方法)
3.方法的三要素,可以随意定义

接口的3.默认方法定义

[public] default 返回值类型方法名称(参数列表){//方法体
}

默认方法一定是public,默认方法也可以被覆盖重写(不重写也不报错)
备注:接口当中的默认方法,可以解决接口升级的问题
比如,两个实现类都实现了一个接口,但该接口后来添加了新方法。如果是抽象方法的话,就需要两实现类都重写该方法。但默认方法就可以直接继承即可,更方便

默认方法的使用

a为一个实现类对象
a.methodAbs();//调用抽象方法,实际运行的是右侧实现类(复习:因为new谁,就用谁的方法,而实现类重写了这个方法)
1.接口的默认方法,可以通过接口实现类对象,直接调用。(如实现类中没有重写,就向上找)
2.接口的默认方法,也可以被接口实现类进行覆盖重写

接口的4.静态方法定义

[public] static 返回值类型 方法名称(参数列表){方法体
}

就是将abstract或者default换成static即可,带上方法体
注意:不能通过接口实现类的对象来调用来调用接口中的静态方法:
一个类可以实现多个接口,静态方法可能冲突

  • 但接口中不可以用实现类调用static方法,只能用接口名调用static方法
  • 注意其中区别,已知普通类中,类名. 对象名. 都可以用来调用static方法

通过接口名称,直接调用其中的静态方法 接口名.静态方法名(参数)

接口的5.私有方法定义(接口内使用)(静态+非静态)

接口中需要抽取一个共有方法,用来解决接口中两个默认方法之间重复代码的问题
1.普通私有方法,解决多个默认方法之间重复代码的问题

private 返回值类型 方法名称(参数){方法体
}

2.静态私有方法,解决多个静态方法之间重复代码问题

private static 返回值类型 方法名(参数){方法体
}

private方法只有接口自己才能调用,不能被实现类或别人使用

私有方法使用

两个默认方法调用一个私有方法

public default void methodDefault1(){默认方法1methodCommon();
}
public default void methodDefault2(){默认方法2methodCommon();
}
private void methodCommon(){}

两个静态方法调一个私有静态方法

public static void methStatic1(){静态方法1methodStaticCommon();
}
public static void methStatic2(){静态方法2methodStaticCommon();
}
pirvate static void methodStaticCommon(){}

继承父类并实现多个接口

  1. 接口中没有静态代码块或构造方法
static{……
}

(复习:第一次用到本类时,静态代码块执行唯一的一次。一般用来一次性的对静态成员变量赋值。静态内容总是优先于非静态,静态代码比构造方法先执行。)
shift + F6 重命名类
Ctrl + C/V 复制整个类
实现接口时 Alt + Enter
选要实现的方法
Java中所有类都是Object的直接子类或间接子类

  1. 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB{//覆盖重写所有抽象方法
}
  1. 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。

❓怎么判断是否重复,返回值和名,参数列表全一致吗?(方法的三要素)

A: 方法名和参数相同即为重复方法,与返回值无关
1)与返回值无关,返回值不同,方法名和参数相同也属于重复方法。只需要保证子类重写的方法返回值是父类方法的子类型即可,例如Object做父类返回值 只是此处子方法返回值可以是Integer但不能是Object,因为接口B中返回值Integer不可以当Object的父
(复习:重写3要素:①方法名和参数列表都相同,②只需要保证重写方法的返回值类型 <= 父类(此处是父接口)方法即可。③重写的子类方法的权限 >= 父类方法)

public interface MyInterfaceA {Object method1();
}
public interface MyInterfaceB {Integer method1();
}
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB{@Overridepublic Integer method1(){System.out.println();return 1;}
}

2)与参数有关,若参数不同,就不是同一个方法。在实现类中都继承就需要都重写,属于重载方法。

public interface MyInterfaceA {Object method1();
}
public interface MyInterfaceB {Integer method1(int num);
}
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB{@Overridepublic Integer method1(){System.out.println();return 1;}public Integer method1(int num){return 1;}
}
  1. 如果实现类没有覆盖重写所有接口与当中的所有抽象方法,那么实现类就必须是一个抽象类。
  2. 如多个接口中,存在重复的默认方法,实现类一定要对冲突的默认方法进行覆盖重写。
  3. 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法因为继承优先于接口实现,也不用重写冲突的方法
public class Zi extends Fu implements MyInterface{}

注意:

  1. 多个父接口当中的抽象方法如果重复,没关系。因为没有方法体,实现类中重写一次即可。抽象类作为子类或子接口可以不重写该方法
  2. 多个父接口当中的默认方法如果重复,有关系。子接口必须进行默认方法的覆盖重写,(而且带着default关键字)接口中default不能省略,与普通类方法的权限修饰符 留空即(default )不同。

● 练习

1. 写一个实现类D 实现两个接口A,B,继承一个父类C

接口A写所有可有内容(5种)的完整写法
接口B写所有可有内容的省略写法
其中A,B 中1常量名重复,1抽象方法重复, 1抽象方法只方法名,参数相同,1私有方法重复。A,B,C 1默认方法重复,1静态方法重复。B,C 1默认方法重复(分析哪些不能实现及原因)
A: 总结:一个实现类实现多个接口和一个父类的情况下

  • 多个接口中常量名冲突,用接口名调用即可。实现类对象只能调不冲突的常量,不然混淆
  • 多个接口中抽象方法冲突,实现类重写一次即可。抽象子类或子接口无需重写
  • 多个接口中默认方法冲突,子必须重写一次。
  • 一个父接口和父类的默认方法冲突,不用重写,优先使用父类该重名方法。
  • 静态方法只能用接口名调用,不可以用实现类调用。复习,普通类中,类名,对象名都可以调用静态方法
  • 重写时注意,若多个父接口中的重名方法返回值不同。子中重写方法的返回值类型 <= 父方法即可。此处大小指的是父子类关系,例如:Object类 > Integer类
public interface MyInterA {public static final int NUM = 10;public abstract Object abMethod1();public abstract Integer abMethod2();public default void deMethod1(){System.out.println("接口A的默认方法,A,B,C中重名");
//        method1();
//        method2();}public static void stMethod1(){System.out.println("接口A的静态方法,A,B,C中重名");
//        method2();//method1();调不了,静态方法中调用非静态方法得new对象,但接口不能new对象}/*复习,1.静态方法中调用:①静态方法或变量,内部直接调(外部静态导入也是直接调),外部类名.* ②非静态方法,统一用对象名.调用* 2.非静态方法中调用:①内部类,不论静态或非静态,都直接调* ②外部类,静态用类名.,非静态用对象.*///因为Java8不能写这些
//    private void method1(){
//        System.out.println("A的重复代码,私有");
//    }
//    private static void method2(){
//        System.out.println("A的重复代码,私有静态");
//    }
}
public interface MyInterB {int NUM = 20;int BNUM = 30;Float abMethod1();Integer abMethod2();public default void deMethod1(){System.out.println("接口B的默认方法1,A,B,C中重名");
//        method1();
//        method2();}public default void deMethod2(){System.out.println("接口B的默认方法2,B,C中重名");}public static void stMethod1(){System.out.println("接口B的静态方法,A,B,C中重名");
//        method2();//method1();调不了,静态方法中调用非静态方法得new对象,但接口不能new对象}public static void stMethod2(){System.out.println("接口B自己的静态方法");}//因为Java8不能写这些
//    private void method1(){
//        System.out.println("B的重复代码,私有");
//    }
//    private static void method2(){
//        System.out.println("B的重复代码,私有静态");
//    }}
public class MyClassC {void deMethod1(){System.out.println("------类C的默认方法1,A,B,C中重名------");method1();method2();System.out.println("------------------------------------");}public void deMethod2(){System.out.println("类C的默认方法2,B,C中重名");}public static void stMethod1(){System.out.println("----类C的静态方法,A,B,C中重名---");method2();System.out.println("-------------------------------");//method1();调不了,静态方法中调用非静态方法得new对象,但接口不能new对象}private void method1(){System.out.println("类C的重复代码,私有");}private static void method2(){System.out.println("类C的重复代码,私有静态");}
}
public class MyClassD extends MyClassC implements MyInterA, MyInterB{
//    @Override
//    public Double abMethod1() {
//        return null;
//    }/*复习:虽然该抽象方法,A接口返回值为Object,B接口返回值为Float,重写时子类方法返回值 <= 父类返回值即可*/@Overridepublic Float abMethod1() {System.out.println("类D重写的抽象方法1");return null;}@Overridepublic Integer abMethod2() {System.out.println("类D重写的抽象方法2");return null;}public void deMethod1(){System.out.println("默认方法1,接口A,B默认方法和类C方法重名,所以需要实现类D重写一次");System.out.println("但实际上A,B默认方法都无法调用到,只能super调用父类C的该名称方法");super.deMethod1();}}
public class Main {public static void main(String[] args) {MyClassD d1 = new MyClassD();System.out.println("因为接口中常量都为static,所以类名或实现类对象调用都可以。但在父接口常量重名时,不可用实现类对象调用,因为混淆");System.out.println(MyInterA.NUM);System.out.println(MyInterB.NUM);System.out.println(d1.BNUM);d1.abMethod1();d1.abMethod2();/*默认方法1,ABC中重名,优先使用父类C的,但是接口A,B中也重名,需要在实现类D中重写*/d1.deMethod1();/*默认方法2 ,BC中重名,优先用父类C的,D中不用重写。直接用*/d1.deMethod2();/*静态方法用类名or接口名调用*/System.out.println("======================");MyInterA.stMethod1();MyInterB.stMethod2();MyClassC.stMethod1();}
}

自己分析输出结果

因为接口中常量都为static,所以类名或实现类对象调用都可以。但在父接口常量重名时,不可用实现类对象调用,因为混淆
10
20
30
类D重写的抽象方法1
类D重写的抽象方法2
默认方法1,接口A,B默认方法和类C方法重名,所以需要实现类D重写一次
但实际上A,B默认方法都无法调用到,只能super调用父类C的该名称方法
------类C的默认方法1,A,B,C中重名------
类C的重复代码,私有
类C的重复代码,私有静态
------------------------------------
类C的默认方法2,B,C中重名
======================
接口A的静态方法,A,B,C中重名
接口B自己的静态方法
----类C的静态方法,A,B,C中重名---
类C的重复代码,私有静态
-------------------------------

多态

面向对象三大特征:封装性、继承性、多态性。
extends继承或者implements实现,是多态性的前提。

小明是一个学生,但同时也是一个人。小明是一个对象,这个对象既有学生形态,也有人类形态。
一个对象拥有多种形态,这就是:对象的多态性

多态的格式与使用

Polymorephism -> Mulit
代码中体现多态性: 父类引用指向子类对象

格式:

父类名称 对象名 = new 子类名称();

接口名称 对象名 = new 实现类名称();

复习前篇:
子父类重名方法,new 的是谁就用谁的方法,没有则向上找。

多态中成员变量的使用特点

public class Fu {int num = 10;
void method(){System.out.println(num);}void methodFu(){System.out.println(num);}
}
public class Zi extends Fu{int num = 20;int age = 16;void method(){System.out.println("子类method");System.out.println(num);}
}
public class Main {public static void main(String[] args) {Fu obj = new Zi();obj.method();//20,子类方法obj.methodFu();//10,父类特有方法System.out.println(obj.num);//10//直接调用,重名变量看左侧引用是谁//System.out.println(obj.age);错误写法,变量看左边引用,父类没有,不会向下找}
}

复习前篇:
重名变量:1) 直接调,= 左边既引用是谁就用谁的变量
2) 间接访问:利用类中方法,类中方法都是优先调用本类变量。调用的方法属于哪个类,就是哪个类中的变量

多态中成员方法的使用特点

在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找。

成员变量:编译看左,运行还看左
成员方法:编译看左,运行看右

public class Fu {int num = 10;void showNum(){System.out.println(num);}void method(){System.out.println("重名方法method");}void methodFu(){System.out.println("父类特有methodFu");}}
public class Zi extends Fu{int num = 20;int age = 16;void showNum(){System.out.println(num);}void method(){System.out.println("重名方法method");}void methodZi(){System.out.println("子类特有methodZi");}
}

分析结果:obj.methodZi()编译错误

public class Main {public static void main(String[] args) {Fu obj = new Zi();obj.method();//编译看左,Fu有该方法。运行看右,Zi有该方法,运行子类obj.methodFu();//编译看左,Fu有该方法。运行看右,Zi无该方法,就向上找,运行父类//obj.methodZi();//编译看左,Fu类没有该方法,编译出错}
}

❓扩展:若重名方法内调用重名变量

pulbic class Fu{int num = 10;void method(){System.out.println(num);//10}
}
public class Zi extends Fu{int num = 20;void method(){System.out.println(num);//20}
}

A:分析,方法所在类内的该变量,若有直接调,没有则向上找
多态情况,编译看左,Fu有方法method,运行看右Zi有method方法,运行子类方法

public static void main(String[] args){Fu obj = new Zi();obj.method();//20
}

使用多态的好处

在这里插入图片描述
如不用多态,只用子类,写法:

Teacher one = new Teacher();
one.work();//讲课
Assistent two = new Assistant();
two.work();//辅导

我现在唯一要做的事情,就是调用work方法,其他功能不关心

如果使用多态的写法,对比一下:

Employee one = new Teacher();
one.work();//讲课
Employee two = new Assistant();
two.work();//辅导

好处:无论右边new的时候换成哪个子类对象,等号左边调用方法都不会改变。(改代码更灵活)

对象的向上转型,向下转型

在这里插入图片描述

public interface Animal {void eat();
}
public class Cat implements Animal{@Overridepublic void eat() {System.out.println("猫吃鱼");}public void catchMice(){System.out.println("猫抓老鼠");}
}
public class Dog implements Animal{@Overridepublic void eat() {System.out.println("狗吃骨头");}public void door(){System.out.println("狗看家");}
}
  1. 对象的向上转型,其实就是多态写法:
    Animal animal = new Cat();含义:右侧创建一个子类对象,把它当做父类来看待使用。注意,此时,类对象不可以调用子类Cat特有的方法(因为对于成员方法,编译看左,运行看右。父类Animal没有子类特有的方法,编译出错)
格式:父类名 对象名 = new 子类名称();

创建了一只猫,当做动物看待,没问题。
注意事项:向上转型一定是安全的。从小范围转向了大范围。(动物范围比猫更广)
类似于: double num = 100; //√,整数默认类型为int,int取值范围 < double 范围。int -> double, 自动类型转换。从小范围的猫,向上转换成为更大范围的动物
对象的向上转型,就是父类引用指向子类对象

 Animal animal = new Cat();animal.eat();//猫吃鱼
  1. 对象的向下转型,其实是一个还原的动作。
    格式: 子类名称 对象名 = (子类名称)父类对象;
    含义:将父类对象,还原成为本来的子类对象。
    Animal animal = new Cat();本来是猫,向上转型成为动物
    Cat cat = (Cat) animal;本来是猫,已经被当做动物了,还原回来成为本来的猫
    a. 必须保证对象本来创建的时候,就是猫,才能向下转型成为猫
    b. 如果对象创建的时候本来不是猫(比如是狗Dog类,其他的子类,或父类本身Animal),现在非要向下转型成为猫,就会报错。 ClassCastException类转换异常

❓如何才能知道一个父类引用的对象,本来是什么子类?
格式: 对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象不能当做后面类型的实例。向下转型前一定要用instanceof判断,因为不确定接口有几个实现类

  • 注意,如果方法形参规定是父类或父接口,传实参为子类或实现类不是多态写法,但传参了也符合向上转型。也是从小范围类型赋值给大范围

在这里插入图片描述
在这里插入图片描述

  • 分两步向上转型,和传参再向上转型都可以
public class Main {public static void getPet(Animal animal){if(animal instanceof Dog){System.out.println("得到的宠物是狗狗");Dog dog = (Dog)animal;// ● 向下转型,必须原对象就是Dog类,所以一定先instanceof判断dog.door();//还原后才可以调用子类特有的方法}else if(animal instanceof Cat){System.out.println("得到的宠物是猫猫");Cat cat = (Cat)animal;cat.catchMice();}}public static void main(String[] args) {//向上转型
//        Dog dog1 = new Samoyed();
//        Samoyed sam1 = (Samoyed)dog1;
//        sam1.personality();
/*此处实验,向下转型只能还原,也不能把父类强转成子类。
转的类型必须跟开始的对象类型一致,只有引用不一致*/
//        Dog dog2 = new Dog();
//        Samoyed sam2 = (Samoyed)dog2;
//        sam2.personality();//模拟向上转型Animal a1 = new Cat();//①向上转型Dog a2 = new Dog();Animal a3 = a2;//②分两步向上转型getPet(a2);//③子类传参给形参是父接口的,也属于向上转型getPet(new Dog());//④匿名对象传也可以a1.eat();a3.eat();//不能调用子类特有方法,如door(),catchMice();}
}
得到的宠物是狗狗
狗看家
得到的宠物是狗狗
狗看家
猫吃鱼
狗吃骨头

● 练习

1. 多态中成员方法调用,判断以下输出

public class Fu {void method(){System.out.println("父类method");}void methodFu(){System.out.println("父类特有methodFu");}
}
public class Zi extends Fu{void method(){System.out.println("子类method");}
}
public class Main {public static void main(String[] args) {//判断以下输出Fu obj = new Zi();obj.method();obj.methodFu();}
}

A:new的是谁用谁的方法,没有则向上找

子类method
父类特有methodFu

2. 多态中成员变量,判断对错或结果

public class Fu {int num = 10;void method(){System.out.println(num);}void methodFu(){System.out.println(num);}
}
public class Zi extends Fu{int num = 20;int age = 16;void method(){System.out.println("子类method");System.out.println(num);}
}
public class Main {public static void main(String[] args) {Fu obj = new Zi();obj.method();obj.methodFu();System.out.println(obj.num);System.out.println(obj.age);}
}

A: 记 成员变量:编译看左,运行看左。成员方法:编译看左,运行看右
方法属于哪个类,优先调用本类的变量,若无才向上找

 public static void main(String[] args) {Fu obj = new Zi();obj.method();//编译看左,Fu,有。运行看右,Zi也有,运行子类方法obj.methodFu();//编译看左,Fu,有。运行看右,Zi无,向上找,运行父类方法System.out.println(obj.num);//直接调用,成员变量始终看左,执行父类变量System.out.println(obj.age);//错,变量看左,父类Fu没这个变量编译错误,也不可能向下找}
子类method
20
10
10

3. 多态中,成员方法间接访问成员变量。判断对错或结果

public class Fu {int num = 10;void showNum(){System.out.println(num);}void method(){System.out.println("父类重名方法method");}void methodFu(){System.out.println("父类特有methodFu");}
}
public class Zi extends Fu{int age = 16;void showNum(){System.out.println(num);}void method(){System.out.println("子类重名方法method");}void methodZi(){System.out.println("子类特有methodZi");}
}
public class Main {public static void main(String[] args) {Fu obj = new Zi();obj.method();obj.methodFu();obj.methodZi();obj.showNum();}
}

A:

 public static void main(String[] args) {Fu obj = new Zi();obj.method();//编译看左,Fu有该方法。运行看右,运行子类方法obj.methodFu();//编译看左,运行看右。Zi中没有,向上找,运行父类方法● 错 obj.methodZi();//编译看左,Fu中无,错误obj.showNum();//编译看左,运行看右。运行子类方法,但Zi中没有num,向上找。(只要Fu中num,不是private私有的就行)}
子类重名方法method

复习权限:
private -> 类内部使用
(default) 比上多一个使用区 -> 同一个包
protected 比前两多一个 -> 子类
public 比前几个多 -> 任何地方

4. 接口,多态综合练习,接口的基本使用,对象的上下转型,以及接口作为方法的参数。


A: 分析,use接口有无对电脑,极其开关机操作无关,只是使用设备时需要作为链接的标准,作为参数。鼠标键盘等属于usb设备,需要实现use接口。use接口中功能就是打开和关闭。 具体设备有自己的特有功能,类似点击打字之类。

在这里插入图片描述

public class Iaptop {public void powerOn(){System.out.println("打开笔记本");}public void useDevice(USB usb){usb.open();//因为多态,引用为接口,对象为实现类。不可以调用实现类特有的方法。// 复习:对于成员方法,编译看左,运行看右//所以想要调用子类特有方法,进行还原,即向下转型后调用即可if(usb instanceof Mouse){Mouse mouse = (Mouse)usb;mouse.click();}else if(usb instanceof Keyboard){//注意:不可以直接else,必须加if判断,因为不能确定接口只有这两个实现类Keyboard keyboard = (Keyboard)usb;keyboard.type();}usb.close();
//        System.out.println("使用设备");}public void powerOff(){System.out.println("关闭笔记本");}
}
public interface USB {public abstract void open();public abstract void close();}
public class Mouse implements USB{@Overridepublic void open() {System.out.println("打开鼠标");}@Overridepublic void close() {System.out.println("关闭鼠标");}public void click(){System.out.println("点击");}
}
public class Keyboard implements USB{@Overridepublic void open() {System.out.println("打开键盘");}@Overridepublic void close() {System.out.println("关闭键盘");}public void type(){System.out.println("打字");}
}
public class Main {public static void main(String[] args) {Iaptop c1 = new Iaptop();c1.powerOn();//多态,4种向上转型。//usb1 和 usb3 是一步向上转型和分两步向上转型//usb2 和 usb4 是实现类传参给接口,也是向上转型USB usb1 = new Mouse();Keyboard usb2 = new Keyboard();USB usb3 = usb2;c1.useDevice(usb1);c1.useDevice(usb2);//相当于,形参是double,实参是int。从小范围到大范围传参自动类型转换c1.useDevice(usb3);c1.useDevice(new Mouse());c1.powerOff();}
}
打开笔记本
打开鼠标
点击
关闭鼠标
打开键盘
打字
关闭键盘
打开键盘
打字
关闭键盘
打开鼠标
点击
关闭鼠标
关闭笔记本
http://www.hrbkazy.com/news/44150.html

相关文章:

  • 类似凡科互动的网站免费培训课程
  • 自建服务器做网站要备案百度竞价关键词价格查询工具
  • 北京 公司网站 备案中 开通访问腾讯企点app
  • 海盐建设局网站百度链接收录
  • 在淘宝做网站和网络公司做网站区别交换友情链接的网站标准是什么
  • 国家建设厅网站网络软文投放
  • 手机在线做网站关键词自动优化工具
  • 商城的网站建设西安网站优化培训
  • 无证做音频网站违法吗seo文章生成器
  • 做网站域名解析网络营销策略的内容
  • 做网站需要的大图有哪些网站可以免费发布广告
  • 建设网站的公司专业服务百度人工服务热线
  • 网站域名信息全网媒体发布平台
  • 软件开发价格标准刷seo快速排名
  • 做国外的批发网站有哪些怎么在百度发布免费广告
  • 网站 页面 结构西安全网优化
  • 电子商城网站免费百度seo引流
  • 企业网站首页设计欣赏免费推广平台排行
  • 网站图片自动切换怎么做微信公众号营销
  • 专业的赣州网站建设seo站长常用工具
  • 做电影网站投资多少百度官方网页
  • 网站建设销售方面会遇到的问题百度热榜实时热点
  • 太原注册公司流程seowhy论坛
  • 怎样注册平台网站广东全网推广
  • 哪个网站做推广比较好信息流广告哪个平台好
  • java能网站开发吗网站怎么做的
  • 东莞免费建站在线咨询一个新的app如何推广
  • 微信网站建设咨询西地那非片吃了能延时多久
  • php网站做分享到朋友圈黄页88网推广服务
  • 怎样做网站搜索推广网络优化工资一般多少