受保护的字段对子类不可见

Posted

技术标签:

【中文标题】受保护的字段对子类不可见【英文标题】:Protected fields not visible to subclasses 【发布时间】:2011-06-22 10:05:04 【问题描述】:

我正在编写一个直接扩展android.view.View 的自定义视图。如果我尝试访问字段mScrollXmScrollY,我会看到该字段“无法解析或不是字段”的错误。 source code for android.view.View 具有 mScrollX、mScrollY 和声明为 protected 的类似变量。我的直接子类如何无法访问其父类的受保护字段? (ScrollView 这样的类显然可以。)

附:我意识到我可以打电话给getScrollX(),但我想更新这些字段;打电话给setScroll() 有我不想要的副作用。

【问题讨论】:

奇怪的是,子类,即使在其他包中,也可以访问其超类的受保护变量。我猜你使用的是错误的版本。你能展示一些你的代码吗? 【参考方案1】:

这是因为它们不是 Android SDK 的一部分。

这里是mScrollX的源代码:

/**
 * The offset, in pixels, by which the content of this view is scrolled
 * horizontally.
 * @hide
 */
@ViewDebug.ExportedProperty(category = "scrolling")
protected int mScrollX;

您会注意到@hide 注释。这意味着这不是 Android SDK 的一部分。创建 Android SDK 的构建过程部分不会将此数据成员包含在您正在编译的 android.jar 文件中的 android.view.View 存根版本中。

@hide 注释用于出于内部目的需要公开或受保护但不被视为 SDK 开发人员应该使用的东西。

请为您遇到的任何问题寻找其他解决方案。

【讨论】:

嗯,有趣!所以套用基本原理:“我们懒得理清适当的封装,所以我们颠覆了语言。”... 我注意到了@hide 标签。我认为这就是为什么 mScrollX 没有出现在 JavaDocs 中的原因(比如 proposed @exclude tag,它取代了 @hide)。我没有意识到 SDK 是 API 的存根版本。 我无法理解的一件事是 View 类的受保护变量在 ScrollView 类中被访问。这怎么可能 ?层次结构是 - ScrollView 扩展 FramLayout 扩展 ViewGroup 扩展 View。因此,View 类的 protected 变量只能在 ViewGroup 中访问。【参考方案2】:

这很简单:注意这些变量上方的@hide 注释。 它是一个特定于 Android 的注释,它对公共 SDK 隐藏字段/方法。这就是你不能直接访问它们的原因。

Romain Guy mentioned it in这个帖子。

【讨论】:

这令人不安。开源有什么意义?所以人们可以阅读源代码并了解发生了什么。但是这里发布的消息是假的?不是生产中使用的那个?这也是可以接受的,如果它是透明的。我不在乎JDK源是否是真实的,但我从阅读中获得的任何信息在真实系统中都必须是真实的。 你必须明白开源的含义。首先,您可以直接从源代码构建自己的 Android 版本,对其进行任何修改,并使用每个方法或字段,无论是否隐藏。这就是手机制造商所做的,以及社区中的一些定制 ROM 厨师。开发人员可以从 Android 开源的另一个方面受益,那就是通过源代码了解幕后工作原理,对我来说,这与文档本身一样重要。 隐藏某些字段或方法的情况通常是以下两种情况之一: 1.可能会在未来的SDK版本中发生变化,因此他们希望减少应用程序不兼容的机会,节省您,开发人员需要大量维护您的应用程序,并且 2. 像在您的情况下直接使用这些字段可能会干扰 API 在内部如何正常工作。【参考方案3】:

您可以尝试使用反射设置字段:

import java.lang.reflect.Field;

// ...

try 
    Field scrollXField = View.class.getDeclaredField("mScrollX");
    scrollXField.setAccessible(true);
    scrollXField.set(this, myNewValue);
 catch (Exception ex) 
    // oops, android changed the implementation. sucks to be you.

但是请注意,当您执行此操作时,您依赖于未记录和不受支持的行为,因此您应该为某些设备或未来版本中出现的问题做好准备。

【讨论】:

以上是关于受保护的字段对子类不可见的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Java 允许增加子类中受保护方法的可见性?

超类中的受保护方法在不同包中的子类中是不是可见? [复制]

Java:受保护的,可见的[重复]

对字段和方法使用私有而不是受保护的原因

Java--继承

public private protected 三种访问修饰符在c#中的区别