(Java) Static generic methods versus generic class static methods - java

I've read posts about why you can't have a (Edit -- generic) (which use that type parameter from the generic class) static method in a generic class, but why can you then use static generic methods in non generic classes? I don't see the why the second is allowed, but I kinda understand why the first isn't.

why you can't have a (Edit -- generic) (which use that type parameter from the generic class) static method in a generic class
The reason for this is simple: The type parameter is not associated with the class but with instances of the class.
I.e., you can't do
class Test<T> {
public static void sayHello(T t) { // T for which instance?!
System.out.println("Hello");
}
}
why can you then use static generic methods in non generic classes?
Why wouldn't you? A generic method takes the type parameter, so it doesn't matter if it's static or not, or if the class it's in is generic or not etc.
This for instance compiles fine:
class Test {
public static <T> void sayHello(T t) {
System.out.println("Hello " + t);
}
}
And you'd call the method like this:
Test.<String>sayHello("some argument");
^^^^^^^^
type parameter provided at the method-call: no instance required.

Related

generic type to static method

Example is pretty simple. What I want is written. The problems are in the comments.
import java.util.*;
class Main
{
private static class X<T> {
public static T get() { return new T(); }
}
public static void main(String[] args)
{
System.out.println(X<Interger>.get()); // illegal start of type
// commenting out above yields:
// error: non-static type variable T cannot be referenced from a static context
}
}
The real confounder to me is the error: non-static type variable T cannot be referenced from a static context. The error seems clear: the class & method are static but the type variable isn't. Can I make the type variable work in this static context.
Further, as the example is written, I don't understand why I get an illegal start of type error with nothing else. Is this because the error about the non-static type variable is hidden?
You can't do new T(). For one thing, there is no guarantee that T has an accessible no-args constructor. Relevant here, there is no no-arg constructor for Integer.
Static methods, as well as instance methods and constructors, can have type parameters.
public static <T> T get() {
// Can only legally return null or throw.
...
}
...
System.out.println(X.<Integer>get());
What to use instead? Possibly an abstract factory of some sort, possibly java.util.function.Supplier.
While the type X is generic, the class X is not. In Java, there are no "generic classes" (only generic types). What was most probably intended is a generic parameter on the static method:
private static class X<T> {
public static <T> T get() {
return ...;
}
}
Also, since generics are erased, one cannot instantiate T (thus the three dots in the code above).
One would call the method like such:
...
X.<SomeConcreteType>get();
I think Supplier maybe more suitable for you than static X<T>.get:
public static class aClass {}
public static <T> aMethodWantToUseX(Supplier<T> x) {
T t = x.get();
}
aMethodWantToUseX(aClass::new)

Can I make a constructor generic without making the class generic?

I have seen in Java that one can make a Class generic and a method generic. I have also seen codes that make the constructor generic along with the Class. Can I make only the constructor generic? And if yes, how to call the constructor?
Yes you can.
class Example {
public <T> Example(T t) {}
public static void main(String[] args){
// In this example the type can be inferred, so new Example("foo")
// works, but here is the syntax just to show you the general case.
Example example = new<String>Example("foo");
}
}

generic declaration confusion

I'm reading an article by Brain Goetz. I had a doubt regarding factory method for the below code.
public class BoxImpl<T> implements Box<T> {
public static<V> Box<V> make() {
return new BoxImpl<V>();
}
Author had written this to reduce the redundancy of redeclaration of the type parameters as
Box<String> box=new Box<String>();
So, he used the factory method like above.
Box<String> myBox = BoxImpl.make();
But here my doubt is why <V> in the make method of the Box class, why can't we use like below:
public class BoxImpl<T> implements Box<T> {
public static<T> Box<T> make() {
return new BoxImpl<T>();
}
What is the difference between above two ?
This technique (used, among the others, by the Guava collections) was quite useful before the introduction of the diamond operator <> in Java 7, to avoid very noisy code like:
// Java 5:
Box<Map<String, List<Integer>> box = new BoxImpl<Map<String, List<Integer>>();
// with static inference
Box<Map<String, List<Integer>> box = BoxImpl.make();
// with diamond operator - Java7
Box<Map<String, List<Integer>> box = new BoxImpl<>();
As per why declaring a new type parameter V in the make method, it's because it's static, and static method can't access type arguments because they are out of scope, and belong to a specific instantiation of a type (similar to instance variables, that can't be used in static methods)
This
public class BoxImpl<T> implements Box<T> {
is a generic class declaration. It declares a type variable T for use in instance class members.
This
public static<V> Box<V> make() {
return new BoxImpl<V>();
}
is a generic method. It declares its own generic variables and is static. It cannot use the class type variables.
The name of the type variable is not an issue here. The name could be the same, but it will not be referring to the same type.
Making that method generic is important, because you can't use the type parameter T of the class in a static context. So the following code wouldn't compile:
class BoxImpl<T> implements Box<T> {
// Will fail to compile. Cannot use type parameter `T` in static context
public static Box<T> make() {
return new BoxImpl<T>();
}
}
From Java Generics FAQs:
The scope of a class's type parameter is the entire definition of the
class, except any static members or static initializers of the class.
This means that the type parameters cannot be used in the declaration
of static fields or methods or in static nested types or static
initializers.

Genereic class and static generic method

I'm writing generic class
public class SomeClass<T> {
public static <T extends Comparable<? super T>> T min(Collection<? extends T> c) {
T min = c.iterator().next();
for (T element : c)
if (element.compareTo(min) < 0)
min = element;
return min;
}
}
public class Main {
public static void main(String[] args) {
SomeClass<Integer>.min(Arrays.asList(1, 2, 3)); // compile-time error
SomeClass.min(Arrays.asList(1, 2, 3)); // ok
}
}
In generic class SomeClass and generic method SomeMethod type-parameter T is the same or defference?
Why we have compile time-error on the string SomeClass<Integer>.min(Arrays.asList(1,2,3));?
The class declaration
public class SomeClass<T>
defines a generic class, where <T> specifies the type parameter (also called type variable). This introduces the type variable, T, that can be used anywhere inside the class.
And the method declaration:
public static <T extends Comparable<? super T>> T min(Collection<? extends T> c) {
...
}
defines a generic method. Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared.
Now if you want to call the generic method min, you need to call:
SomeClass.<Integer>min(Arrays.asList(1,2,3));
It's different, and you should never write code like this, specifically because of the possibility for confusion. Always use different type variables on classes and methods inside those classes.
T is for Type and you are accessing static method which has nothing to do with T.
Either use like this
SomeClass<Integer> a = new SomeClass<Integer>();
a.min(Arrays.asList(1, 2, 3));
OR
SomeClass.min(Arrays.asList(1, 2, 3));
The two Ts are different: the fist one is a parameter for the class (and is unused) and the second one is specific to the method. Since the method is static, the class parameter doesn’t affect it.
When you write SomeClass<Integer>.min(Arrays.asList(1, 2, 3));, you get an error because it doesn’t make sense to add a parameter to SomeClass since no object of that class is instanciated. SomeClass is only used to tell the compiler that you want to call a static method from that class. You can add a parameter to the method with SomeClass.<Integer>min(Arrays.asList(1, 2, 3));, but you don't have to since the compiler can infer the type here.
So what the compile message told you was that it's a syntax error. Why it's invalid syntax is easy to understand. You are trying to call a method on a type. That means you are calling a static method. Static methods are not within the scope of generic type parameters. So it is not allowed to put a generic type argument on the left side.
If you want the technical reason, it's because your method call expression is not one of the forms that's allowed by the syntax. The closest form to yours is TypeName . NonWildTypeArguments Identifier ( ArgumentListopt ). But TypeName (which is defined here) must be an identifier or package-qualified identifier. It does not allow brackets.

Generics Java and Shadowing of type parameters

This code seems to work fine
class Rule<T>
{
public <T>Rule(T t)
{
}
public <T> void Foo(T t)
{
}
}
Does the method type parameter shadow the class type parameter?
Also when you create an object does it use the type parameter of the class?
example
Rule<String> r = new Rule<String>();
Does this normally apply to the type parameter of the class, in the situation where they do not conflict? I mean when only the class has a type parameter, not the constructor, or does this look for a type parameter in the constructor? If they do conflict how does this change?
SEE DISCUSSION BELOW
if I have a function call
x = <Type Parameter>method(); // this is a syntax error even inside the function or class ; I must place a this before it, why is this, and does everything still hold true. Why don't I need to prefix anything for the constructor call. Shouldn't Oracle fix this.
All of your Ts are different, but you can only see it if you call your methods with the complete syntax:
For example, this code is valid:
new <Float>Rule<Integer>().<Character>Foo();
Just to make this easier to explain, let's assume your code is this:
class Rule<A>
{
public <B>Rule()
{
}
public <C> void Foo()
{
}
}
Then you can explicitly declare generic types like:
new <B>Rule<A>().<C>Foo();
If the types have the same name, the inner-most one will be chosen (the T on the method, not the class):
With this code, taking parameters:
class Rule<T>
{
public <T>Rule(T t)
{
}
public <T> void Foo(T t)
{
}
}
Then this is valid:
new <Float>Rule<Integer>(3.2f);
Note that T in the constructor is Float, not Integer.
Another example:
class Example<T> {
public <T> void foo1() {
// T here is the <T> declared on foo1
}
public void foo2() {
// T here is the <T> declared on the class Example
}
}
I found another question that deals with calling methods with explicit generic types without something before them. It seems like static imports and same-class method calls are the same. It seems like Java doesn't let you start a line with <Type> for some reason.
Does the method type parameter shadow the class type parameter?
The <T> declaration on constructor is not referred to class type. So yes, it shadow the class type parameter.
In this case it is used as a generic type param that you can use with the constructor, for example as argument. Try this constructor:
public <P> Rule(P arg1, P arg2) {
}
As you can see I define a type <P> and then I use it to be sure that the arguments will be of type P. In your case you are declaring a type that will be valid for the constructor without using it.
Look at this page.
Also when you create an object does it use the type parameter of the class?
Every generic type definition has is scope as a variable. So out of the constructor returns valid the class type.

Categories