I'm trying to implement a linked collection using generics, something like the following.
public class A<E> {
private class B {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B
} // end class A
A is the collection and B an element or node in the collection with an array referencing successors/predecessors and an item.
The array creation is not allowed. The error I get is generic array creation. Am I right to think that what it's actually creating is an array of A<E>.B?
If not, what's causing the error?
If so, how can I get around this?
I have obviously omitted a substantial amount of code, if what I've provided is not enough please let me know. Any advice would be appreciated. Thank you.
EDIT 1: I should have mentioned that the parameterized type must be the same in A as in B. So passing <E> to the inner class is not possible, as it creates E#2 and leaves A with E#1.
You call B inherits the generic from the outer class, as it is not static. And you can't just make it static, because it will then need E also.
So your B.b array will indeed need a type that is generic, i.e. A<E>.B or if you'd change your code to a static inner class, A.B<E> (if you would use private static class B<E>).
In Java, due to the way generics are implemented (by erasure), the type of the array is not well-defined. On one hand, it should be an array of B, on the other hand, it should be an array of Object.
The most workable solution seems to be to use Object[] and cast explicitly.
If you want increased type safety, you can of course use an ArrayList<B>, which internally uses Object[], too!
In you particular code, B b1, b2; might also be an option which is actually faster (no bounds checking) and needs less memory (no array object; no size information).
B is a non-static inner class. That means it has a reference to an instance of the enclosing class. So it is implicitly parameterized by the type parameter of outer class. So when you write B, it means A<E>.B. To create an array, you should use the raw class. However, B is not the raw class; to refer to the raw class you need to explicitly qualify it: A.B
So this is that you want:
this.b = new A.B[2];
You need to pass E to the inner class as well
private class B<E> {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B
Related
public class A<T> {
B[] bs = new B[5];
private class B {
}
}
I receive a compile-time error saying that new B[5] is generic array creation. I did not expect this because:
B itself is not parametrized.
B is not a type parameter of A.
With these reasons in mind, why is new B[5] still considered generic array creation?
Because the only way to create an instance of B (since it is an inner class) is with an instance of a parameterized A. Simple fix, change
private class B
to
private static class B
Since B is an non-static inner class of A, inside the scope of A, the unqualified name B implies A<T>.B, and this is a parameterized type (even though B doesn't look parameterized). (This makes sense since non-static inner classes contain a reference to an outer class instance; since this reference to the outer class instance is parameterized, the inner class instance must also be parameterized, so the inner class instance "inherits" the outer class type parameter.) You cannot create an array of a parameterized type in an array creation expression, so you cannot do new B[5] (because it implicitly means new A<T>.B[5]).
You can instead create an array of the raw type. But remember that B itself is a parameterized type and not a raw type. To get the raw type, you must explicitly qualify it with the raw outer class type:
B[] bs = new A.B[5];
Or you can create an array of the wildcard-parameterized type:
B[] bs = (B[])new A<?>.B[5];
In both cases, you will get an unchecked warning, which is always unavoidable in Java if you want to get a variable of a type "array of parameterized type", like B[].
I'm trying to implement a linked collection using generics, something like the following.
public class A<E> {
private class B {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B
} // end class A
A is the collection and B an element or node in the collection with an array referencing successors/predecessors and an item.
The array creation is not allowed. The error I get is generic array creation. Am I right to think that what it's actually creating is an array of A<E>.B?
If not, what's causing the error?
If so, how can I get around this?
I have obviously omitted a substantial amount of code, if what I've provided is not enough please let me know. Any advice would be appreciated. Thank you.
EDIT 1: I should have mentioned that the parameterized type must be the same in A as in B. So passing <E> to the inner class is not possible, as it creates E#2 and leaves A with E#1.
You call B inherits the generic from the outer class, as it is not static. And you can't just make it static, because it will then need E also.
So your B.b array will indeed need a type that is generic, i.e. A<E>.B or if you'd change your code to a static inner class, A.B<E> (if you would use private static class B<E>).
In Java, due to the way generics are implemented (by erasure), the type of the array is not well-defined. On one hand, it should be an array of B, on the other hand, it should be an array of Object.
The most workable solution seems to be to use Object[] and cast explicitly.
If you want increased type safety, you can of course use an ArrayList<B>, which internally uses Object[], too!
In you particular code, B b1, b2; might also be an option which is actually faster (no bounds checking) and needs less memory (no array object; no size information).
B is a non-static inner class. That means it has a reference to an instance of the enclosing class. So it is implicitly parameterized by the type parameter of outer class. So when you write B, it means A<E>.B. To create an array, you should use the raw class. However, B is not the raw class; to refer to the raw class you need to explicitly qualify it: A.B
So this is that you want:
this.b = new A.B[2];
You need to pass E to the inner class as well
private class B<E> {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B
we can achieve the output in two ways one is typecasting and one is without typecasting
A a=new B() // without typecaste
A a = (A)a// with Typecaste
in both ways we get same output.so, what is the use of typecasting
Let's assume that you have a list of Animals. and you have Tigers and Lions in it.
ArrayList<Animal> animals = new ArrayList<>();
//add some Tigers and some Lions
//sort so Tigers are at the beggining of the list
Tiger t = (Tiger)animals.get(0);
Without casting you will get type missmatch at compile time. With a cast you only risk ClassCastException which can be easy caught with a try-catch
It's just an example of a proper use of class casting in Java.
Casting is for "the opposite direction", i.e. for converting to a expression of a subtype of the original expression.
Example
Given
Object o = "Hello World";
String s = o;
does not compile, but
String s = (String) o;
compiles. This may yield a ClassCastException however, e.g. if a Integer was stored in o.
Casting has different uses. Unfortunately, your example doesn't exercise any useful example of casting since you create an instance of A (a) then cast it to an A.
What you need to understand is there are apparent types and actual types. An apparent type would be List<T> list;. Here we see that it's a list. But the actual type might be an ArrayList<T> (List<T> list = new ArrayList<>();). In this scenario we can, with care, cast the apparent type to the actual type. This would allow us to then use the functionality of the actual type. For example, let's look at some code; given:
List<Integer> list = new ArrayList<>();
ArrayList<Integer> aList;
LinkedList<Integer> lList = new LinkedList<>();
We can do this without issue (although dangerous in general)...
// Dangerous but OK with a cast
// list might not be an ArrayList
aList = (ArrayList<Integer>) list;
// Use ArrayList methods
aList.trimToSize();
list = lList;
LinkedList<Integer> danger = (LinkedList<Integer>) list;
...but it's also possible to do:
aList = (ArrayList<Integer) list;
// Use ArrayList methods
aList.trimToSize();
// list = lList;
LinkedList<Integer> danger = (LinkedList<Integer>) list;
The last snippet results in a ClassCastException because list isn't a LinkedList.
Casting goes beyond that though. Consider when you have two integers you want to divide. Without a cast you could end up with an integer result where a floating point is more appropriate. Consider:
int i = 2;
int j = 3;
System.out.println("No cast: " + i/j + " ;With cast: " + (double)i/j);
Output:
No cast: 0 ;With cast: 0.6666666666666666
So, it depends on the use case.
A a = new B();
will only works if B inherit from A.
If B inherit from A, the type cast is not required as B is a A. Type cast will be necessary if you need to type cast to a subclass:
A a = new B();
B b = (B) a;
While this would be illegal :
A a = new A();
B b = (B) a;
as a is not a B.
Java implicitly upcast with assignment, so in the code you've provided the casting operator is redundant; a is already of type A:
A a = new B(); // without typecast operator (implicit upcast)
A a = (A)a; // with redundant typecast operator
One reason to have a casting operator is that you may also wish to downcast (which is not done implicitly in Java). For instance, when a is a type A reference to an object of class B (e.g. when B is a subclass of A) one may need to downcast to access certain methods:
A a = new B(); // implicit upcast
C c = ((B)a).methodOfBOnly(); // explicit downcast
You may also want to check this question on why Java doesn't do implicit downcasting.
There can be times when upcasting needs to be done explicitly as well. For instance, if a class contains overloaded methods
C method(A x){/*does one thing*/}
C method(B x){/*does another*/}
and assuming b is of type B, the calls to method((A)b) and method(b) would behave differently.
A a=new B()
is applicable only when class B extends class A. In this way the extra methods that are available in class B other than class A will be available with reference a.
When you do this
A a = (A)a
Then actually you are down casting the object of class B into an object of class A. And it is true that child can be type cast to parent. After this statement the reference a will not be able to call any method of class B which were not in class A because now the reference a points to an object of class A.
It is useful in many scenarios.
For example, you want to have a collection of Objects that point to same base class. Instead of maintaining separate collections for each sub class, you maintain a single collection of base class. And then when you want to use any child object you type cast the base class object to child class object to do that.
ArrayList<Base> children = new ArrayList<Base>();
children.add(new Child1());
children.add(new Child2());
Console.WriteLine(((Child1)children.get(0)).getChildName());
Console.WriteLine(((Child2)children.get(1)).getChildName());
Now base class does not have any method named getChild1Name or getChild2Name. And you need to typecast object of base class to respective child class to do that.
I want to know about the advantage in between the creating an object for sub class but assigning class A ref instead of assigning Class B ref. which is shown in line1,line2 below code
class A
{
int b=10;
}
class B extends A
{
int b=12;
}
class Test
{
public static void main(String[] args)
{
A a=new B(); //line1
//B a=new B();//line2
System.our.println(a.b);
}
}
If you're not going to need any methods specific to B, in other words, you're strictly going to use it as an A, it's an advantage for readability to state so.
But the main advantage comes to light when you use the general type in a method declaration:
public String resolveName(A a) { ... }
If you used B here for no good reason, then you would unnecessarily cripple your method. It could have worked for any A, but it works only for B.
try reading this: Polymorphism
In your short example there's no real advantage,.
But in general your question is about what polymorphism is good for?
And the answer goes back to the need of OOP methodology.
In short it gives you the ability to encapsulate and abstract the implementation from the usage, and can help you I the future to replace the implementation without a need to change the usage.
For more details see http://en.wikipedia.org/wiki/Polymorphism_(computer_science)
In that example, I don't think you can talk about an advantage (or disadvantage), because your two lines of code each do something very different.
If the type of variable a is A, then a.b refers to the field b with the value 10.
But if you change the type of a to B then a.b refers to a totally different field, the one declared inside B, with the value 12.
If instead b was a method, then the one declared in B would "override" the one declared in A, which is a very different situation. e.g.
class A
{
public int b() { return 10; };
}
class B extends A
{
public int b() { return 12; }
}
And the calling code would be:
A a=new B(); //line1
//B a=new B();//line2
System.our.println(a.b());
That is, we call the method b to get the return value. Now it makes no difference to the behaviour whether the type of a is A or B. What matters is the type of object that a refers to, which is always B and hence always has the behaviour defined in B, so it will print 12 regardless.
The advantage of this is that you can have a collection of objects (e.g. various kinds of vehicle) and they can be a mixture of cars, boats, trains etc. Each has its own implementation of the start method, so you can treat them all the same way.
Although generally it's clearer to define such methods in an interface, rather than a class. There is no general way to start a vehicle, so no reason to have a base class that has a meaningless implementation of start. Instead you just use an interface to declare the "shape" of the method without giving it any implementation.
In Java, is it possible to use a type variable, as an array element, inside an Interface?
I've tried as a filed type and as a cast operator, but always get the error
Cannot make a static reference to the non-static type A
interface ITest<A> {
A[] j; // Cannot make a static reference to the non-static type A
Object[] = (A[]) new Object[3]; // Cannot make a static reference to the non-static type A
}
Is there any case, where I am able to use the construct A[] inside the interface (and in an enum type?)?
class CTest<A> {
enum MyEnum {
F, G, H;
// something that uses A[] inside. Getting the same error as above
}
}
You can use a generic array type in an interface, like this:
public interface Foo<T> {
void doSomething(T[] array);
}
Your problem was you were trying to declare a field in an interface, which you basically can't do other than for constants. You can't declare a field of a generic array type in an interface, but I'd hope that you wouldn't want to anyway.
Admittedly type erasure makes the combination of arrays and generics somewhat awkward in various situations, but I think the above at least answers the question you posed.
Fields in interfaces are implicitly public, static and final, they're basically constants. And you can't have constants that depend on a type parameter because in Java parameters are removed from the type on compilation.
By the way, this is independent of whether you're using an array or not,
public interface X<T> {
T c = (T)new AnyType();
}
won't work either. And neither would
public class X<T> {
public static final T c = (T)new AnyType();
}