class A {
private int foo;
void bar(B b) { b.foo = 42; }
}
class B extends A { }
编译失败,报错:
A.java:3: error: foo has private access in A
void bar(B b) { b.foo = 42; }
^
1 error
向基类添加强制转换使其工作。
void bar(B b) { ((A) b).foo = 42; }
有人能解释一下为什么第一个片段是非法的吗?被禁止的原因是什么?这是JLS说:
Otherwise, the member or constructor is declared
private, and access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
据我所知,我的代码符合这个措辞。那么这是 Java 编译器的错误,还是我对 JLS 的解释不正确?
(注意:我不是在寻找解决方法,比如让变量 protected。我知道如何解决这个问题。)
最佳答案
错误消息“在 A 中有私有(private)访问权限”是一个很长一段时间的 java bug。
JDK 1.1:
JDK-4096353 : JLS 6.6.1: When subclass references are used to access privates of superclasses
包含完全符合问题一的代码片段
class X{
private static int i = 10;
void f() {
Y oy = new Y();
oy.i = 5; // Is this an error? Is i accessable through a reference to Y?
}
}
class Y extends X {}
他们试图修复它并导致
JDK-4122297 : javac's error messages are not appropriate for a private field.
======TP1======
1 class C extends S {
2 void f(){
3 java.lang.System.out.println("foo");
4 }
5 }
6
7 class S {
8 private int java;
9 }
======
% javac C.java
C.java:3: Variable java in class S not accessible from class C.
java.lang.System.out.println("foo");
^
C.java:3: Attempt to reference field lang in a int.
java.lang.System.out.println("foo");
^
2 errors
======
但是按照规范,java 不是在 C 中继承的,这个程序应该可以编译。
它在 1.2 中修复,但在 1.3 中再次出现
JDK-4240480 : name00705.html: JLS6.3 private members should not be inherited from superclasses
JDK-4249653 : new javac assumes that private fields are inherited by a subclass
当泛型出现时
JDK-6246814 : Private member of type variable wrongly accesible
JDK-7022052 : Invalid compiler error on private method and generics
但是,对于 JLS,这个成员根本不存在于继承的类型中。
JLS 8.2. Class Members
Members of a class that are declared private are not inherited by subclasses of that class.
所以 b.foo 是非法的,因为类 B 没有名为 foo 的字段。
没有限制,是B中没有的字段。
Java 具有强类型,我们无法访问 B 中不存在的字段,即使它们存在于父类(super class) A 中。
强制转换 (A) b 是合法的,因为 B 是 A 的子类。
A 有一个名为 foo 的字段,我们可以访问这个私有(private)字段,因为 b(B b) 是 类中的一个函数>A 即使 b != this 由于
JLS 6.6.1. Determining Accessibility
Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
如果我们写
class A {
private int foo;
void baz(A b) { b.foo = 42; }
}
class B extends A { }
class T {
void x() {
B b = new B();
b.baz(b);
}
}
它将编译,因为 Java 推断多态调用的类型参数。
JLS 15.12.2.7. Inferring Type Arguments Based on Actual Arguments:
A supertype constraint T :> X implies that the solution is one of supertypes of X. Given several such constraints on T, we can intersect the sets of supertypes implied by each of the constraints, since the type parameter must be a member of all of them. We can then choose the most specific type that is in the intersection
关于java - 无法通过子类实例从自己的类访问私有(private)变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28377005/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg