I started studying Java-generics. And I have some misunderstanding of the generics syntax and its meaning. I beg to treat with understanding if my question seems too trivial.
You can write:
public class MyClass<SomeClass> {}
and you can write:
public class MyClass<C extends SomeClass> {}
and you can write also:
public class MyClass<? extends SomeClass> {}
What is the difference between these cases?
The first case is absolutely clear to me: you can use instance of SomeClass and instance of his subclasses as class's parameter for MyClass.
I think that in this case you can only use instance of MyClass's subclasses
The same: only use instance of MyClass's subclasses as class's parameter for MyClass.
Are my guesses right or not? And especially what is the difference between the using of the second and third cases?
Thanks in advance for explanation!
Well the difference is you cant use ? in generic class declaration
public class MyClass<? extends SomeClass> {} // this isn't valid
The above declaration leads to compiler error.
From Documentation:
A generic class is defined with the following format:
class name { /* ... */ } The type parameter section,
delimited by angle brackets (<>), follows the class name. It specifies
the type parameters (also called type variables) T1, T2, ..., and Tn.
public class MyClass<C extends SomeClass> {}
In this declaration C is a type-argument which could be of type SomeClass or any of its SubClass's.
Example :
Class SomeOtherClass extends SomeClass {
}
MyClass clazz = new MyClass<SomeOtherClass>();
MyClass clazz = new MyClass<SomeClass>();
Related
Given
public class Foo {
public static class FooBuilder { ... }
}
I want to write a method on a third class that returns Foo, given Foo.FooBuilder.class
i.e.
Foo f = x.make(Foo.FooBuilder.class, someData);
Is it possible to declare a signature using generics that can imply the return type? Is there some language feature that lets me say "type U is outer class of type T"?
Obviously, it is possible to specify that type extends, or is the base of, a generic type (U extends T or U super T, respectively) but I am looking for U outer T which is, I think, more than Java can offer, even indirectly, at least in 1.7, which I am targeting.
So far, I have simply declared both inner and outer types, which works but is a wider definition than I am after and looks clumsy too.
public <TYPE,BUILDER> TYPE make(Class<BUILDER> builderClass, Map<String,Object> data) {
// Construct TYPE
}
Is there a way to infer TYPE without explicitly providing a template parameter?
There is a Class#getDeclaringClass method that may work in your case.
Quoting the docs:
If the class or interface represented by this Class object is a member of another class, returns the Class object representing the class in which it was declared.
EDIT:
After the clarification of OP, here is the new suggestion:
You create an generic interface to mark all your nested classes:
public interface Nested<P> {
}
Then you apply it to your Foo.Bar class like this:
public class Foo {
public static class Bar implements Nested<Foo> {
}
}
Then in your factory you can have the following:
public <P> P make(Class<? extends Nested<P>> clazz, Map<String, Object> someData) {
// do whatever you need to do
return (P) clazz.getDeclaringClass();
}
However, with this construct, there is not way to validate it your nested class is the real class, declared when implementing the generic interface.
I got an interesting issue. Consider the following code:
public class GenericsTest
{
// An interface with a generic type.
public interface IObject<K>{}
// An class with a generic type
public static class ObjectA<K>
{
// An inner class without generic type, but implementing the interface with generic Type
// When adding a genericType to this class, it will popup the warning: 'hiding'
public class ObjectB implements IObject<K>
{
}
// A getter with the interface as return Type
public IObject<K> getObjectB()
{
return new ObjectB();
}
}
public ObjectA<String> objectA = new ObjectA<String>();
// This field is yelling for an genericType, though it can't get one because the class doesn't support a generic argument.
public ObjectB genericObject = (ObjectB)objectA.getObjectB();
}
So the issue is that my IDE is complaining about a missing genericType of the genericObject field, and that I should add a SupressWarning annotation to the method. (luckily not code breaking, though still pretty annoying).
I could add a generic type to the inner class, though than it would 'hide' a generic argument, meaning I would need to add a SupressWarning annotation there.
A second fix would be to use a second generic type like <S extends K>. In which case I don't need a SupressWarning annotation at the class. Though when I try to use the getter, my IDE is complaining:
The member type GenericsTest.ObjectA.ObjectB<String> must be qualified with a parameterized type, since it is not static.
So basically I can't use the getter, unless I add an argument of the genericType to the method.
My question is, what is the cleanest way to solve this problem without changing the inner class to a nested class?
Here's a short example that compiles with no issues:
public class Test
{
interface K<T> { }
static class A<T>
{
class B implements K<T> { }
public K<T> getK() { return new B(); }
}
A<String> a = new A<String>();
A<String>.B b = (A<String>.B) a.getK();
}
Notice the last line:
A<String>.B b = (A<String>.B) a.getK();
To be honest, I'm not sure how the example you've given even compiles as far as it does - the class 'ObjectB' is not visible from the main 'GenericsTest' scope, it needs to be prefixed with its' parent class.
Class subA is the subclass of class A. I tried to override a method but Somehow it doesn't let me override it. why is that? Is it because of the argument in the parameter?
Error message read:
name clash: add(E#1) in subA and add(E#2) in A have the same erasure, yet neither overrides the other
where E#1,E#2 are type-variables:
E#1 extends Object declared in class subA
E#2 extends Object declared in class A
SuperClass A:
public class A <E> {
public void add(E toInsert) {...}
}
SubClass subA:
public class subA <E> extends A {
//overrides the method from A class
public void add (E toInsert) <-- doesn't let me overrides
{...}
}
You are subclassing the raw A class (generic parameters have not been provided), which by definition from the Java Language Specification strips all generic information from the superclass. This means that your subclass generic method is incompatible with the (now) non-generic superclass method.
Provide a generic parameter for A by passing through the generic parameter for your subclass:
public class subA <E extends Comparable<E>> extends A<E> {
#Override
public void add (E toInsert) {
// ...
}
}
Function Overriding in C++ Programming
If base class and derived class have member functions with same name and arguments. If you create an object of derived class and write code to access that member function then, the member function in derived class is only invoked, i.e., the member function of derived class overrides the member function of base class. This feature in C++ programming is known as function overriding.
Example to demonstrate function overriding in C++ programming
Accessing the Overridden Function in Base Class From Derived Class
To access the overridden function of base class from derived class, scope resolution operator ::. For example: If you want to access get_data() function of base class from derived class in above example then, the following statement is used in derived class.
A::get_data; // Calling get_data() of class A.
It is because, if the name of class is not specified, the compiler thinks get_data() function is calling itself.
User of scope resolution operator in overridden function
- See more at: http://www.programiz.com/cpp-programming/function-overriding#sthash.7UmWybpS.dpuf
public class subA <E extends A> extends A {
because E is defined in A you need to have your generic extend the same generic type of A is. I'm sure someone would have a better explanation than mine but I know this way works.
I know it's possible to add multiple constraints to a Generic class definition, e.g.:
class Example<I extends Object & Comparable<Object>>{}
But I want a generic (MyGeneric) that takes another generic (SomeGeneric<T>) as its type parameter, and to constrain the type parameter (T) of that generic (e.g. T extends SomeClass).
Important, I need to know the types of both SomeGeneric and SomeClass from inside the class (G and T need to both be bound). For example, imagine something like this:
class MyGeneric<G extends SomeGeneric<T>, T extends SomeClass>
{
public G returnSomeGenericImpl(){}
public T returnSomeClassImpl(){}
}
Question:
The above works, but I would prefer if my class had only one type parameter, to make life easier for implementers of my class. Is there a way of doing this?
Something like this would be nice (but this particular code is incorrect):
class MyGeneric<G extends SomeGeneric<T extends SomeClass>>
{
public G returnSomeGenericImpl(){}
public T returnSomeClassImpl(){}
}
If I wasn't clear, I'll gladly try to clarify my intent.
It looks impossible to achieve.
After reducing your type definition by one order by removing one type variable and trying to define it,
class G extends SomeGeneric<T extends SomeClass>{}
does not compile because the type parameter T is not bound with respect to an already defined type parameter. But, this works -
class G<T extends SomeClass> extends SomeGeneric<T>{}
So, I infer that the only way of parameterizing with two types is by declaring them up front.
try this
class Test1<T extends List<? extends Number>> {
public static void main(String[] args) throws Exception {
new Test1<ArrayList<Number>>();
new Test1<ArrayList<Integer>>();
new Test1<ArrayList<Object>>(); // compile error
}
}
Imagine this:
Type t = someClass();
Type g = someGeneric(t);
foobar(g,t)
compared to this
Type g = someGeneric(someClass());
foobar(g,?)
the second one is Evgeniy Dorofeev's solution.
You see the problem? You can't bind to a variable within an argument. Same with generics.
What you want to do is this
Type g = someGeneric(Type t = someClass());
foobar(g,t)
I have a utility class that needs to work on a generic Class but must be restricted to those that are an enum and implement a particular interface.
// These two work
Class<? extends Enum<?>> enumClass;
Class<? extends MyInterface> interfaceClass;
// This is what I want but does not work
Class<? extends MyInterface & Enum<?>> enumAndInterfaceClass;
For generics I can successfully use this
public class MyClass<T extends Enum<T> & MyInterface> {
public MyClass(Class<T> theClass) {
...
}
}
However I can't use the Generics everywhere and need to declare it separately. I am not sure if this is even possible.
So my question boils down to how can I declare a member variable with those constraints?
So Currently MyClass is a singleton then as needed the enum/interface can be updated. The return values of its operations will change depending on which enum it is given. I would like to not have the generics on it since that would require creating a new instance for every change to the enum. There is a lot of code using it already so deviating from the singleton is not going to be approved. So a reference must be kept. I suppose I could only enforce the Interface requirement then check in the setter method that it is an enum throwing an exception otherwise but that is not ideal.
Edit (Updated question and added more detail)
As far as I remember, you can only declare intersection types (this is what & creates) for type parameters of classes and methods. You can not declare a local variable with an intersection type directly; you can create such variables with the aid of a class or method type parameter, as seen in the answer of milkplusvellocet.
See the JLS reference in this answer to a similar question:
https://stackoverflow.com/a/6643378/282229
This should work:
public interface MyInterface {
void foo();
}
public final class Utils {
public static <E extends Enum<E> & MyInterface> void doWork(Class<E> clazz) {
for(E enumConstant : clazz.getEnumConstants) {
enumConstant.foo();
}
}
}
EDIT I didn't notice your line about using the captured type as a local variable. You can of course use this throughout the body of the parameterised method, see revised snippet above.