java 为什么我们不能在子类中分配较弱的权限
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17510152/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
why can't we assign weaker privilege in subclass
提问by syam
I have a class which has a method whose access specifier by default is public. Now, I would like to extend this class in a subclass and I want to override this method to have access specifier "private". When compiling this code, I am getting a compilation error:
我有一个类,它有一个方法,其访问说明符默认为 public。现在,我想在子类中扩展这个类,我想覆盖这个方法以获得访问说明符“private”。编译此代码时,出现编译错误:
"attempting to assign weaker access privileges".
“试图分配较弱的访问权限”。
Could somebody please explain to me what is wrong with assigning weaker privileges in a subclass?
有人可以向我解释在子类中分配较弱的权限有什么问题吗?
Here is the code that caused the compilation error:
这是导致编译错误的代码:
class Superclass
{
void foo()
{
System.out.println("Superclass.foo");
}
}
class Subclass extends Superclass
{
private void foo()
{
System.out.println("Subclass.foo");
}
}
回答by Stephen C
The short answer is that it is not allowed because it would break type substitutability; see also the Liskov Substititution Principle (LSP).
简短的回答是不允许的,因为它会破坏类型可替换性;另请参阅Liskov 替换原则 (LSP)。
The point is that polymorphism in Java (and other programming languages) relies on you being able to treat an instance of a subclass as ifit was an instance of the superclass. But if the method is restricted in the subclass, you find that the compiler cannot figure out whether the access rules allow a method to be called ...
关键是 Java(和其他编程语言)中的多态性依赖于您能够将子类的实例视为超类的实例。但是如果在子类中限制了方法,你会发现编译器无法判断访问规则是否允许调用一个方法......
For instance, lets assume that your example code was legal:
例如,假设您的示例代码是合法的:
// Assume this code is in some other class ...
SuperClass s1 = new SuperClass();
s1.foo(); // OK!
SuperClass s2 = new Subclass();
s2.foo(); // What happens now?
SuperClass s3 = OtherClass.someMethod();
s3.foo(); // What happens now?
If you base the decision on whether s2.foo()
is allowed on the declared type of s2
, then you allow a call to a private
method from outside the abstraction boundary of Subclass
.
如果您s2.foo()
根据 的声明类型来决定是否允许s2
,那么您允许private
从 的抽象边界之外调用方法Subclass
。
If you base the decision on the actual type of the object that s2
refers to, you cannot do the access check statically. The s3
case makes this even clearer. The compiler has absolutely no way of knowing what the actual type of the object returned by someMethod
will be.
如果您根据s2
引用的对象的实际类型做出决定,则不能静态地进行访问检查。这个s3
案例更清楚地说明了这一点。编译器绝对无法知道所返回对象的实际类型是什么someMethod
。
Access checks that could result in runtime exceptions would be a major source of bugs in Java application. The language restriction under discussion here avoids this nasty problem.
可能导致运行时异常的访问检查将是 Java 应用程序错误的主要来源。这里讨论的语言限制避免了这个讨厌的问题。
回答by Peter Lawrey
You can't restrict access because you have already allowed more access in the super class. e.g.
您不能限制访问,因为您已经允许在超类中进行更多访问。例如
SuperClass sc = new SubClass();
sc.foo(); // is package local, not private.
The access of sc
is determined by the type of the reference sc
not what it references because it is impossible for the compiler to know in all cases what type the object is at run time. For this to be a safe assumption the sub-class must honour the contract given by the parent or it fails to be a valid subclass. This is no different to the parent saying a method is implemented but the sub class saying it is not (or not accessible)
的访问sc
取决于引用的类型而sc
不是它引用的内容,因为编译器不可能在所有情况下都知道对象在运行时是什么类型。为了这是一个安全的假设,子类必须遵守父类给出的合同,否则它就不能成为有效的子类。这与父类说一个方法已实现但子类说它不是(或不可访问)没有什么不同
You could work around this by saying you can only access the sub-class method via the parent, not directly. The problem with this is you don't know when a parent might add a method and when you make a method private
you do this because you want it to be private, and not accessible another way.
您可以通过说您只能通过父类而不是直接访问子类方法来解决这个问题。这样做的问题是您不知道父级何时可能添加一个方法,而当您创建一个方法时,private
您会这样做,因为您希望它是私有的,并且不能以其他方式访问。
BTW You can still access a private method via reflection which has the side effect that it cause all sort of problems for the JVM. e.g. it has to keep private methods even though it might determine there is no way it can be called normally.
顺便说一句,您仍然可以通过反射访问私有方法,它的副作用是它会导致 JVM 出现各种问题。例如,它必须保留私有方法,即使它可能确定无法正常调用它。
In short, you want code which means what it says, and not have a split personality. It is either package local or it is private not something sort of in between but not really either. This is not such a problem the other way. i.e. if the sub class is public. It just means the sub-class can be used in more places than the parent, just like it can implement more methods.
简而言之,你想要代码能表达它的意思,而不是有分裂的个性。它要么是本地包,要么是私有的,而不是介于两者之间,但也不是。反过来说,这不是问题。即如果子类是公共的。它只是意味着子类可以在比父类更多的地方使用,就像它可以实现更多的方法一样。
回答by Vikas V
If this were allowed, there would be a backdoor through which you could call methods that should not be accessible.
如果允许这样做,就会有一个后门,您可以通过它调用不应访问的方法。
Lets say that this is allowed
让我们说这是允许的
class Super {
public void method() {
System.out.println("Super");
}
}
class Sub extends Super {
// This is not allowed, but suppose it was allowed
protected void method() {
System.out.println("Sub");
}
}
// In another class, in another package:
Super obj = new Sub();
obj.method();
obj.method
would be possible, because method()
is public
in class Super. But it should not be allowed,
because obj is really referring to an instance of Sub, and in that class, the method is protected!
obj.method
将是可能的,因为method()
是public
在班级超级。但它不应该被允许,因为 obj 确实指的是 Sub 的实例,并且在该类中,该方法是受保护的!
To restrict a call to a method in class Sub that should not be accessible from the outside, this restriction is put.
为了限制对 Sub 类中不应从外部访问的方法的调用,设置了此限制。
回答by Ravi Thapliyal
Constricting the access modifier of a super class method is an invalid override because it's breaking the super-class contract and invalidates the substitution principle i.e. a sub-class object IS-A super-class objectas well.
限制超类方法的访问修饰符是无效覆盖,因为它违反了超类契约并使替换原则无效,即子类对象也是超类对象。
public void doSomething(SuperClass sc) {
sc.publicMethodInSuperClass();
}
doSomething(new SubClass()); // would break
If this was allowed, the above client code would break because your SubClassdoesn't have that method public.
如果这被允许,上面的客户端代码将中断,因为您的SubClass没有该方法public。
Reference:
Liskov substitution principle
参考:
Liskov 替换原则
回答by Zavior
Apart from the obvious problems with using such a constructions(as pointed out by Peter Lawrey in his answer), read about the theory behind it as well: LSP, which means you must be able to substitute the main type with its subclass.
除了使用这种结构的明显问题(正如 Peter Lawrey 在他的回答中指出的那样)之外,还要阅读它背后的理论:LSP,这意味着您必须能够用它的子类替换主类型。
回答by quamrana
I think the short answer is that the compiler writers have set the rules to work this way. LSP has nothing to do with the problem at hand.
我认为简短的回答是编译器编写者已经设置了以这种方式工作的规则。LSP与手头的问题无关。
The only reason I can think of to have this restriction is that when a subclass derives from an interface, as a client programmer, you expect to be able to call all the accessible methods of the interface from a reference to the derived class.
我能想到有这个限制的唯一原因是当子类从接口派生时,作为客户端程序员,您希望能够从对派生类的引用调用接口的所有可访问方法。
Just suppose that you could write the code that the OP has shown. If you have a reference to the derived class you should be able to call any public members of the derived class (though there are none in this case). However, pass the reference as a parameter to a method which takes a reference to the base class and the method will expect to call any public or package method, which is foo
. This is the LSP that other contributors are looking for!
假设您可以编写 OP 显示的代码。如果您有对派生类的引用,您应该能够调用派生类的任何公共成员(尽管在这种情况下没有)。但是,将引用作为参数传递给接受基类引用的方法,该方法将期望调用任何公共或包方法,即foo
. 这是其他贡献者正在寻找的 LSP!
C++ example:
C++ 示例:
class Superclass{
public:
virtual void foo(){ cout << "Superclass.foo" << endl; }
};
class Subclass: public Superclass{
virtual void foo(){ cout << "Subclass.foo" << endl; }
};
int main(){
Superclass s1;
s1.foo() // Prints Superclass.foo
Subclass s2;
// s2.foo(); // Error, would not compile
Superclass& s1a=s2; // Reference to Superclass 'pointing' to Subclass
s1a.foo(); // Compiles OK, Prints Subclass.foo()
}
回答by mihir S
In dynamic method dispatch, call to overridden method is resolved at runtime rather than compile time. It based on the object being referred to at the time of the call...
在动态方法分派中,对覆盖方法的调用是在运行时而不是编译时解决的。它基于调用时引用的对象...
Now suppose weaker access privilege was allowed and we write the following statement in your code some other class:
现在假设允许较弱的访问权限,我们在其他类的代码中编写以下语句:
Superclass ref=new Subclass();
ref.foo()
Now during runtime, when java comes across the statement ref.foo()
, it will have to call foo()
of Subclass
...but foo()
method of subclass is declared as private in your code and private cant be called outside its own class..so now there is a conflict and it would result in runtime exception...
现在运行期间,Java的时候遇到的声明ref.foo()
,它会叫foo()
的Subclass
......但foo()
子类的方法声明为您的代码和私营着私人自己的class..so外部调用现在有一个矛盾,它会导致运行时异常...
回答by Aakash Chaudhary
Because you alter the order of access privileges , so you got error
因为你改变了访问权限的顺序,所以你得到了错误
correct order is:==> private to default to protected to public
正确的顺序是:==> private 默认为protected to public
*in your case you goes default ==> private whenever you goes in wrong order ,it result is error
*在您的情况下,每当您以错误的顺序进行时,您都会默认 ==> 私有,结果是错误
Right order of access privilege is--
访问权限的正确顺序是——
`class SuperClass{
void foo(){
System.out.print("SuperClass");
}
class SubClass extends{
//--default to default--//
void foo(){
System.out.print("SubClass");
}
//--default to protected--//
protected void foo(){
System.out.print("SubClass");
//--default to public //
public void foo(){
System.out.print("SubClass");
}`
**you make sure to preserve correct order while overriding **