I have the next code:
class Foo {
public Foo (String param) { ... }
}
class Bar extends Foo {
public Bar () {
super (doSmth());
...
}
private static String doSmth () {
//what I can NOT do here?
}
}
I wond开发者_开发问答er is it safe? Are there any limitations about doSmth
method?
The simple rule is do not access, directly or indirectly, the "this" object from within a constructor.
That means you should not call overrideable methods from a constructor, nor should you call a method that calls an overrideable method, or call a method that calls a method that calls an overrideable method, or ... you get the idea.
It also means that you should not pass "this" to anything, as the other thing could call an overrideable method.
In your particular case what you have is fine. If it were to change to:
class Bar extends Foo
{
public Bar () {
super (doSmth(this));
...
}
private static String doSmth (Bar bar) {
//what I can NOT do here?
}
}
Then you would have a (potential) problem because doSmth could call an overriden method in subclass of Bar that relies on data that hasn't been initialized yet.
Here is an example of what could happen:
public class Main
{
public static void main(final String[] argv)
{
final A a;
a = new B();
a.foo();
}
}
abstract class A
{
protected A()
{
bar(this);
}
private static void bar(final A a)
{
a.foo();
}
public abstract void foo();
}
class B extends A
{
final String str;
public B()
{
super();
str = "Hello, World!";
}
public void foo()
{
System.out.println("str - " + str);
}
}
So, as long as you don't call any overridden methods you are good. However it is safest to just follow the "rule" of never passing this outside of the constructor and never invoking overrideable (non-final) methods, directly or indirectly from a constructor.
Bypassing the requirement is very unsafe because it would allow you to call a method on the base class before its constructor had been run. Only bad things can happen there. This is why Java (and most other sane languages force this to be done)
class Foo {
string m_field;
public Foo(string param) {
m_field = param;
}
public void Method() {
// use m_field
}
}
class Bar extends Foo {
public Bar() {
// no super
Method(); // oops
}
}
I don't see anyone answering your actual question yet...
private static String doSmth () {
//what I can NOT do here?
}
You can do whatever you want there. The method is static, so you can access all the static fields you'd like. Your compiler will stop you from attempting to access instance-specific methods/fields.
Furthermore, nothing prevents you from using your static method in the constructor, or even as a prerequisite to a call to a super()
constructor:
public Bar () {
super (doSmth());
/* ... */
}
... as long as doSmth()
is static, you're golden.
Sometimes I use it to create parameters for a constructor of superclass. But the method has to be static:
class MyImplementation extends SuperImplementation {
public MyImplementation(String input) {
super(convertInput(input));
...
}
private static String convertInput (String input) {
String output = "";
// do something with input and put it to output
return output;
}
}
For the question Why java has a requirement that the first line of constructor should call parent constructor?
I believe it is because java take that into considerations when deciding whether or not to inject a default constructor
class Foo(){
abc()
this()
}
may become
class Foo(){
this()
abc()
this()
}
From here http://www.leepoint.net/notes-java/oop/constructors/constructor.html
The first line of a constructor must either be a call on another constructor in the same class (using this), or a call on the superclass constructor (using super). If the first line is neither of these, the compiler automatically inserts a call to the parameterless super class constructor.
精彩评论