I am having issues extending an inner class with a generic abstract class.
I get an Non-static field cannot be referenced from a static context which is odd because the class itself is static, not necessarily the field value.
This is basically what I have:
// AbstractFoo.java
public abstract class AbstractFoo extends FrameLayout {
// Some logic
}
// AbstractBar.java
public abstract class AbstractBar<T> {
int someNumber;
// Some logic
}
// Foo.java
public class Foo extends AbstractFoo {
// Some logic
// Foo.InnerFoo.java
public static class InnerFoo extends AbstractBar<InnerFoo> {
public InnerFoo() {
super.someNumber = 5; // Compiler error HERE
}
}
}
For some reason I cannot access someNumber from InnerFoo. From my understanding this shouldn't cause any issues. The classes I'm extending btw is from an external library.
This is also all done with Android where minimum SDK is 24.
Thanks for the help!
The fields defined in your classes do not have an explicit access modifier which would use the default access modifier and limit the visibility to classes within the same package.
You should make the fields in AbstractBar as protected -
public abstract class AbstractBar<T> {
protected int someNumber;
}
Related
This question already has answers here:
When overriding a method, why can I increase access but not decrease it?
(8 answers)
Closed 4 years ago.
For example, class Base has two public methods: foo() and bar(). Class Derived is inherited from class Base (I cannot modify this class, as its a in a library I use).
In class Derived (Its in my application), I want to make foo() public but bar() private. Is the following code the correct and natural way to do this? Instead of extending it, I am creating a object and accessing only the required methods.
class Base {
public void foo();
public void bar();
};
public class Derived {
private Base base;
public void bar() {
base.bar();
}
};
You cannot reduce the visibility of a method you inherit from
So if the super method is public you cannot reduce to protected or private
This question already covers it : Cannot reduce visibility of method inherited method from parent
You cannot inherit from a class and reduce the visibility of the inherited methods. On the other hand, the code you are showing is not making use of inheritance. If you need to extend a class (so that you inherit all state and behavior from the base class), but also don't want to expose all inherited methods as public, here's a way to do it:
public final class Derived {
private final Base base = new Base() { // extending base class here
#Override
public void foo() {
Derived.this.foo();
}
#Override
public void bar() {
Derived.this.bar();
}
};
public void foo() {
// Implement foo here
}
private void bar() {
// Implement bar here
}
}
So the idea is to encapsulate the implementation of a class that extends Base in a private final field of a new Derived class that only exposes the foo method, while keeping the bar method private. This anonymous inner class just delegates to methods of the Derived class. As an extra safety measure, we are also making the Derived class final.
Let's say I have a
public abstract class Super{
protected static int BASE = 1;
public int foo(){
//do some computation with BASE, e.g:
return BASE + 1;
}
}
and a couple static classes inheriting from it:
public static abstract class Sub extends Super{
//this class should keep BASE at 1
}
static class SubSub1 extends Sub{
//this class should change BASE to 0
static{
SubSub1.BASE = 0;
}
}
static class SubSub2 extends Sub{
//this class should in effect have a BASE of 1
}
And yes, this fails.
The problem obviously is that since SubSub1 is a static class, if it is to change BASE, Super.BASE must be static.
But if Super.BASE is static, then SubSub1.Base IS Super.BASE.
How do I best achieve what I'm trying to do? (No, I can't make the classes non-static, and assume there are a lot of subclasses.)
I'd appreciate the help.
There are no static classes in Java. All Java classes are implicitly static, except nested classes. Interfaces, Annotations and Enums are always static.
The actual issue is a different one: there is no static inheritance in Java. A subclass does not get a copy of the static superclass field, it gets the same field. Whether you reference it as SubSub.BASE or as Super.BASE doesn't matter, it is Super.BASE
Actually, the "abstract protected int getBase()" wasn't so bad an idea - I just didn't like that "abstract" part since I would have had to implement that in all non-abstract subclasses.
This, on the other hand, seems to be working and allows me to change BASE only where I need it to change:
public abstract class Super{
protected int BASE = 1;
protected void setBase(){}
public int foo(){
setBase();
return BASE + 1;
}
}
and then:
public static abstract class Sub extends Super{
//this class should keep BASE at 1
}
static class SubSub1 extends Sub{
//this class should change BASE to 0
#Override
protected void setBase(){
BASE = 0;
}
}
static class SubSub2 extends Sub{
//this class should still have a BASE of 1
}
Thanks a lot, guys.
I know the difference between all the access modifiers in Java. However, someone asked me a very interesting question that I struggled to find the answer to: What is the difference between a private interface and a public interface in Java, in particular, how it is used as a class member? Any help would be greatly appreciated.
I believe we all know the use of public interface, so I would mention the point of private/protected interface here.
Interfaces can be members of class definitions and can be declared private or protected there.
public class Test {
private interface Sortable {
}
protected interface Searchable {
}
}
Example 1: -- Source
public class PrivateInterface {
private interface InnerInterface {
void f();
}
private class InnerClass1 implements InnerInterface {
public void f() {
System.out.println("From InnerClass1");
}
}
private class InnerClass2 implements InnerInterface {
public void f() {
System.out.println("From InnerClass2");
}
}
public static void main(String[] args) {
PrivateInterface pi = new PrivateInterface();
pi.new InnerClass1().f();
pi.new InnerClass2().f();
}
}
/* Output:
From InnerClass1
From InnerClass2
*/
It's the interface itself that can be package-private, not the methods
in it. You can define an interface that can only be used (by name)
within the package it's defined in, but its methods are public like
all interface methods. If a class implements that interface, the
methods it defines must be public. The key thing here is that it's the
interface type that isn't visible outside the package, not the
methods.
The public, private, and protected access modifiers on an interface mean the same thing that they mean on a class. I typically see these modifiers used on an interface that is nested in a class. Something like this:
//: interfaces/RandomWords.java
// Implementing an interface to conform to a method.
package interfaces;
public class PrivateInterface {
private interface InnerInterface {
void f();
}
private class InnerClass1 implements InnerInterface {
public void f() {
System.out.println("From InnerClass1");
}
}
private class InnerClass2 implements InnerInterface {
public void f() {
System.out.println("From InnerClass2");
}
}
public static void main(String[] args) {
PrivateInterface pi = new PrivateInterface();
pi.new InnerClass1().f();
pi.new InnerClass2().f();
}
}
An interface declaration may include these access modifiers:
public protected private abstract static strictfp
public: If an interface type is declared public,then it can be accessed by any code.
protected/private: The access modifiers protected and private pertain only to member interfaces within a directly enclosing class declaration. A member interface is an interface whose declaration is directly enclosed in another class or interface declaration.
static: The access modifier static pertains only to member interfaces, not to top level interfaces.
abstract: Every interface is implicitly abstract. This modifier is obsolete and should not
be used in new programs.
strictfp: The effect of the strictfp modifier is to make all float or double expressions
within the interface declaration be explicitly FP-strict.
Ref: Java Language and Virtual Machine Specifications
I have a sample interface
public interface SampleVariables {
int var1=0;
int var2=0;
}
and I want to use var1 and var2 across multiple classes i am trying to do this using
public class InterfaceImplementor extends Message implements SampleVariables{
private int var3;
public int getVar1(){
return var1;
}
public void setVar1(int var1){
SampleVariables.var1=var1; // ** error here in eclipse which says " remove final modifier of 'var1' " Though I have not defined it as final
}
public int getVar3() {
return var3;
}
public void setVar3(int var3) {
this.var3 = var3;
}
}
where class Message is a pre-defined class which I try to use and I cannot define var1, var2 in the class Message.
Is there a better way to do this? Or am I missing something really simple ?
All fields in an interface are implicitly static and final, hence your warning above. See this SO question for more details.
It seems to me that you want a base class with these variables, but as you've noted you can't do this since you're deriving from a 3rd party class.
I would not derive from that 3rd-party class, since you don't control its implementation. I would rather create a class that wraps it and provides your additional functionality. That gives you a level of comfort that if/when that 3rd-party class changes, you can limit the scope of the changes that you have to subsequently make.
Unfortunately Java doesn't support mixins, which is what you're trying to achieve here.
In interface by default variables are static final you cannot change there value ie. you cannot do SampleVariables.var1=var1;
what you can do is
public class InterfaceImplementor extends Message { // do not implement interface here
private int var3;
private int var1;
public void setVar1(int var1){
this.var1=var1; // will work
}
and to access variable of interface SampleVariables.var1
Since member variable of Interface are by default static, final so you can't reassign the value again once you have initialized.
Every field declaration in the body of an interface is implicitly public, static, and final. It is permitted to redundantly specify any or all of these modifiers for such fields.
See Java Language Specification.
You should use an abstract class for this.
example:
public abstract class AbstractClass {
protected int var1;
}
class SubClass1 extends AbstractClass {
}
class SubClass2 extends AbstractClass {
}
This way SubClass1 and SubClass2 will have a var1. Note that you can do the same with getters and setters, but for making the point this was shorter.
If I write an abstract class, then nest a class in the abstract class, will I have access to its methods in any subclasses of the abstract class? I cannot find the answer anywhere..
Of course, access modifiers on inner classes obey the same rules as on fields and methods. It does not matter whether your class is abstract or concrete, as long as the nested class is either public, protected or the subclass is in the same package and the inner class is package private (default access modifier), the subclass will have access to it.
public abstract class AbstractTest {
// all subclasses have access to these classes
public class PublicInner {}
protected class ProtectedInner {}
// subclasses in the same package have access to this class
class PackagePrivateInner {}
// subclasses do not have access to this class
private class PrivateClass {}
}
class Abstract {
modifier1 class Nested { modifier2 int i = 0; }
Abstract() {
Nested n = new Nested();
n.i = 1;
}
}
class Sub extends Abstract {
Sub() {
Nested n = new Nested();
// have access as long you not choose "private"
// for `modifier1` or `modifier2`:
n.i = 5;
}
}
If the nested class is at least protected, we can access its methods (as long as the methods are public or we are in the same package and they are not private).
But you could have tried this out yourself easily :-)