I have something equivalent to this:
class Main {
public static class Data {
private void foo() {}
}
public <D extends Data> D process(D data) {
data.foo();
return data;
}
}
The compiler complains:
The method foo() from the type Main.Data is not visible
I don't see why this shouldn't work. It compiles fine if I don't use generics in process
:
public Data process(Data data) {
data.foo();
return data;
}
I want to use generics here so I can keep a fluent interface that returns the exact subclass of Data that is passed in, but I also want to keep Data's base members private to the outer class.
Why is this happening and what are my options?
CodePudding user response:
even though you dont use generics , this problem will be there. D is not a "Data" for compiler , it is some other type which extends "Data".
public class Main {
public static class Data {
private void foo() {}
}
public static class DataX extends Data
{
}
public DataX process(DataX data) {
data.foo(); // will not be compiled because foo() has private access
return data;
}
}
as a solution you can directly cast it to a local variable of type Data
, or you can do it in tricky way (same thing, suits if process
method has some logic inside) like this.
public class Main {
public static class Data {
private void foo() {}
}
public <D extends Data> D process(D data) {
internalProcess(data);
return data;
}
private void internalProcess(Data data)
{
data.foo();
}
}
CodePudding user response:
The compile error is because even subclasses do not have direct access to private
members. Your generic method declares D
as a subclass of Data
, thus it does not have access to foo
which is private
. This is outlined in the docs.
The reason why you can do this without generics is because whilst foo
is private
, it is visible at the class
level and thus Data
and Main
. If the Data
class declaration was separate (file or package) then Main
would not have access either.
That said, a simple solution is to assign to a local variable as per shmosel's comment:
public <D extends Data> D process(D data) {
Data d = data;
d.foo();
return data;
}
We could also make this more concise by using casting:
((Data) data).foo();
In either case, this is type safe because D
is a type of Data
(as declared in the method signature) so we can treat it as such, and we don't break the requirement to keep the member private
.
Alternatively, if we don't strictly require the members to be private
, we could declare them protected
or package private (no modifier).