Java面向对象编程,包、继承、组合、多态、抽象类、接口

了解java面向对象编程,了解基本语法

1.包

包 (package) 是组织类的一种方式.使用包的主要目的是保证类的唯一性.
import
导入包中的类

import java.util.Date;
public class Test {
    
    
    public static void main(String[] args) {
    
    
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
   }
}

如果需要使用 java.util 中的其他类, 可以使用 import java.util.*

import java.util.*;
public class Test {
    
    
    public static void main(String[] args) {
    
    
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
   }
}

但是我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况.
比如 java.sql 中的类 java.sql.Datejava.util 中的类 java.util.Date

import java.util.*;
import java.sql.*;
public class Test {
    
    
    public static void main(String[] args) {
    
    
        // util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
        Date date = new Date();
        System.out.println(date.getTime());
   }
}

这样就会编译失败,Date不明确。应该:

import java.util.*;
import java.sql.*;
public class Test {
    
    
    public static void main(String[] args) {
    
    
        java.util.Date date = new java.util.Date();
        System.out.println(date.getTime());
   }
}

使用 import static 可以导入包中的静态的方法和字段.

import static java.lang.Math.*;
public class Test {
    
    
    public static void main(String[] args) {
    
    
        double x = 30;
        double y = 40;
        // 静态导入的方式写起来更方便一些. 
        // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        double result = sqrt(pow(x, 2) + pow(y, 2));
        System.out.println(result);
   }
}

将类放到包中的基本规则

  1. 在文件的最上方加上一个 package 语句指定该代码在哪个包中.
  2. 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.cqupt.demo1 .
  3. 包名要和代码路径相匹配. 例如创建 com.cqupt.demo1 的包, 那么会存在一个对应的路径 com/cqupt/demo1 来存储代码.
  4. 如果一个类没有 package 语句, 则该类被放到一个默认包中.

2.包的访问权限控制

我们已经了解了类中的 public 和 private. private 中的成员只能被类的内部使用.
如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使用.(包访问权限)

3.继承

在这里插入图片描述
语法:

class 子类 extends 父类 {
    
     
 
} 
class Animal {
    
    
    public String name;
    public int age;
    private int count;

    public Animal(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public void eat() {
    
    
        System.out.println("eat()");
    }
}

class Dog extends Animal {
    
    
    public Dog(String name, int age) {
    
    
        super(name, age);
    }
}

class Bird extends Animal {
    
    
    public Bird(String name, int age,String swing) {
    
    
        super(name, age);
        this.swing=swing;
    }

    public String swing;

    public void fly() {
    
    
        System.out.println(name + "fly()"+swing);
    }
}

public class TestDemo {
    
    
    public static void main(String[] args) {
    
    
        Animal animal=new Dog("jenny",23);//父类引用  引用  子类对象

    }
    public static void main1(String[] args) {
    
    
        Dog dog = new Dog("jenny",22);
        System.out.println(dog.name);
        dog.eat();

        Bird bird = new Bird("james",45,"我要的飞翔");
        System.out.println(bird.name);
        bird.eat();
        bird.fly();
    }

}

在这里插入图片描述

在这里插入图片描述

1. 使用 extends 指定父类.
2. Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
3. 子类会继承父类的所有 public 的字段和方法.
4. 对于父类的 private 的字段和方法, 子类中是无法访问的.
5. 子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用

4.protected 关键字

刚才我们发现, 如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 “封装” 的初衷.
两全其美的办法就是 protected 关键字:
对于类的调用者来说, protected 修饰的字段和方法是不能访问的
对于类的 子类 和 同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的

总结::Java 中对于字段和方法共有四种访问权限

  1. private: 类内部能访问, 类外部不能访问
  2. 默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
  3. protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
  4. public : 类内部和类的调用者都能访问

在这里插入图片描述

5.final 关键字

在这里插入图片描述

6.组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。

组合表示 has - a 语义
一个学校中 “包含” 若干学生和教师.。

public class Student {
    
     
 ... 
} 
public class Teacher {
    
     
 ... 
} 
public class School {
    
     
 public Student[] students; 
 public Teacher[] teachers; 
} 

7.多态

使用多态的好处是什么?

  1. 类调用者对类的使用成本进一步降低.
    封装是让类的调用者不需要知道类的实现细节.
    多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可.
    因此, 多态可以理解成是封装的更进一步, 让类调用者对类的使用成本进一步降低
  2. 够降低代码的 “圈复杂度”, 避免使用大量的 if - else
  3. 可扩展能力更强.
class Shape {
    
    
    public void draw() {
    
    

    }
}

class Rect extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("◇");
    }
}

class Flower extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("❀");
    }
}

class Triangle extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("△");
    }
}

class Circle extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("●");
    }
}


public class Test {
    
    
    public static void main(String[] args) {
    
    
        Rect rect = new Rect();
        Flower flower = new Flower();
        Triangle triangle = new Triangle();
        Circle circle=new Circle();
        Shape[] shapes = {
    
    rect, flower, triangle, circle};
        for (Shape shape:shapes) {
    
    
            shape.draw();
        }
    }
    public static void drawMap(Shape shape) {
    
    
        shape.draw();
    }
    //多态:不同对象调用同一个方法产生不同的结果效果
    public static void main1(String[] args) {
    
    
        Rect rect = new Rect();
        drawMap(rect);
        Flower flower = new Flower();
        drawMap(flower);
        Triangle triangle = new Triangle();
        drawMap(triangle);
    }
}

在这里插入图片描述

7.1向上转型

public static void main1(String[] args) {
    
    
        //向上转型
        Animal animal = new Dog("jenny", 23);//父类引用  引用  子类对象
        Dog dog = new Dog("james", 55);
        func(dog);
    }

此时 animal 是一个父类 (Animal) 的引用, 指向一个子类 (Dog) 的实例. 这种写法称为 向上转型.

在这里插入图片描述

在这里插入图片描述

7.2动态绑定

//动态绑定
public static void main2(String[] args) {
    
    
    Animal animal = new Dog("jenny", 23);//父类引用  引用  子类对象
    animal.eat();

    Animal animal2 = new Bird("jjj", 45, "ijh");
    animal2.eat();
    //通过父类的引用   只能访问父类自己的成员
    System.out.println(animal2.name);
}

在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定

在这里插入图片描述

7.3方法重写

子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override)

注意:

  1. 重写和重载完全不一样. 不要混淆(思考一下, 重载的规则是啥?)
  2. 普通方法可以重写, static 修饰的静态方法不能重写
  3. 重写中子类的方法的访问权限不能低于父类的方法访问权限.
  4. 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外)
class Animal {
    
    
    public String name;
    public int age;
    private int count;

    public Animal(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public void eat() {
    
    
        System.out.println(name + "eat()");
    }
}

class Dog extends Animal {
    
    
    public Dog(String name, int age) {
    
    
        super(name, age);
    }

    @Override
    public void eat() {
    
    
        System.out.println(name + " 狼吞虎咽的 eat()");
    }

    //重载
    public void func(int a) {
    
    
        System.out.println(a);
    }

    public void func(int a, int b) {
    
    
        System.out.println(a + b);
    }

    public void func(int a, int b, double n) {
    
    
        System.out.println(a + b + n);
    }

}

class Bird extends Animal {
    
    
    public Bird(String name, int age, String swing) {
    
    
        super(name, age);
        this.swing = swing;
    }

    public String swing;

    public void fly() {
    
    
        System.out.println(name + "fly()" + swing);
    }
}

Dog类中重写父类Animal中的eat()方法.

7.4向下转型

向上转型是子类对象转成父类对象, 向下转型就是父类对象转成子类对象. 相比于向上转型来说, 向下转型没那么常见.不是很安全
在这里插入图片描述

在这里插入图片描述

7.5静态绑定

//重载
    public void func(int a) {
    
    
        System.out.println(a);
    }
    public void func(int a, int b) {
    
    
        System.out.println(a + b);
    }
    public void func(int a, int b, double n) {
    
    
        System.out.println(a + b + n);
    }
 //静态绑定
    public static void main3(String[] args) {
    
    
        Dog dog = new Dog("jenny", 34);
        dog.func(3);
        dog.func(2, 4);
        dog.func(4, 5, 3.88);
    }

在这里插入图片描述

7.6super 关键字

前面的代码中由于使用了重写机制, 调用到的是子类的方法. 如果需要在子类内部调用父类方法怎么办? 可以使用super 关键字.
在这里插入图片描述

7.7在构造方法中调用重写的方法(一个坑)

我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法. 并且在 B 的构造方法中调用 func

class B {
    
     
 public B() {
    
     
 // do nothing 
 func(); 
 } 
 public void func() {
    
     
 System.out.println("B.func()"); 
 } 
} 
class D extends B {
    
     
 private int num = 1; 
 @Override 
 public void func() {
    
     
 System.out.println("D.func() " + num); 
 } 
} 
public class Test {
    
     
 public static void main(String[] args) {
    
     
 D d = new D(); 
  } 
}

//运行结果:D.func()0
1. 构造 D 对象的同时, 会调用 B 的构造方法.
2. B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
3. 此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0

8.抽象类

  1. 包含抽象方法(没有具体实现的方法,被abstract修饰)的类
  2. 抽象类不能被实例化
  3. 不能被实例化,其实这个类只能被继承
  4. 抽象类中也可以包含普通的成员和方法
  5. 普通类,继承一个抽象类,普通类需要重写抽象类中所有的抽象方法
  6. 抽象类最大的作用就是被继承
  7. 如果抽象类B继承抽象类A,那么抽象类B可以不实现抽象父类A中的抽象方法
  8. 结合上一句,当B类被普通类继承,那么A和B这两个抽象类中的抽象方法必须在普通类重写
  9. 抽象类不能被final所修饰
  10. 抽象方法也不能被final修饰
abstract class Shape {
    
    
    public abstract void draw();//抽象方法
}

//如果抽象类B继承抽象类A,那么抽象类B可以不实现抽象父类A中的抽象方法
abstract class A extends Shape{
    
    
    public abstract void funcA();
}

//当B类被普通类继承,那么A和B这两个抽象类中的抽象方法必须在普通类重写
class B extends A{
    
    
    @Override
    public void draw() {
    
    
        
    }
    @Override
    public void funcA() {
    
    
        
    }
}

class Rect extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("◇");
    }
}

class Flower extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("❀");
    }
}

class Triangle extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("△");
    }
}

class Circle extends Shape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("●");
    }
}

public class Test {
    
    
    //动态绑定
    public static void drawMap(Shape shape){
    
    
        shape.draw();
    }
    public static void main(String[] args) {
    
    
        //Shape shape=new Shape();//error,抽象类不能被实例化
        Shape shape=new Rect();//抽象类可以发生向上转型,子类对象赋值给父类引用
        drawMap(shape);//动态绑定
    }
}

抽象类的作用

  1. 抽象类存在的最大意义就是为了被继承.
  2. 抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法。

9.接口

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量。

  1. 使用interface实现
  2. 接口中的方法不能有具体实现;如果要具体实现,在前面加default来修饰这个方法。
  3. 接口中可以有static方法
  4. 里面所有方法默认public的,
  5. 抽象方法默认是public abstract
  6. 接口不能被实例化
  7. 接口和类之间用implements
  8. 当类实现接口,就要重写接口中的抽象方法
  9. 接口中的成员变量默认是由public static final修饰
  10. 当一个类实现一个接口之后,重写接口中的方法,方法前面必须加public
  11. 一个类可以通过extends继承抽象类或者普通类,但是只能继承一个;同时可通过implements实现多个接口,接口之间通过’,'隔开
  12. 接口接口之间通过extends来拓展;当一个类实现一个接口C,但是接口C又拓展接口D,那么 这个类要重写接口C和D中所有的方法
interface IShape {
    
    
    public abstract void draw();//抽象方法

   /* default public void func() {
        System.out.println("ffff");
    }

    default public void func2() {
        System.out.println("4332");
    }

    public static void funcStatic() {
        System.out.println("sat");
    }*/
}

//当类实现接口,就要重写接口中的抽象方法
class Rect implements IShape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("◇");
    }
}

class Flower implements IShape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("❀");
    }
}

class Triangle implements IShape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("△");
    }
}

class Circle implements IShape {
    
    
    @Override
    public void draw() {
    
    
        System.out.println("●");
    }
}


public class Test {
    
    
    public static void drawMap(IShape iShape) {
    
    
        iShape.draw();
    }

    //动态绑定
    public static void main(String[] args) {
    
    
        Rect rect = new Rect();
        Flower flower = new Flower();
        drawMap(rect);
        drawMap(flower);
    }

    public static void main1(String[] args) {
    
    
        //IIShape IIShape=new IIShape();//error,不能被实例化
        IShape IShape = new Rect();
        IShape.draw();
    }
}

在这里插入图片描述

接口中只能包含抽象方法. 对于字段来说,接口中只能包含静态常量(final static).

interface IA {
    
    
    public static final int A = 10;//成员变量默认是常量
    int B = 10;//public static final
    void funcA();//public abstract
}

class A implements IA{
    
    
    @Override
    public void funcA() {
    
    //子类重写父类的方法,必须加public,
        // 子类的访问权限范围大于等于父类,父类默认是public
        System.out.println("A::funcA");
    }
}

8.1实现多个接口

interface IA {
    
    
    public static final int A = 10;//成员变量默认是常量
    int B = 10;//public static final

    void funcA();//public abstract
}

interface IB {
    
    
    void funcB();
}

abstract class BClass {
    
    

}

class AClass extends BClass implements IA, IB {
    
    
    @Override
    public void funcA() {
    
    
        System.out.println("A::funcA()");
        System.out.println(A);
    }

    @Override
    public void funcB() {
    
    
        System.out.println("A::funcB()");
    }
}

一个类可以通过extends继承抽象类或者普通类,但是只能继承一个;同时可通过implements实现多个接口,接口之间通过’,'隔开

8.2接口间的继承

接口接口之间通过implements来拓展;当一个类实现一个接口C,但是接口C又拓展接口D,那么 这个类要重写接口C和D中所有的方法

interface IA1 {
    
    
    void funcA();
}

interface IB1 extends IA1 {
    
    
    void funcB();
}

class C implements IB1 {
    
    
    @Override
    public void funcA() {
    
    
        System.out.println("IA1::funcA");
    }

    @Override
    public void funcB() {
    
    
        System.out.println("IB1::funcB");
    }
}

8.3接口的使用

class Animal {
    
    
    protected String name;

    public Animal(String name) {
    
    
        this.name = name;
    }
}

//不是所有的动物都可以飞
interface IFlying {
    
    
    void fly();
}

interface IRunning {
    
    
    void run();
}

interface ISwimming {
    
    
    void swim();
}

class Bird extends Animal implements IFlying {
    
    
    public Bird(String name) {
    
    
        super(name);
    }

    @Override
    public void fly() {
    
    
        System.out.println(this.name + "正在飞!");
    }
}

class Frog extends Animal implements IRunning, ISwimming {
    
    
    public Frog(String name) {
    
    
        super(name);
    }

    @Override
    public void run() {
    
    
        System.out.println(this.name + "正在跑");
    }

    @Override
    public void swim() {
    
    
        System.out.println(this.name + "正在游泳");
    }
}

class Duck extends Animal implements IRunning, IFlying, ISwimming {
    
    
    public Duck(String name) {
    
    
        super(name);
    }

    @Override
    public void fly() {
    
    
        System.out.println(this.name + "正在飞!");
    }

    @Override
    public void run() {
    
    
        System.out.println(this.name + "正在跑");
    }

    @Override
    public void swim() {
    
    
        System.out.println(this.name + "正在游泳");
    }
}

class Roobot implements IRunning{
    
    
    @Override
    public void run() {
    
    
        System.out.println("机器人在跑!");
    }
}
public class Test4 {
    
    
    public static void runFunc(IRunning iRunning) {
    
    
        iRunning.run();
    }

    public static void swimFunc(ISwimming iSwimming) {
    
    
        iSwimming.swim();
    }

    public static void flyFunc(IFlying iFlying) {
    
    
        iFlying.fly();
    }

    public static void main(String[] args) {
    
    
        runFunc(new Duck("鸭子"));
        runFunc(new Frog("青蛙"));
        new Roobot().run();
    }

    public static void main3(String[] args) {
    
    
        flyFunc(new Duck("鸭子"));
        flyFunc(new Bird("小鸟"));
    }

    public static void main2(String[] args) {
    
    
        swimFunc(new Duck("鸭子"));
        swimFunc(new Frog("青蛙"));
    }

    public static void main1(String[] args) {
    
    
        runFunc(new Duck("鸭子"));
        runFunc(new Frog("青蛙"));
    }
}

在这里插入图片描述

8.4常用接口

8.4.1Comparable

这个接口有很大的缺点,对类的侵入性非常强,不敢轻易改动。
如果自定义数据类型进行大小比较,一定要实现可比较的接口

class Student implements Comparable<Student> {
    
    
    public int age;
    public String name;
    public double score;

    public Student(int age, String name, double score) {
    
    
        this.age = age;
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                '}';
    }

    @Override
    //谁调用这个方法,这就是this
    public int compareTo(Student o) {
    
    
        /*if (this.age > o.age) {
            return 1;
        } else if (this.age == o.age) {
            return 0;
        } else {
            return -1;
        }*/
        //return this.age-o.age;//从小到大
        return o.age-this.age;//从大到小
    }
}

public class Test {
    
    
    public static void main2(String[] args) {
    
    
        Student students1 = new Student(12, "kkk", 99.8);
        Student students2 = new Student(32, "lll", 67.8);
        /*if(students1.compareTo(students2)>0){

        }*/
        System.out.println(students1.compareTo(students2));
    }

    public static void main(String[] args) {
    
    
        Student[] students = new Student[3];
        students[0] = new Student(12, "kkk", 99.8);
        students[1] = new Student(32, "lll", 67.8);
        students[2] = new Student(22, "zzz", 90.5);
        System.out.println(Arrays.toString(students));
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }

    public static void main1(String[] args) {
    
    
        int[] array = {
    
    1, 21, 3, 14, 5, 16};
        System.out.println(Arrays.toString(array));
        Arrays.sort(array);//从小到大排序
        System.out.println(Arrays.toString(array));
    }
}

在这里插入图片描述

8.4.2Comparator

对类的侵入性非常弱。

class Student {
    
    
    public int age;
    public String name;
    public double score;

    public Student(int age, String name, double score) {
    
    
        this.age = age;
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

class AgeComparator implements Comparator<Student> {
    
    
    @Override
    public int compare(Student o1, Student o2) {
    
    
        return o1.age - o2.age;
    }
}

class ScoreComparator implements Comparator<Student> {
    
    
    @Override
    public int compare(Student o1, Student o2) {
    
    
        return (int) (o1.score - o2.score);
    }
}

class NameComparator implements Comparator<Student> {
    
    
    @Override
    public int compare(Student o1, Student o2) {
    
    
        return o1.name.compareTo(o2.name);
    }
}

public class Test {
    
    
    //根据名字比较
    public static void main(String[] args) {
    
    
        Student[] students = new Student[3];
        students[0] = new Student(24, "kkk", 99.8);
        students[1] = new Student(12, "all", 87.8);
        students[2] = new Student(22, "zzz", 79.5);
        System.out.println(Arrays.toString(students));
        NameComparator nameComparator=new NameComparator();
        Arrays.sort(students, nameComparator);
        System.out.println(Arrays.toString(students));
    }

    //根据成绩
    public static void main4(String[] args) {
    
    
        Student[] students = new Student[3];
        students[0] = new Student(24, "kkk", 99.8);
        students[1] = new Student(12, "lll", 87.8);
        students[2] = new Student(22, "zzz", 79.5);
        System.out.println(Arrays.toString(students));
        ScoreComparator scoreComparator = new ScoreComparator();
        Arrays.sort(students, scoreComparator);
        System.out.println(Arrays.toString(students));
    }

    public static void main3(String[] args) {
    
    
        Student students1 = new Student(12, "kkk", 99.8);
        Student students2 = new Student(2, "lll", 67.8);
        /*if(students1.compareTo(students2)>0){

        }*/
        //System.out.println(students1.compareTo(students2));
        AgeComparator ageComparator = new AgeComparator();
        System.out.println(ageComparator.compare(students1, students2));
    }

    //根据年龄
    public static void main2(String[] args) {
    
    
        Student[] students = new Student[3];
        students[0] = new Student(24, "kkk", 99.8);
        students[1] = new Student(12, "lll", 87.8);
        students[2] = new Student(22, "zzz", 79.5);
        System.out.println(Arrays.toString(students));
        AgeComparator ageComparator = new AgeComparator();
        Arrays.sort(students, ageComparator);
        System.out.println(Arrays.toString(students));
    }
    }

在这里插入图片描述

8.4.3Clonable

创建对象的方式:

  1. new关键字
  2. clone()方法

对象实现cloneable接口,里面必须重写clone()方法:
在这里插入图片描述
Person进行克隆为person2
在这里插入图片描述

 Person person = new Person();
    person.age = 99;
    Person person2 = (Person) person.clone();
class Person implements Cloneable {
    
    
    public int age;

    public void eat() {
    
    
        System.out.println("吃!");
    }

    @Override
    public String toString() {
    
    
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }
}

public class TestDemo {
    
    
    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        Person person = new Person();
        person.age = 99;
        Person person2 = (Person) person.clone();
        System.out.println(person2);
        System.out.println("================");
        person2.age = 199;
        System.out.println(person);
        System.out.println(person2);
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_44721738/article/details/121255312