由Object.clone()引出的protected权限问题

本文深入探讨了Java中protected权限修饰符的使用细节及其在不同情况下的可见性规则,通过多个实例帮助理解基类与子类间受保护成员的访问限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Object.clone()

大家可能不太理解由Object.clone()而引出的protected权限问题这句话,那我们先看一段代码:
第一个类CloneClassOne

package com.ustc.sup;
public class CloneClassOne {
}

第二个类CloneClassTwo

package com.ustc.sup;

public class CloneClassTwo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        CloneClassOne one=new CloneClassOne();
        one.clone();
        Object object = new Object();
        object.clone(); 
    }
}

大家觉得这段代码有没有错呢?
答案:
one.clone();和object.clone();这两句提示The method clone() from the type Object is not visible

我们会有疑问:Object类是所有类的父类,那么为什么子类不能访问父类的protected修饰的方法呢?
与基类不在同一个包中的子类,只能访问自身从基类继承而来的受保护成员,而不能访问基类实例本身的受保护成员
例如:
父类Person在包com.ustc.sub;

package com.ustc.sub;

public class Person {

    protected int a = 4;

    protected int getA() {
        return a;
    }
}

子类Manager 、Student在包com.ustc.sup

package com.ustc.sup;

import com.ustc.sub.Person;

public class Student extends Person {

    int getB()
    {
        return getA();
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Manager m = new Manager();
        System.out.println(m.getB());
        System.out.println(m.getA());//error
    }

}
package com.ustc.sup;

import com.ustc.sub.Person;

public class Manager extends Person {

    int getB()
    {
        return getA();
    }
    public static void main(String[] argr) {
        Student s = new Student();
        System.out.println(s.getB());
        System.out.println(m.getA());//error
    }
}

父类和子类不太一个包中,子类的方法getB()可以访问getA(),而实例s,m不能访问getA()方法。

protected

我们都知道:protected 修饰的类和属性,对于自己、本包和其子类可见
但这样说你并不完全正确
对于protected的成员或方法,要分子类和超类是否在同一个包中。与基类不在同一个包中的子类,只能访问自身从基类继承而来的受保护成员,而不能访问基类实例本身的受保护成员。在相同包时,protected和public是一样的
这里写图片描述

  • Class SubB has
    access only to the inherited from Base protected elements,
    i.e. its own elements, but the protecteddata of other Base instances
    is not accessible from SubB.

接下来将一些实例,看完既可以完全理解protected权限了
例1

class MyObject {}

public class Test {
    public static void main(String[] args) {
       MyObject obj = new MyObject();
       obj.clone(); // Compile error.
    }
}

虽然MyObject与Test属于同一个包,但受保护的clone方法来自java.lang.Object类型,而在Test中,其基类Object的受保护方法是不可见的。

例2

class MyObject2 {
    protected Object clone() throws CloneNotSupportedException {
       return super.clone();
    }
}

public class Test2 {
    public static void main(String[] args) throws CloneNotSupportedException {
       MyObject2 obj = new MyObject2();
       obj.clone(); // Compile OK.
    }
}

MyObject与Test在同一个包中,受保护的clone方法来自MyObject本身,所以它对Test而言是可见的。(在相同包时,protected和public是一样的)另外在这个示例中,还说明了super关键字对于基类受保护成员的调用是个语言设计之中的“例外”。

例3

package 1
class MyObject3 {
protected Object clone() throws CloneNotSupportedException {
       return super.clone();
    }
}

package 2
public class Test3 extends MyObject3 {
    public static void main(String args[]) {
       MyObject3 obj = new MyObject3();
       obj.clone(); // Compile error.
       Test3 tobj = new Test3();
       tobj.clone();// Complie OK.
    }
}

企图跨越不同的包,从子类中调用基类实例的受保护方法。明显不行。

例4

class MyObject extends Test{}
public class Test {
  public static void main(String[] args) {
    MyObject obj = new MyObject();
    obj.clone(); // Compile ok.
  }
}

可见呢?因为MyObject的clone方法继承自Test,而Test做为相对于Object的子类,是可以访问继承而来的属于它自己的受保护方法的。

例5

package 1
class MyObject extends Test {
}

package 2
public class Test {
  public static void main(String args[]) {
    MyObject obj = new MyObject();
    obj.clone(); // Compile OK
  }
}

虽然处于不同的包,但子类的受保护方法实际上继承自父类,父类的自己的受保护方法对自己可见,其原理同示例4.

例6

package 1
class MyObject extends Test {
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}

package 2
public class Test {
  public static void main(String args[]) {
    MyObject obj = new MyObject();
    obj.clone(); // Compile error!
  }
}

不同包中子类本身的受保护方法当然不可能对父类可见
例7

package a;
class MyObject extends Test {
    public static void main(String[] args) {
    Test test = new Test();
    test.clone(); // Compile error.
  }
}
package a;
public class Test {

}

同一个包中,父类实例的clone方法在子类中依然不可见,原理同示例1,就是因为父类的clone方法,实际上来自java.lang.Object。


<think>好的,我现在需要帮助用户理解Java中的Object.clone()方法,包括使用场景和实现细节。用户之前的问题是关于Android中的上下文选择,但现在转向了Java的clone方法,所以需要确保回答专注于这个新主题,同时参考提供的引用内容。首先,用户提供的引用[1]提到clone方法是为了对象拷贝,避免重复创建对象的开销。引用[2]讨论了深克隆和浅克隆的区别以及如何实现深克隆。用户现在想了解clone方法的具体使用场景和实现细节。我需要先回忆Java中clone方法的基础知识。Object类中的clone()protected方法,所以需要重写并公开访问权限。实现Cloneable接口是必须的,否则会抛出CloneNotSupportedException。默认的clone方法是浅拷贝,复制基本类型和引用,但引用指向同一对象。深克隆需要手动处理,复制引用对象的副本。接下来,用户可能需要了解为什么使用clone而不是构造函数。比如,当对象创建成本高时,clone可以避免重复初始化的开销。需要举例子说明适用场景,比如缓存对象、原型模式等。然后,实现细节部分需要分步骤说明如何正确重写clone方法,处理浅克隆和深克隆的区别。代码示例会有帮助,比如展示浅克隆的问题,然后如何通过深克隆解决。还需要注意常见的陷阱,比如没有实现Cloneable接口导致的异常,或者深克隆时递归克隆所有可变对象。此外,是否应该使用clone方法还是其他拷贝方式(如拷贝构造函数、序列化)可能也是一个点,但用户的问题集中在clone本身,所以可能需要简要提及替代方案。引用部分需要正确标注,比如在解释为什么需要clone时引用[1],在讨论深克隆实现时引用[2]。同时,确保回答结构清晰,分点列出使用场景、实现步骤、注意事项等。 最后,生成相关问题,可能需要包括深克隆与浅克隆的区别、替代方案、性能比较等。确保问题与当前主题相关,并帮助用户进一步探索。 需要检查是否有遗漏的关键点,比如clone方法的限制、多线程环境下的问题,或者如何正确实现深克隆的步骤。同时,确保代码示例正确,使用Java语法,并正确标注代码语言。</think>### Java Object clone方法 使用场景及实现细节 --- #### 一、核心使用场景 1. **高效对象复制** `clone()` 方法通过直接复制内存数据,避免通过构造函数重新初始化对象带来的性能开销[^1]。适用于: - 需要快速创建大量相似对象(如游戏中的粒子系统) - 原型模式(Prototype Pattern)的默认实现 ```java public class Prototype implements Cloneable { @Override public Prototype clone() throws CloneNotSupportedException { return (Prototype) super.clone(); } } ``` 2. **状态隔离需求** 当需要修改对象副本而不影响原始对象时,可通过克隆实现隔离。例如: - 缓存对象的副本操作 - 事务回滚前的状态备份 --- #### 二、实现细节与步骤 1. **基本实现要求** - 类必须实现 `Cloneable` 接口(标记接口) - 重写 `clone()` 方法并提升访问权限为 `public` ```java public class User implements Cloneable { private String name; private Address address; // 引用类型成员 @Override public User clone() throws CloneNotSupportedException { return (User) super.clone(); // 默认浅克隆 } } ``` 2. **浅克隆与深克隆** - **浅克隆**:仅复制基本类型和引用地址(默认行为)[^2] ```mermaid graph LR A[原始对象] --> B[克隆对象] A.ref --> C[共享引用对象] B.ref --> C ``` - **深克隆**:递归复制所有引用对象 ```java public User clone() throws CloneNotSupportedException { User cloned = (User) super.clone(); cloned.address = this.address.clone(); // 递归克隆引用对象 return cloned; } ``` 3. **深克隆实现模板** ```java public class Order implements Cloneable { private List<Item> items; @Override public Order clone() { try { Order cloned = (Order) super.clone(); cloned.items = new ArrayList<>(); for (Item item : this.items) { cloned.items.add(item.clone()); } return cloned; } catch (CloneNotSupportedException e) { throw new AssertionError(); // 不会发生 } } } ``` --- #### 三、关键注意事项 1. **引用类型处理** - 若类包含可变对象(如集合、自定义类),必须显式实现深克隆 - 使用 `Arrays.copyOf()` 或集合的构造函数处理数组/集合的克隆 2. **性能权衡** $$T_{\text{clone}} = O(n) \quad \text{vs} \quad T_{\text{new}} = O(k)$$ 当对象构造成本 $k$ 较高时,克隆效率优势显著;若对象结构简单,直接构造可能更快。 3. **替代方案对比** | 方法 | 优点 | 缺点 | |------------------|-----------------------|------------------------| | `clone()` | 高效内存复制 | 需处理深克隆逻辑 | | 拷贝构造函数 | 显式控制复制过程 | 需要额外编码 | | 序列化/反序列化 | 自动深克隆 | 性能低,需实现Serializable | --- #### 四、典型问题示例 **问题:浅克隆导致数据污染** ```java User original = new User("Alice", new Address("Paris")); User cloned = original.clone(); cloned.getAddress().setCity("Berlin"); // 修改克隆对象会影响原始对象! ``` **解决方案:递归深克隆** ```java public class Address implements Cloneable { @Override public Address clone() throws CloneNotSupportedException { return (Address) super.clone(); } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值