• JAVA 抽象类和接口——万字理解


    目录

    一、抽象类的理解

    二、接口

    1、接口的特点

    2、接口的使用

    3、实现多接口

    4、接口间的继承

    5、抽象类和接口的区别

    6、Object类

    7、对象比较equals方法

    8、hashcode方法

    9、接口使用实例

    1)Comparable

    2)Comparator

    3)实现对象冒泡排序

    10、自定义对象克隆


    一、抽象类的理解

    理解

    抽象方法:在父类不用具体实现,但在子类必须重写

    1. abstract class Shape{
    2. // 抽象方法,在父类不用具体实现,在子类重写
    3. public abstract void draw();//有抽象方法就必须是抽象类
    4. }

    内容

    抽象类的特点

    • 抽象类 使用abstract修饰类
    • 抽象类当中 1可以包含普通类所能包含的成员
    • 抽象类和普通类不一样的是, 抽象类当中可以包含抽象方法
    1. // 抽象类:被abstract修饰的类
    2. public abstract class Shape {
    3. // 抽象方法:被abstract修饰的方法,没有方法体
    4. abstract public void draw();
    5. abstract void calcArea();
    6. // 抽象类也是类,也可以增加普通方法和属性
    7. public double getArea(){
    8. return area;
    9. }
    10. protected double area; // 面积
    11. }
    • 抽象方法是使用abstract修饰的。 这个方法没有具体的实现
    • 不能实例化抽象类 new
    1. Shape shape = new Shape();
    2. // 编译出错
    3. Error:(30, 23) java: Shape是抽象的; 无法实例化
    • 抽象列存在的最大的意义 就是为了被继承。
    • 继承抽象类后必须重写他的抽象方法
    1. public abstract class Triangle extends Shape {
    2. private double a;
    3. private double b;
    4. private double c;
    5. @Override
    6. public void draw() {
    7. System.out.println("三角形:a = "+a + " b = "+b+" c = "+c);
    8. }
    9. }
    • 如果一个抽象类A继承了一个抽象类B,此时A当中不需要重写B中的抽象方法 但是如果A再被普通类继承,就需要重写。
    1. abstract class Shape{
    2. // 抽象方法,在父类不用具体实现,在子类重写
    3. public abstract void draw();//有抽象方法就必须是抽象类
    4. }
    5. abstract class A extends Shape{
    6. // 没有对父类Shape的抽象方法进行重写,但是也不会出错
    7. }

     

    • 抽象方法不能是私有的 ,static也不可以,也就是要满足重写的规则
    • final不可以 他和abstract是矛盾的
    • 抽象类当中可以有构造方法。 为了方便子类能够调用, 来初始化抽象类当中的成员

    二、接口

    理解

    多个类的公共规范,是一种引用数据类型

    接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口

    1. public interface 接口名称{
    2. // 抽象方法
    3. public abstract void method1(); // public abstract 是固定搭配,可以不写
    4. public void method2();
    5. abstract void method3();
    6. void method4(); //最简洁写法
    7. // 注意:在接口中上述写法都是抽象方法
    8. }

    1、接口的特点

    内容

    特点:

    • 1.使用interface来修饰接口

    • 2.接口当中的成员方法, 不能有具体的实现 [public]

      1. 抽象方法:默认是public abstract的方法,其他修饰符都会报错
    1. public interface USB {
    2. // Error:(4, 18) java: 此处不允许使用修饰符private
    3. private void openDevice();
    4. void closeDevice();
    5. }

                       2. JDK1.8开始 允许有可以实现的方法, 但是这个方法只能是由default修饰的。

                       3. 可以实现有一个静态方法
     

    • 3.成员变量默认是public static final修饰的
    1. public interface USB {
    2. double brand = 3.0; // 默认被:final public static修饰
    3. void openDevice();
    4. void closeDevice();
    5. }
    6. public class TestUSB {
    7. public static void main(String[] args) {
    8. System.out.println(USB.brand); // 可以直接通过接口名访问,说明是静态的
    9. // 编译报错:Error:(12, 12) java: 无法为最终变量brand分配值
    10. USB.brand = 2.0; // 说明brand具有final属性
    11. }
    12. }
    • 4.接口不能被实例化
    1. public class TestUSB {
    2. public static void main(String[] args) {
    3. USB usb = new USB();
    4. }
    5. }
    6. // Error:(10, 19) java: day20210915.USB是抽象的; 无法实例化
    • 5.类和接口之间采用implements来实现多个接口
    • 6.子类重写抽象方法, 必须加上public。
    1. public interface USB {
    2. void openDevice(); // 默认是public的
    3. void closeDevice(); // 默认是public的
    4. }
    5. public class Mouse implements USB {
    6. @Override
    7. void openDevice() {
    8. System.out.println("打开鼠标");
    9. }
    10. // ...
    11. }
    12. // 编译报错,重写USB中openDevice方法时,不能使用默认修饰符
    13. // 正在尝试分配更低的访问权限; 以前为public
    • 7.接口中不能有静态代码块和构造方法
    1. public interface USB {
    2. // 编译失败
    3. public USB(){
    4. }
    5. { } // 编译失败
    6. void openDevice();
    7. void closeDevice();
    8. }
    • 8.如果你不想实现接口的方法, 那么就把这个类定义为抽象类。 但如果这个类被其他类继承 那么必须重写
    • 9.一个类 可以实现多个接口。使用implements用逗号隔开【解决了多继承的问题】

    2、接口的使用

    理解

    接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法

    1. class 类名称 implements 接口名称 {
    2. // ...
    3. }

    内容

    **注意:子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。 **

    实现笔记本电脑使用USB鼠标、USB键盘的例子

    1. USB接口:包含打开设备、关闭设备功能
    2. 笔记本类:包含开机功能、关机功能、使用USB设备功能
    3. 鼠标类:实现USB接口,并具备点击功能
    4. 键盘类:实现USB接口,并具备输入功能

    注意:

    1. if(usb instanceof Mouse){
    2. Mouse mouse = (Mouse)usb;
    3. mouse.click();
    4. }

    需要将usb强转成Mouse类

    因为click行为在Mouse类里面

    代码

    1. // USB接口
    2. public interface USB {
    3. void openDevice();
    4. void closeDevice();
    5. }
    6. // 鼠标类,实现USB接口
    7. public class Mouse implements USB {
    8. @Override
    9. public void openDevice() {
    10. System.out.println("打开鼠标");
    11. }
    12. @Override
    13. public void closeDevice() {
    14. System.out.println("关闭鼠标");
    15. }
    16. public void click(){
    17. System.out.println("鼠标点击");
    18. }
    19. }
    20. //键盘类,实现USB接口
    21. public class KeyBoard implements USB {
    22. @Override
    23. public void openDevice() {
    24. System.out.println("打开键盘");
    25. }
    26. @Override
    27. public void closeDevice() {
    28. System.out.println("关闭键盘");
    29. }
    30. public void inPut(){
    31. System.out.println("键盘输入");
    32. }
    33. }
    34. // 笔记本类:使用USB设备
    35. public class Computer {
    36. public void powerOn(){
    37. System.out.println("打开笔记本电脑");
    38. }
    39. public void powerOff(){
    40. System.out.println("关闭笔记本电脑");
    41. }
    42. public void useDevice(USB usb){
    43. usb.openDevice();
    44. if(usb instanceof Mouse){
    45. Mouse mouse = (Mouse)usb;
    46. mouse.click();
    47. }
    48. else if(usb instanceof KeyBoard){
    49. KeyBoard keyBoard = (KeyBoard)usb;
    50. keyBoard.inPut();
    51. }
    52. usb.closeDevice();
    53. }
    54. }

    3、实现多接口

    理解

    父类的继承(生物共性用继承) 重写行为(行为动作共性用接口) 目的是解决JAVA没办法实现多继承的情况

    内容

            在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承,但是一个类可以实现多个接口。下面通过类来表示一组动物 注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类。

    提示: IDEA 中使用 ctrl + i 快速实现接口

    代码

    1. interface IFlying{
    2. void flying();
    3. }
    4. interface ISwimming{
    5. void swimming();
    6. }
    7. interface IRunning{
    8. void running();
    9. }
    10. class Animal{
    11. public String name;
    12. public int age;
    13. // 构造方法
    14. public Animal(String name, int age) {
    15. this.name = name;
    16. this.age = age;
    17. }
    18. // 实例方法
    19. public void eat(){
    20. System.out.println("吃饭");
    21. }
    22. }
    23. class Dog extends Animal implements IRunning,ISwimming{
    24. // 父类的继承(生物共性用继承)
    25. public Dog(String name, int age) {
    26. super(name, age);
    27. }
    28. // 重写行为(行为动作共性用接口)
    29. @Override
    30. public void swimming() {
    31. System.out.println(name + "正在游泳");
    32. }
    33. @Override
    34. public void running() {
    35. System.out.println(name + "正在跑");
    36. }
    37. // 甚至可以重写父类的行为(动态绑定)
    38. @Override
    39. public void eat() {
    40. System.out.println(name+"正在吃狗粮");
    41. }
    42. }
    43. class Bird extends Animal implements IFlying{
    44. public Bird(String name, int age) {
    45. super(name, age);
    46. }
    47. @Override
    48. public void flying() {
    49. System.out.println(name + "正在飞!");
    50. }
    51. }
    52. class Duck extends Animal implements IFlying,ISwimming,IRunning{
    53. public Duck(String name, int age) {
    54. super(name, age);
    55. }
    56. @Override
    57. public void flying() {
    58. System.out.println(name + "正在飞!");
    59. }
    60. @Override
    61. public void swimming() {
    62. System.out.println(name + "正在游泳");
    63. }
    64. @Override
    65. public void running() {
    66. System.out.println(name + "正在跑");
    67. }
    68. }
    69. class Robot implements IRunning{
    70. @Override
    71. public void running() {
    72. System.out.println("机器人正在跑");
    73. }
    74. }
    75. public class Test3 {
    76. public static void walk(IRunning iRunning){
    77. iRunning.running();
    78. }
    79. // 实现多态
    80. public static void func(Animal animal){
    81. animal.eat();
    82. }
    83. public static void main(String[] args) {
    84. walk(new Dog("Huang",10) );
    85. walk(new Duck("Ming",10) );
    86. // 接口构造行为甚至可以————只要具备这个行为的东西就可以触发,不用继承
    87. walk(new Robot());
    88. System.out.println("======================");
    89. func(new Dog("Huang",10));
    90. func(new Duck("Ming",10));
    91. }
    92. }

    4、接口间的继承

    理解

            在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的。

    接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字

    内容

            通过接口继承创建一个新的接口 IAmphibious 表示 "两栖的". 此时实现接口创建的 Frog 类, 就继续要实现 run 方 法, 也需要实现 swim 方法.
    接口间的继承相当于把多个接口合并在一起

    代码

    1. interface IRunning {
    2. void run();
    3. }
    4. interface ISwimming {
    5. void swim();
    6. }
    7. // 两栖的动物, 既能跑, 也能游
    8. interface IAmphibious extends IRunning, ISwimming {
    9. }
    10. class Frog implements IAmphibious {
    11. ...
    12. }

    5、抽象类和接口的区别

    理解

            核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法.

     


    6、Object类

    理解

    Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父类。即所有类的对象都可以使用Object的引用进行接收 使用Object接收所有类的对象

    1. class Person{}
    2. class Student{}
    3. public class Test {
    4. public static void main(String[] args) {
    5. function(new Person());
    6. function(new Student());
    7. }
    8. public static void function(Object obj) {
    9. System.out.println(obj);
    10. }
    11. }
    12. //执行结果:
    13. Person@1b6d3586
    14. Student@4554617c

    7、对象比较equals方法

    理解

    在Java中,==进行比较时:

    a.如果==左右两侧是基本类型变量,比较的是变量中值是否相同

    b.如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同

    c.如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的:

    Person类重写equals方法后,然后比较:

    1. class Person{
    2. ...
    3. @Override
    4. public boolean equals(Object obj) {
    5. if (obj == null) {
    6. return false ;
    7. } if(
    8. this == obj) {
    9. return true ;
    10. } // 不是Person类对象
    11. if (!(obj instanceof Person)) {
    12. return false ;
    13. }
    14. Person person = (Person) obj ; // 向下转型,比较属性值
    15. return this.name.equals(person.name) && this.age==person.age ;
    16. }
    17. }

    内容

            比较对象中内容是否相同的时候,一定要重写equals方法


    8、hashcode方法

    理解

    hashcode方法源码:

    我们认为两个名字相同,年龄相同的对象,将存储在同一个位置,如果不重写hashcode()方法,我们可以来看示例

    1. class Person {
    2. public String name;
    3. public int age;
    4. public Person(String name, int age) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. }
    9. public class TestDemo4 {
    10. public static void main(String[] args) {
    11. Person per1 = new Person("gaobo", 20) ;
    12. Person per2 = new Person("gaobo", 20) ;
    13. System.out.println(per1.hashCode());
    14. System.out.println(per2.hashCode());
    15. }
    16. }
    17. //执行结果
    18. 460141958
    19. 1163157884

    注意事项:两个对象的hash值不一样。

    重写hashcode()方法再来看看

    1. class Person {
    2. public String name;
    3. public int age;
    4. public Person(String name, int age) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. @Override
    9. public int hashCode() {
    10. return Objects.hash(name, age);
    11. }
    12. }
    13. public class TestDemo4 {
    14. public static void main(String[] args) {
    15. Person per1 = new Person("gaobo", 20) ;
    16. Person per2 = new Person("gaobo", 20) ;
    17. System.out.println(per1.hashCode());
    18. System.out.println(per2.hashCode());
    19. }
    20. }
    21. //执行结果
    22. 460141958
    23. 460141958

    **注意事项:哈希值一样。 **

    内容

    **结论:

    1. hashcode方法用来确定对象在内存中存储的位置是否相同
    2. 事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

    9、接口使用实例

    理解

    给对象数组排序

            按照我们之前的理解, 数组我们有一个现成的 sort 方法, 能否直接使用这个方法呢?

    1. // 原方法无法成功调用比较,会报错
    2. public static void main3(String[] args) {
    3. Student[] students = new Student[3];
    4. students[0] = new Student("ccc",10);
    5. students[1] = new Student("hello",40);
    6. students[2] = new Student("gbc",5);
    7. Arrays.sort(students);
    8. System.out.println(Arrays.toString(students));
    9. }

    解决方案:

    1. 如果我们以后自定义的类型 一定要记住 如果比较大小那么必须要让这个类具备可以比较的功能。 此时可以选择实现接口 Comparable<...> 入侵性强
    2. 需要更换时:此时 需要根据姓名比较大小,就要用 比较器 Comparator<...> 入侵性比较弱

    内容

     

    1)Comparable

    Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法

    1. // Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法
    2. class Student implements Comparable{
    3. public String name;
    4. public int age;
    5. // 构造
    6. public Student(String name, int age) {
    7. this.name = name;
    8. this.age = age;
    9. }
    10. // 重写字符串输出
    11. @Override
    12. public String toString() {
    13. return "Student{" +
    14. "name='" + name + '\'' +
    15. ", age=" + age +
    16. '}';
    17. }
    18. // Comparable 重写比较方法 比较以年龄为准
    19. @Override
    20. public int compareTo(Student o) {
    21. if(this.age - o.age > 0) { // 以 调用该方法的age 与 引用的o的age作比较
    22. return 1;
    23. }else if(this.age - o.age < 0) {
    24. return -1;
    25. }else {
    26. return 0;
    27. }
    28. //return 0;
    29. }
    30. }
    31. public class TEST {
    32. // **student1 调用compareTo改写后的比较方法 并且引用 student2 (以年龄比较)**
    33. public static void main4(String[] args) {
    34. Student student1 = new Student("ccc",10);
    35. Student student2 = new Student("hello",40);
    36. if(student1.compareTo(student2) > 0) {
    37. System.out.println("student1 > student2");
    38. }else {
    39. System.out.println("student1 < student2");
    40. }
    41. }
    42. }

    2)Comparator

    Comparator 比较器 ,类似提供一个比较模板,放在比较方法的后边

    1. // Comparator 比较器 ,类似提供一个比较模板,放在比较方法的后边
    2. class AgeComparator implements Comparator {
    3. @Override
    4. public int compare(Student o1, Student o2) {
    5. return o1.age - o2.age;
    6. }
    7. }
    8. class NameComparator implements Comparator {
    9. @Override
    10. public int compare(Student o1, Student o2) {
    11. return o1.name.compareTo(o2.name);
    12. }
    13. }
    14. public class TEST {
    15. // 可以直接调用比较器中的方法进行比较,只需要引用比较双方的对象
    16. public static void main6(String[] args) {
    17. Student student1 = new Student("ccc",10);
    18. Student student2 = new Student("hello",40);
    19. AgeComparator ageComparator = new AgeComparator();
    20. if(ageComparator.compare(student1,student2) > 0) {
    21. System.out.println("student1 > student2");
    22. }else {
    23. System.out.println("student1 < student2");
    24. }
    25. }
    26. // new一个比较器对象,放入sort后边,可以达到自己的比较效果
    27. public static void main5(String[] args) {
    28. Student[] students = new Student[3];
    29. students[0] = new Student("ccc",10);
    30. students[1] = new Student("hello",40);
    31. students[2] = new Student("gbc",5);
    32. //AgeComparator ageComparator = new AgeComparator();
    33. NameComparator nameComparator = new NameComparator();
    34. Arrays.sort(students,nameComparator);
    35. System.out.println(Arrays.toString(students));
    36. }
    37. }

    3)实现对象冒泡排序

    1. public class TEST {
    2. // 自定义的类想要比较,必须实现比较接口,所以冒泡传入的应该是已经完成接口化的Comparable[]数组类型
    3. public static void bubbleSort(Comparable[] array) {
    4. for (int i = 0; i < array.length-1; i++) {
    5. for (int j = 0; j < array.length-1-i; j++) {
    6. if(array[j].compareTo(array[j+1]) > 0) { // 不能直接大小进行比较,因为他是一个对象,要引用他本身的方法去调用
    7. Comparable tmp = array[j]; // 创建存储类型也要是Comparable类型
    8. array[j] = array[j+1];
    9. array[j+1] = tmp;
    10. }
    11. }
    12. }
    13. }
    14. // 提供比较的算法
    15. public static void main(String[] args) {
    16. Student[] students = new Student[3];
    17. students[0] = new Student("ccc",10);
    18. students[1] = new Student("hello",40);
    19. students[2] = new Student("gbc",5);
    20. bubbleSort(students);
    21. System.out.println(Arrays.toString(students));
    22. }
    23. }

    代码

    1. package demo1;
    2. import java.util.Arrays;
    3. import java.util.Comparator;
    4. class Student implements Comparable{ // 利用范型改造比较的方法
    5. public String name;
    6. public int age;
    7. // 构造
    8. public Student(String name, int age) {
    9. this.name = name;
    10. this.age = age;
    11. }
    12. // 重写字符串输出
    13. @Override
    14. public String toString() {
    15. return "Student{" +
    16. "name='" + name + '\'' +
    17. ", age=" + age +
    18. '}';
    19. }
    20. // Comparable 重写比较方法 比较以年龄为准
    21. @Override
    22. public int compareTo(Student o) {
    23. if(this.age - o.age > 0) { // 以 调用该方法的age 与 引用的o的age作比较
    24. return 1;
    25. }else if(this.age - o.age < 0) {
    26. return -1;
    27. }else {
    28. return 0;
    29. }
    30. //return 0;
    31. }
    32. }
    33. // Comparator 比较器 ,类似提供一个比较模板,放在比较方法的后边
    34. class AgeComparator implements Comparator {
    35. @Override
    36. public int compare(Student o1, Student o2) {
    37. return o1.age - o2.age;
    38. }
    39. }
    40. class NameComparator implements Comparator {
    41. @Override
    42. public int compare(Student o1, Student o2) {
    43. return o1.name.compareTo(o2.name);
    44. }
    45. }
    46. public class TEST {
    47. // 自定义的类想要比较,必须实现比较接口,所以冒泡传入的应该是已经完成接口化的Comparable[]数组类型
    48. public static void bubbleSort(Comparable[] array) {
    49. for (int i = 0; i < array.length-1; i++) {
    50. for (int j = 0; j < array.length-1-i; j++) {
    51. if(array[j].compareTo(array[j+1]) > 0) { // 不能直接大小进行比较,因为他是一个对象,要引用他本身的方法去调用
    52. Comparable tmp = array[j]; // 创建存储类型也要是Comparable类型
    53. array[j] = array[j+1];
    54. array[j+1] = tmp;
    55. }
    56. }
    57. }
    58. }
    59. // 提供比较的算法
    60. public static void main(String[] args) {
    61. Student[] students = new Student[3];
    62. students[0] = new Student("ccc",10);
    63. students[1] = new Student("hello",40);
    64. students[2] = new Student("gbc",5);
    65. bubbleSort(students);
    66. System.out.println(Arrays.toString(students));
    67. }
    68. // 可以直接调用比较器中的方法进行比较,只需要引用比较双方的对象
    69. public static void main6(String[] args) {
    70. Student student1 = new Student("ccc",10);
    71. Student student2 = new Student("hello",40);
    72. AgeComparator ageComparator = new AgeComparator();
    73. if(ageComparator.compare(student1,student2) > 0) {
    74. System.out.println("student1 > student2");
    75. }else {
    76. System.out.println("student1 < student2");
    77. }
    78. }
    79. // new一个比较器对象,放入sort后边,可以达到自己的比较效果
    80. public static void main5(String[] args) {
    81. Student[] students = new Student[3];
    82. students[0] = new Student("ccc",10);
    83. students[1] = new Student("hello",40);
    84. students[2] = new Student("gbc",5);
    85. //AgeComparator ageComparator = new AgeComparator();
    86. NameComparator nameComparator = new NameComparator();
    87. Arrays.sort(students,nameComparator);
    88. System.out.println(Arrays.toString(students));
    89. }
    90. // student1 调用compareTo改写后的比较方法 并且引用 student2 (以年龄比较)
    91. public static void main4(String[] args) {
    92. Student student1 = new Student("ccc",10);
    93. Student student2 = new Student("hello",40);
    94. if(student1.compareTo(student2) > 0) {
    95. System.out.println("student1 > student2");
    96. }else {
    97. System.out.println("student1 < student2");
    98. }
    99. }
    100. // 基本的字符串比较方法
    101. public static void main2(String[] args) {
    102. String[] strings = {"abc","hello","bcd"};
    103. Arrays.sort(strings);
    104. System.out.println(Arrays.toString(strings));
    105. }
    106. // 原方法无法成功调用比较,会报错
    107. public static void main3(String[] args) {
    108. Student[] students = new Student[3];
    109. students[0] = new Student("ccc",10);
    110. students[1] = new Student("hello",40);
    111. students[2] = new Student("gbc",5);
    112. Arrays.sort(students);
    113. System.out.println(Arrays.toString(students));
    114. }
    115. // 正常数组比较
    116. public static void main1(String[] args) {
    117. int[] array = {1,4,2,7,3,8,5};
    118. Arrays.sort(array);
    119. System.out.println(Arrays.toString(array));
    120. }
    121. }

    10、自定义对象克隆

    理解

    Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出CloneNotSupportedException 异常

    内容

    1、实现克隆接口

    implement Cloneable{}
    

    2、重写克隆方法

    1. @Override
    2. protected Object clone() throws CloneNotSupportedException {
    3. //return super.clone();
    4. Person tmp = (Person) super.clone();
    5. tmp.money = (Money) this.money.clone();
    6. return tmp;
    7. }

    3、解决异常,以及强转类型

    1. Person tmp = (Person) super.clone();// super调用后的类型是Object的,需要强转
    2. tmp.money = (Money) this.money.clone();

    代码

    1. class Money implements Cloneable{
    2. public double m = 12.5;
    3. // 调用父类的clone接口
    4. @Override
    5. protected Object clone() throws CloneNotSupportedException {
    6. return super.clone();
    7. }
    8. }
    9. class Person implements Cloneable{
    10. public int id;
    11. public Money money = new Money();
    12. // 重写克隆方法(深拷贝)
    13. @Override
    14. protected Object clone() throws CloneNotSupportedException {
    15. //return super.clone();
    16. Person tmp = (Person) super.clone(); // 调用父类的克隆方法先浅拷贝一个副本
    17. tmp.money = (Money) this.money.clone();// 将副本里的元素money类调用自己的clone方法也进行拷贝处理(因为money类中已经调用了父类的拷贝方法)
    18. return tmp;
    19. }
    20. @Override
    21. public String toString() {
    22. return "Person{" +
    23. "id=" + id +
    24. '}';
    25. }
    26. }
    27. public class Test2 {
    28. public static void main(String[] args) throws CloneNotSupportedException{
    29. Person person = new Person();
    30. Person person2 = (Person)person.clone();
    31. person2.money.m = 1999;
    32. System.out.println("person:"+person.money.m);
    33. System.out.println("person2:"+person2.money.m);
    34. }
    35. }
  • 相关阅读:
    from表单、css选择器、css组合器、字体样式、背景属性、边框设置、display设置
    网络安全(黑客)自学
    1024程序员狂欢节特辑 | 聊一聊Halcon中的3D手眼标定
    设计模式之解释器模式
    simucpp系列教程(7)坟墓
    mp 代码生成器
    【实训项目】你好,教练-校园私教平台的设计与开发
    丁鹿学堂:前端异步进阶之Rxjs的使用
    【PostgreSQL内核学习(十七)—— (AutoAnalyze)】
    Redis优化之持久化和性能管理
  • 原文地址:https://blog.csdn.net/qq_35056587/article/details/126892308