Instantiate nested class in Scala when extending Java class - java

I have abstract java class which contains nested class declared as protected static:
public abstract class AbstractJavaClass {
// contains nested class
protected static class InnerClass {
...
}
}
When I'm trying to instantiate it in Scala class extending AbstractJavaClass like I do in java (i.e. just referring name inside method new InnerClass):
class ScalaClass extends AbstractJavaClass {
def method = new InnerClass()
}
I get error: type InnerClass is not a member of ScalaClass. What am I doing wrong? The same in java works fine.

Stumbled here: access java base class's static member in scala
It says
This isn't possible in Scala. Since Scala has no notation of static you can't
access protected static members of a parent class. This is a known limitation.
Though I couldn't resolve initial issue (when class is protected static), when I changed it to public static in definition of AbstractJavaClass I could use it this way:
class ScalaClass extends AbstractJavaClass {
import AbstractJavaClass.InnerClass
def method = new InnerClass
}
Using new InnerClass without import gives the same error.

Related

Parameterizing superclass with static member class from subclass

Is there a way to parameterize a superclass with a static member class of the subclass?
Contrived Example
ExampleSuperClass.java:
package foo;
public class ExampleSuperClass<T> {
protected T field;
public ExampleSuperClass(T field) {
this.field = field;
}
public T getField() {
return field;
}
}
ExampleSubClass.java:
package foo;
public class ExampleSubClass extends ExampleSuperClass<Member> {
static class Member {
}
public ExampleSubClass() {
super(new Member());
}
}
Compilation fails on ExampleSubClass.java with error:
[javac] ExampleSubClass.java:3: error: cannot find symbol
[javac] public class ExampleSubClass extends ExampleSuperClass<Member> {
[javac] ^
[javac] symbol: class Member
[javac] 1 error
or in Eclipse with:
Member cannot be resolved to a type
in Eclipse the super invocation also has the error:
The constructor ExampleSuperClass(Member) refers to missing type Member
It works fine (aka no errors) if ExampleSubClass is instead parameterized with another package-protected top-level class.
Summary
The driving force behind this is that I have a generic super class and many different ${SubClass-extends-GenericSuperClass}.java and ${ClassUsedBySubClass}.java pairs. But since ClassUsedBySubClass is only ever referenced by SubClass, it would be nice to:
restrict ClassUsedBySubClass's access by making it a static member class and
cut down on the number of files by not giving ClassUsedBySubClass its own file.
So, is there a way to use a subclass's member class in parameterizing the superclass?
If there isn't -- is there an alternative approach?
Yes, you can do it. However, since Java uses the scope outside the declaration for name resolution, you must qualify Member with the name of ExampleSubClass:
public class ExampleSubClass extends ExampleSuperClass<ExampleSubClass.Member> {
...
}
Because Member is an inner class, you need to specify that when using it as a generic type. I'm able to get it to compile by using the following:
static class ExampleSubClass extends ExampleSuperClass<ExampleSubClass.Member> {
static class Member {
}
public ExampleSubClass() {
super(new Member());
}
}
Member is a static nested class. Static nested class is accessed using the enclosing class name:
ExampleSubClass.Member
You do this every time a static nested class occurs outside the scope of its outer class.
Therefore, the following is correct:
public class ExampleSubClass extends ExampleSuperClass<ExampleSubClass.Member> {
^
enclosing class name
static class Member {
...
}
}
Same as when you want to create an object for the static nested class:
ExampleSubClass.Member member = new ExampleSubClass.Member();

Extending an Inner class into a Nested class?

I was learning about Nested and Inner classes and this led me to think whether it is possible to extend an Inner class to be a Nested class or not. For example.
public class Outer{
public class Inner{
// notice the lack of static keyword
}
}
public class ExtendedOuter extends Outer{
public static class ExtendedInner extends Inner{
// notice the static keyword
}
}
I did try to compile the code above and I couldn't, but the compile time error I received made me believe that there may be a work around. I can however extend a Nested class to be an Inner class.
This is the compile time error I received.
no enclosing instance of type Outer is in scope
An inner class has a reference to the outer class. You cannot remove it in a subclass. This would be like removing a field in a sub-class.
Actually you can extend the inner class. You just have to provide an instance of Outer that the class will be bound to. To do so, you have to explicitly call the super constructor with the instance.
public class Outer {
public class Inner{
// notice the lack of static keyword
}
}
public class ExtendedOuter extends Outer {
private static Outer outer = new ExtendedOuter(); // or any other instance
public static class ExtendedInner extends Inner {
public ExtendedInner() {
outer.super(); // this call is explicitly required
}
}
}
This also works if you have a nested class that extends another nested class from a different enclosing class.
Your question doesn't make sense. An inner class is already a nested class, and so is any other class defined inside another one. Evidently you don't know what these words mean:
nested class: a class declared inside another one
inner class: a nested class that isn't declared 'static'.
Note that 'static nested' and 'inner' are mutually exclusive. Note also that an inner class can extend a static nested class, but not vice versa.
What your code is actually trying to do is extend the inner class as a static class, which is what causes the error. Not because the extending class is nested.

Static nested class as generic type bound doesn't work

File AbstractContainer.java
package container;
import static container.AbstractContainer.*;
public abstract class AbstractContainer<ElementType extends AbstractElement> {
public static abstract class AbstractElement {
}
}
File ConcreteElement.java
package container;
import static container.ConcreteContainer.*;
import static container.AbstractContainer.*;
public class ConcreteContainer extends AbstractContainer<ConcreteElement> {
public static class ConcreteElement extends AbstractElement {
}
}
This code gives me a compile error:
java: type argument container.ConcreteContainer.ConcreteElement is not within bounds of type-variable ElementType
but the IDE doesn't see any problems (IDEA 12).
First: What is going on here?
Second question, In AbstractContainer.java why do I have to static import the nested class, that's obviously in scope, to use it in the generic type (extends AbstractElement instead of extends AbstractContainer.AbstractElement) ?
First, you don't have to static-import the class. Just qualify the reference to your inner classes:
public abstract class AbstractContainer<ElementType extends
AbstractContainer.AbstractElement> {
and
public class ConcreteContainer extends
AbstractContainer<ConcreteContainer.ConcreteElement>
When compiling with Java 1.6, I don't see your compiler error. But I do see it when compiling with 1.7.
As it happens, fully-qualifying AbstractElement when declaring ConcreteElement seems to satisfy the compiiler:
public class ConcreteContainer extends
AbstractContainer<ConcreteContainer.ConcreteElement> {
// fully qualify here
public static class ConcreteElement extends AbstractContainer.AbstractElement {
}
}
First question - probably a compiler bug.
Second question - probably due to technicality:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.3
The scope of a declaration of a member m declared in or inherited by a class type C (ยง8.1.6) is the entire body of C
For example
#SomeAnnotation(M.class)
class C
<T extends M>
{
static class M{}
}
the code is illegal, because M is used outside the body of C, in annotation, and in type parameter.
Prior to Java 5, there's no annotation/generics, therefore "the entire body of C" covers all places "M" can be sensibly referenced. But now the rule is outdated, we should really extend the scope of M a little bit; I don't see any problem in doing that.

Can we create public static abstract class in java?

I was searching in google for something and I got a code like
public static abstract class LocationResult{
public abstract void gotLocation(Location location);
}
It's a nested class but wondering how it could be accessible ?
It must be a nested class: the static keyword on the class (not methods within it) is only used (and syntactically valid) for nested classes. Such static member classes (to use Java in a Nutshell's common nomenculture) hold no reference to the enclosing class, and thus can only access static fields and methods within it (unlike non-static ones; see any summary of nested classes in Java (also known as inner classes).
It can be accessible like this:
public class EnclosingClass {
public static abstract class LocationResult{
public abstract void gotLocation(Location location);
}
}
EnclosingClass.LocationResult locationResult = ...
Only nested classes can be static. By doing so you can use the nested class without having an instance of the outer class.
So you could create a class extending it using extends Mainclass.LocationResult and use it with Mainclass.LocationResult instance = ...

Protected nested class not accessible to derived classes in other package

Here is what I'm trying to accomplish
File 1: ./net/Class1.java
package net;
public class Class1
{
protected static class Nested
{
}
}
File 2: ./com/Class2.java
package com;
import net.Class1;
public class Class2 extends Class1
{
Nested nested = new Nested();
}
Here is the error I'm getting
>javac ./net/Class1.java ./com/Class2.java
.\com\Class2.java:7: error: Nested() has protected access in Nested
Nested nested = new Nested();
Is this error expected? Am I doing something wrong?
Problem
Few important facts (which many people forget or are not aware of):
default constructors (including ones for static and non-static nested classes) have same visibility as visibility of class which they belong to. So in case of protected class Nested{...} its default constructor is also protected.
element with protected visibility can be accessed only from class which
belongs to same package as class which declared that element,
extends (explicitly or implicitly) class which declared it.
Your Class2 extends Class1 so it only have access to members of Class1 (including access to Nested type). But since it
doesn't extend Nested (even implicitly, it only inherits access to it since it is protected)
doesn't belong to same package as Nested
it can't access protected elements from Nested class (including constructors).
Solution:
To solve that problem make Nested constructor public by either
explicitly creating no-argument constructor of Nested class with public modifier:
package net;
public class Class1 {
protected static class Nested {
public Nested(){
//^^^^^^
}
}
}
making Nested class public (its default constructor will also become public - see point 1.)
package net;
public class Class1 {
public static class Nested {
//^^^^^^
}
}

Categories

Resources