• 【无标题】


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

    目录

    前言

    抽象类和接口

    一.抽象类

    完整的抽象类

             二.接口

    接口的简单案例:

    动物类

    狗:

    鸟:

    测试:

    定义fly接口,并让鸟实现这个功能:

    重写测试:

    总结

    抽象类和接口的区别:

    三.接口的应用

    比较接口

         比较俩个对象的大小

    1.调用compareable接口,重写其中的compare to方法

                   对象的排序

    2.比较器比较大小

    比较器方式比较数组:

    自己实现sort比较对象

    总结:

    克隆接口

    浅拷贝

     如何实现深拷贝:

    总结:



    前言

    回顾javase基础


    提示:以下是本篇文章正文内容,下面案例可供参考

    抽象类和接口

    一.抽象类

    1.使用abstract修饰的方法是抽象方法

    2.包含抽象方法的类必须设计为抽象类,使用abstract修饰这个类

    3.抽象类是不能够被实例化的

    4.抽象类当中,可以有和普通类一样的方法,成员,最突出的和普通类不一样的地方是,抽象类不可以进行实例化

    1. public abstract class Shape {
    2. public int a;
    3. public int b;
    4. public void fun(){
    5. }
    6. //抽象方法
    7. public abstract void draw();
    8. }

    5.抽象类虽然不可以进行实例化,但是可以被继承,也就是说抽象类其实就是为了被继承

    6.当一个普通l类继承这个抽象类之后,如果这个抽象类当中包含抽象方法,那么需要重写这个抽象方法,否则代码不能通过编译(相当于编译器的一层检查必须如果是重写抽向方法必须加上@override

    1. class Rect extends Shape{
    2. @Override
    3. public void draw() {
    4. System.out.println("重写抽象方法");
    5. }
    6. }

    7.如果一个抽象类a继承另一个抽象类b,那么此时抽象类a,可以不重写b的抽象方法(此时实现类要重写所有的抽象方法

    完整的抽象类

    画图形

    1. package 抽象类和接口;
    2. public abstract class Shape {
    3. public int a;
    4. public int b;
    5. public void fun(){
    6. }
    7. //抽象方法
    8. public abstract void draw();
    9. }
    10. class Rect extends Shape{
    11. @Override
    12. public void draw() {
    13. System.out.println("重写抽象方法");
    14. }
    15. }
    16. class Flower extends Shape{
    17. @Override
    18. public void draw() {
    19. System.out.println("画一朵花");
    20. }
    21. }
    22. class Cycle extends Shape {
    23. @Override
    24. public void draw() {
    25. System.out.println("圆形");
    26. }
    27. }
    28. class Triangle extends Shape {
    29. @Override
    30. public void draw() {
    31. System.out.println("△");
    32. }
    33. }

    1. package 抽象类和接口;
    2. public class Test {
    3. public static void darwMap(Shape shape){
    4. shape.draw();
    5. }
    6. public static void main(String[] args) {
    7. // Shape shape=new Shape();
    8. darwMap(new Cycle());
    9. darwMap(new Flower());
    10. darwMap(new Triangle());
    11. darwMap(new Rect());
    12. }
    13. }

    8.抽象方法不能是private的,static,final修饰

    9.抽象类也可以有构造方法

    二.接口

    1.使用interface修饰一个接口

    interface  Shape{}

    2.接口当中的成员变量默认都是public static final修饰的

    3.接口当中的成员方法,默认都是抽象方法,punlic ,abstract修饰的

    1. //接口当中的方法默认都是被public abstract 修饰
    2. abstract void fun1();
    3. public void fun2();
    4. public abstract void fun();
    5. void draw();
    6. //接口当中成员变量默认被public static final修饰
    7. public static final int a=5;
    8. public static final int b=7;

    4.接口当中的实例成员方法(普通方法)是不能有具体的实现的 

    5.接口当中的实例成员方法(普通方法)如果要有具体的实现,必须加上default修饰

        default void draw(){};

    6.接口当中可以有静态的成员方法,但是不管是静态的方法还是普通方法都是被public修饰的

    1. public static void fun5(){
    2. System.out.println("静态方法");
    3. }

    7.接口本身不能被实例化

    8.类和接口的关系是使用implements来关联的

    1. class Rect implements Shape{
    2. @Override
    3. public void fun1() {
    4. System.out.println("重写接口方法");
    5. }
    6. }

    109.一个接口可以引用具体的实现类的,相当于是向上转型

    1. public class Test {
    2. public static void drawMap(Shape shape){
    3. shape.fun1();
    4. }
    5. public static void main(String[] args) {
    6. Rect rect=new Rect();
    7. drawMap(rect);
    8. //可以发生向上转型
    9. Shape shape=new Rect();
    10. }
    11. }

    10.接口当中不能有静态,实例代码块,构造方法

    因为接口不能直接调用,要靠实现类继承

    11.一个抽象类实现一个接口,可以不重写这个抽象方法,但是出来混迟早要还。

    1. abstract class A implements Shape{
    2. ;
    3. }

    接口的简单案例:

    动物类

    由于我们不清楚eat什么,可以先设置成抽象方法,等待类被继承

    1. abstract class Animal{
    2. String name;
    3. int age;
    4. public Animal(String name, int age) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. // public void eat(){
    9. // System.out.println("动物会干饭");
    10. // }
    11. public abstract void eat();
    12. }

    狗:

    需要重写抽象方法

    1. class Dog extends Animal{
    2. public Dog(String name, int age) {
    3. super(name, age);
    4. }
    5. @Override
    6. public void eat() {
    7. System.out.println("狗吃狗粮");
    8. }
    9. }

    鸟:

    重写eat方法:

    1. class Bird extends Animal{
    2. public Bird(String name, int age) {
    3. super(name, age);
    4. }
    5. @Override
    6. public void eat() {
    7. System.out.println("鸟吃鸟粮");
    8. }
    9. }

    测试:

    通过方法传参形式完成向上转型,并调用重写后的方法

    1. public class Test2 {
    2. public static void fun(Animal animal){
    3. animal.eat();
    4. }
    5. public static void main(String[] args) {
    6. fun(new Bird("小鸟",15));
    7. fun(new Dog("二哈",8));
    8. }
    9. }

    此时还有缺陷:小鸟还会飞,但是动物不一定都会飞,如果给动物类飞设置成抽象方法,后续实现类都需要重写飞的方法,非常麻烦。

    如果采取向下转型,如果后续还有要飞的动物,又重写判定也不方便,java还不能多继承,不能在写一个实现类。

    这时候就需要考虑接口了

    定义fly接口,并让鸟实现这个功能:

    1. interface fly{
    2. public abstract void fly();
    3. }
    4. class Bird extends Animal implements fly{
    5. public Bird(String name, int age) {
    6. super(name, age);
    7. }
    8. @Override
    9. public void eat() {
    10. System.out.println("鸟吃鸟粮");
    11. }
    12. @Override
    13. public void fly() {
    14. System.out.println("鸟会飞");
    15. }
    16. }

    重写测试:

    1. public class Test2 {
    2. public static void fly(IFly iFly){
    3. iFly.fly();
    4. }
    5. public static void fun(Animal animal){
    6. animal.eat();
    7. }
    8. public static void main(String[] args) {
    9. fun(new Bird("小鸟",15));
    10. fun(new Dog("二哈",8));
    11. fly(new Bird("小鸟",15));
    12. }
    13. }

    总结

    接口完美解决了不能多继承的问题:

    抽象类和接口的区别:

     1.成员变量

    抽象类当中可以有普通的成员变量,可以有静态的成员变量

    接口的成员变量只能被public static final修饰

    2.成员方法

    抽象类可以构造方法,也可以有普通方法,不能被default修饰,可以有静态方法

    但接口只能有抽象方法,或者被default修饰,或者静态方法

    共同点是都不能实例化

    区别是一个类只能继承一个抽象类,但是可以实现多个接口

    三.接口的应用

    • 比较接口

    比较俩个对象的大小

    对象之间不能直接比较大小

     
    

    1.调用compareable接口,重写其中的compare to方法

    1. package 接口;
    2. class Student implements Comparable{
    3. String name;
    4. int age;
    5. double score;
    6. public Student(String name, int age, double score) {
    7. this.name = name;
    8. this.age = age;
    9. this.score = score;
    10. }
    11. @Override
    12. public String toString() {
    13. return "student{" +
    14. "name='" + name + '\'' +
    15. ", age=" + age +
    16. ", score=" + score +
    17. '}';
    18. }
    19. @Override
    20. public int compareTo(Student o) {
    21. if(o.score>this.score){
    22. return 1;
    23. }else if(o.score<this.score){
    24. return -1;
    25. }else{
    26. return 0;
    27. }
    28. }
    29. }
    30. public class Test3 {
    31. public static void main(String[] args) {
    32. Student student1=new Student("张三",18,98.5);
    33. Student student2=new Student("张三",18,97.5);
    34. if(student1.compareTo(student2)<0){
    35. System.out.println("student1>student2");
    36. }
    37. }
    38. }

    注意比较方法:

    对象的排序

    如果直接排序会这样:

    1. Student student1=new Student("张三",18,98.5);
    2. Student student2=new Student("张三",15,97.5);
    3. Student student3=new Student("张三",12,97.5);
    4. Student student[]=new Student[]{student1,student2,student3};
    5. Arrays.sort(student);

    sort方法比较对象时其实实现了Comparable接口,但是我们并没有实现compareto方法,所以我们要给比较的对象实现comparable接口并重写compareto方法

    上述比较方式有一个缺陷,就是由于是在类里面写的比较方法,相当于比较方式唯一的,如果根据年龄比,就得重新修改,破坏了原来的比较方式

    2.比较器比较大小

    更加灵活:

    根据用户需求自定义一个比较器(类)而不是直接在原来类里面写死比较方法

    实现compartor接口,重写compare方法

    1. class AgeComparator implements Comparator {
    2. @Override
    3. public int compare(Student o1, Student o2) {
    4. return o1.age - o2.age;
    5. }
    6. }
    7. class ScoreComparator implements Comparator {
    8. @Override
    9. public int compare(Student o1, Student o2) {
    10. return (int) (o1.score - o2.score);
    11. }
    12. }
    13. public class Test3 {
    14. public static void main(String[] args) {
    15. Student student1 = new Student("张三", 18, 98.5);
    16. Student student2 = new Student("张三", 15, 97.5);
    17. Student student3 = new Student("张三", 12, 95.5);
    18. AgeComparator ageComparator = new AgeComparator();
    19. int ret = ageComparator.compare(student1, student2);
    20. System.out.println("年龄比较" + ret);
    21. ScoreComparator scoreComparator = new ScoreComparator();
    22. int ret2 = scoreComparator.compare(student1, student2);
    23. System.out.println("分数比较" + ret2);
    24. }

    比较器方式比较数组:

    1. Student student1 = new Student("张三", 18, 98.5);
    2. Student student2 = new Student("张三", 15, 97.5);
    3. Student student3 = new Student("张三", 12, 97.5);
    4. Student student[] = new Student[]{student1, student2, student3};
    5. AgeComparator ageComparator = new AgeComparator();
    6. Arrays.sort(student, ageComparator);

    array.sort()可以传俩个参数,比较器和对象

    自己实现sort比较对象

    1. //自己实现sort比较对象
    2. public static void sort(Comparable[]array){
    3. for (int i = 0; i 1 ; i++) {
    4. for (int j = 0; j 1-i ; j++) {
    5. if(array[j].compareTo(array[j+1])>0){
    6. //不符合要求
    7. Comparable tmp=array[j+1];
    8. array[j+1]=array[j];
    9. array[j]=tmp;
    10. }
    11. }
    12. }

    总结:

    如果以后是自定义类型的数据,牵扯到大小比较,需要进行一些设计,比如实现接口

    比较数组array.sort()构成了重载,可以传比较器,对象和只穿对象

    string类型默认实现comparator接口,重写了compareTo方法,直接调用即可

    • 克隆接口

    • 克隆就是产生对象一个个副本

      1.实现克隆接口:

      其实这个接口cloneable当中,没有抽象方法,空接口/标记接口:当前类可以被克隆

      2.重写克隆方法(重写的是object类克隆方法),底层是c++实现的不关注

      1. class Person implements Cloneable{
      2. public int age=10;
      3. @Override
      4. protected Object clone() throws CloneNotSupportedException {
      5. return super.clone();
      6. }
      7. }

      此时person已经具有了clone方法(object类的)

      测试克隆:

      需要向下转型

      1. public static void main(String[] args) throws CloneNotSupportedException {
      2. Person person=new Person();
      3. Person person2=(Person) person.clone();
      4. }

      相当于新分配了内存,产生了新对象产生对象的副本,改变person2不会影响person1

      浅拷贝

      我们给person类加一个money属性,money里存了m

      1. class Money{
      2. public int m;
      3. }
      4. class Person implements Cloneable{
      5. public int age=10;
      6. Money money=new Money();
      7. @Override
      8. protected Object clone() throws CloneNotSupportedException {
      9. return super.clone();
      10. }
      11. @Override
      12. public String toString() {
      13. return "Person{" +
      14. "age=" + age +
      15. '}';
      16. }
      17. }

       通过测试修改第二个Person的m,第一个也随之改变

      1. public static void main(String[] args) throws CloneNotSupportedException {
      2. Person person=new Person();
      3. Person person2=(Person) person.clone();
      4. person.money.m=99;
      5. person2.money.m=180;
      6. System.out.println(person.money.m);
      7. }

      此时输出180,第一个人存的钱变了???为什么这样呢

      发生了浅拷贝:相互影响

       如何实现深拷贝:

      不相互影响

      效果如下:

      1.给money实现克隆接口

      1. class Money implements Cloneable{
      2. public int m;
      3. @Override
      4. protected Object clone() throws CloneNotSupportedException {
      5. return super.clone();
      6. }
      7. }

      2.修改Person的克隆使其能再拷贝出一个money,并返回tmp

      1. class Person implements Cloneable {
      2. public int age = 10;
      3. public Money m = new Money();
      4. @Override
      5. protected Object clone() throws CloneNotSupportedException {
      6. Person tmp = (Person) super.clone();
      7. tmp.m = (Money) this.m.clone();
      8. return tmp;
      9. // return super.clone();
      10. }

      3.person调用clone方法返回值tmp(也就是新的money)给person2

      Person person2 = (Person) person.clone();

      这样修改

      person2.m.money = 180;

      不会影响person1.m.money了

      总结

      深拷贝和浅拷贝不是那方法来决定

      是取决于你代码的实现

  • 相关阅读:
    一文解决 Go 安装和常用环境变量的配置
    项目全生命周期阶段检查单
    060:mapboxGL点击某处,通过flyTo,以动画的形式聚焦到此点
    PT Application Inspector 现支持集成开发环境
    apollo lidar 模块3.0&6.0
    gland 管理 go 依赖包
    算法效率的计算
    Docker启动mysql服务
    layui2.9.7-入门初学
    第十章:枚举类与注解
  • 原文地址:https://blog.csdn.net/panpanaa/article/details/127929898