Sure, I have do some research like package scan, reflection of java, gson and so on.
What I want?
I want get some instance randomly but keep this part code in the subclass.
So, each subclass should have a method named like SuperClass nextInstance().
If I get subclass List, say classes, by reflection, I just need invoke nextInstance for each element in classes.
That's just be done.
But, I need add static method for every subclass, and the name must be nextInstance, real stupid!!!
Why I wanna doing this.
There is a huge test project that I need run.
And each subclass has their own parameters(it is randomly).
I wanna hide the parameters settings.
The co-worker does not need to care what the parameters are.
They just need to care their own code.
I think the only way to implement that, is extend a method from superClass.
What I have do.
Create a factory class for each of them(too troublesome).
Add subclass path in a List to loading them in runtime(Hard to maintain).
Try a abstract static method by reflection(impossible in java).
And so on(may be, I give it up)
Example
Abstract class SuperClass{
// I know it is impossible in java, but just explain what I mean.
public static abstract SuperClass nextInstance();
}
class SubClassA extend SuperClass{
private double params;
public SuperClass(double parmas){
this.params = params;
}
public static SuperClass nextInstance(){
return new SubClassA(r.nextDouble()+4);
}
}
class SubClassB extend SuperClass{
private int params;
public SuperClass(int parmas){
this.params = params;
}
public static SuperClass nextInstance(){
return new SubClassB(r.nextInt(20)+4);
}
}
class Main{
public static void main(String[] args){
List<Class> classes.....// get classes extend from SuperClass by reflection.
List<SuperClass> res = new ArrayList<>();
for(Class c:classes){
res.add(c.nextInstance())
}
// do something on each element in res.
}
}
Update
I think I need simpler re-explain what I want to do.
If there anyone has used slfj LoggerFactory.getLogger(Class c),it will be easier to understand.
For me, I need implement a method like Factory.getInstance(Class c), and the code in this method will invoke c.nextInstance();
Any suggest about it?
Ok so you can't declare your "public static abstract" method in the super class but you can tell your co-workers just to include a method which is "public static" returns a SuperClass and accepts no arguments and then find that method by reflection in your factory:
public static class Main {
public static void main(String[] args) {
List<Class> classes.....// get classes extend from SuperClass by reflection.
List<SuperClass> res = new ArrayList<>();
for (Class<?> clazz : classes) {
for (Method method : clazz.getMethods()) {
if (isStatic(method) && returnsSuperClass(method) && hasNoParameters(method)) {
res.add((SuperClass) method.invoke(null));
}
}
}
}
public static boolean hasNoParameters(Method method) {
return method.getParameterTypes().length == 0;
}
public static boolean returnsSuperClass(Method method) {
return SuperClass.class.isAssignableFrom(method.getReturnType());
}
public static boolean isStatic(Method method) {
return (method.getModifiers() & Modifier.STATIC) == Modifier.STATIC;
}
}
Related
I am trying to create a generic method, but it requires data from the sub class. Is there a way to do this, or is there a better implementation?
Example of my situation:
public class Super {
public static Object method() {
return doSomethingWith(specificToSubClassValue);
}
}
public class Sub1 extends Super {
public static String specificToSubClassValue = "123";
}
public class Sub2 extends Super {
public static String specificToSubClassValue = "456";
}
I obviously cannot do this. What is a better approach?
One alternative I can think of is to override the #method method in each sub class, but it will be the same code in each instance so I wanted to throw it in the parent class (and it won't be truly overridden since it is static), but I am not sure how to approach it since it is dependent on the sub class value.
Static methods in Java can't be overwritten, and can't access children-specific information: they know nothing about inheritance.
What you need here is instance method, which you can overwrite. An you also may use generics.
public class Super<T> {
public Object method() {
final T specificToSubClassValue = getSpecificToSubClassValue();
if (specificToSubClassValue != null) {
return specificToSubClassValue.hashCode();
} else {
return null;
}
}
protected T getSpecificToSubClassValue() {
return null;
}
}
class Sub1 extends Super<String> {
#Override
protected String getSpecificToSubClassValue() {
return "abc";
}
}
class Sub2 extends Super<Integer> {
#Override
protected Integer getSpecificToSubClassValue() {
return 123;
}
}
Declare an abstract method in Super, which will be used to return the value from the implementing classes. Note that this can only be achieved with non-static methods. As per #JB Nizet's comment, static methods cannot be overriden by subclasses. I've removed the static modifier from the code below to shown you how it would work.
public class Super {
public static Object method() {
return doSomethingWith(specificToSubClassValue);
}
protected abstract Object getValue ();
}
public class Sub1 extends Super {
public static String specificToSubClassValue = "123";
#Override
protected Object getValue () {
return specificToSubClassValue;
}
}
public class Sub2 extends Super {
public static String specificToSubClassValue = "456";
#Override
protected Object getValue () {
return specificToSubClassValue;
}
}
Well, te whole idea of inheritance is that the superclass should not be able to do that much without the sub-class. Otherwise the whole inheritance would be pointless exercise and spaghetti code. But you are tackling the problem the wrong way. Make sub-class "spill" the data you need (through getter) and use the generic method from superclass on the data in the sub-class.
Also the overriding of super class methods is highly overrated. You should strive for your super method to be as flexible and re-usable as possible, and even then strive rather for overloading, instead of overriding.
You could have:
public class Super {
public Object method(String specificValue) {
return doSomethingWith(specificToSubClassValue);
}
And then have your sub do this
public class Sub1 extends Super {
public static String specificToSubClassValue = "123";
Object method(specificToSubClassValue);
}
This way you accomplish exactly what you want, operate on the class specific value using the super method.
I want to make a unit test that will ensure that all subclasses implement a method.
Some code may better explain what I am trying to do.
The super class is like this:
class SuperClass
{
public boolean isImportant()
{
throw customException;
}
}
Now say that I have sub classes A and B.
I'd like to ensure that this is included in those classes, so like:
class A extends SuperClass
{
#Override
public boolean isImportant()
{
return true; //or false
}
}
and class b:
class B extends SuperClass
{
}
Now if I do B b = new B(); b.isImportant() I will get the exception.
Instead of having a test for each class (there are many and I may miss some and in the future more subclasses may be added), how can I easily test this.
I am thinking if there is some way to instantiate a object of every subclass.
Something like this:
for(Class subClass : SuperClass.subclasses)
{
subClass obj = new subClass();
obj.isImportant();
}
As this will iterate through all the subclasses, regardless of if some are added or removed and will fail if there is an exception thrown.
Is there some way to do this?
Make the method abstract and subclasses have to implement it, or they won't compile. No unit test needed (for that, anyway).
Update
Now, if you can't (or don't want to) change the method to abstract, you can test it like this.
class SuperClass {
public boolean isImportant() { throw new UnsupportedOperationException(); }
}
class A extends SuperClass {
#Override
public boolean isImportant() { return true; }
}
class B extends SuperClass {
}
class TestIsImportant {
#SuppressWarnings("unchecked")
private static final Class<?>[] classesToTest = new Class[] {
A.class, B.class
};
#Test
public void test() throws Exception {
for (Class<?> classToTest : classesToTest) {
classToTest.getDeclaredMethod("isImportant");
}
}
}
This will throw NoSuchMethodException if method is not implemented, and it's easy to add to the list of classes to test.
I think what you're trying to test is weird and you should probably go with #Andreas's solution:
Make the method abstract and subclasses have to implement it, or they
won't compile. No unit test needed (for that, anyway).
That being said, here's how you'd test what you want:
public class SuperClass {
public void method() {
System.out.println("Default implementation.");
}
}
public class SubClassA extends SuperClass {
#Override
public void method() {
System.out.println("Overridden implementation.");
}
}
public class SubClassB extends SuperClass {}
public class TestClass {
#Test
public void test() throws NoSuchMethodException {
// nothing happens here
SubClassA.class.getDeclaredMethod("isImportant");
// the line below throws NoSuchMethodException, failing the test
SubClassB.class.getDeclaredMethod("isImportant");
}
}
Now, if you want to be able to loop through all SuperClass subclasses, you should take a look at this:
How do you find all subclasses of a given class in Java?
I don't understand how exactly you think unit testing relates to the inheritance in your case. If you need to ensure that isImportant() is implemented/inherited in the subclasses, simply make A and B extend the SuperClass. Then you can be sure all all subclasses forever will have all the methods of the SuperClass.
class A extends SuperClass {
...
If the method is not implemented in the super class, but you still want to do what you have written, make the SuperClass abstract.
Or finally, define an interface like:
interface SuperInterface {
boolean isImportant();
}
...and make A and B to implement it. This is probably the cleanest way to do.
I'm sure this will have been asked before but I can't find it after searching for some time.
I need a function that will do something like the following:
public static AbstractClass createClass(Class<AbstractClass> theChildClass, int someVariable){
AbstractClass theInstance = theChildClass.newInstance(someVariable);
return theInstance;
}
Then on AbstractClass I want to define it like so:
public abstract class AbstractClass{
private int someVariable;
public AbstractClass(int someVariable){
this.someVariable = someVariable;
initOnChild();
}
protected abstract void initOnChild();
}
Then on the child classes I ideally don't want to define the "public ChildClass(int someVariable){}" method, so they look like this:
public class ChildClass extends AbstractClass{
#Override
protected void initOnChild(){
//do some stuff
}
}
The ideal outcome I'm after is being able to call the method like so:
ChildClass theInstance = UtilityClass.createClass(ChildClass.class, 1);
Is this even possible? Any solutions or advice much appreciated.
No. Constructors are not inherited (and therefore are not members in JLS-speak). Depending on the situation you may want to apply the strategy pattern, say.
(ObNote: Generally it's considered a bad idea to call overrideable methods from constructors, and reflection is almost always a really bad idea.)
No, but there is a solution.
First the problem with calling an overriden method in the constructor:
abstract class A {
A() {
init();
}
protected abstract void init();
}
class B extends A {
public String x = null;
public String y;
#Override
protected void init() {
x = "x";
y = "y";
}
}
public static void main(String[] args) {
B b = new B();
System.out.printf("x=%s, y=%s%n", b.x, b.y);
}
Would of course give:
x=null, y=y
in B() - all fields zeroed
super() called, A()
in A() B.init() called
in B() field initialisations are done
But it is not obvious from reading superficially, and when using fields in the base class, can become less obvious.
Now the solution.
As you have a static factory method, maybe place this method in AbstractClass. Then it can call init after construction.
public static <T extends AbstractClass> T create(Class<T> childClass, int param) {
T instance = childClass.getConstructor().newInstance();
instance.init(param);
return instance;
}
This executes the default constructor.
Should this still be unsatisfactory, then it just might be that some datastructure does not reside in the correct inheritance level, or should be restructured.
How would you declare a static variable in Super and instantiate it in subclass
Example
class A
{
static Queue<String> myArray;
public void doStuff()
{
myArray.add(someMethod.getStuff());
}
}
class B extends A
{
myArray = new LinkedList<String>();
}
class C extends A
{
myArray = new LinkedList<String>();
}
Obviously this doesnt work. But how would you go about declaring a variable; then doing some common functionality with the variable in the super class; Then making sure each subclass gets it own static LinkedList?
You can't do stuff along these lines. The closest you can do is to have an abstract (non-static) method in the superclass and do some stuff with it.
But in general, you cannot force subclasses to do anything static, and you cannot access subclasses' static fields from a superclass like you're trying to do.
Since, you have subclass-specific properties to manipulate, you can't do it in the superclass, and it is not logical to do it anyways. As was already mentioned, you can do something like this:
abstract class A {
public abstract void doStuff();
}
class B extends A {
static List<String>myArray = new LinkedList<String>();
public abstract void doStuff() {
// do B stuff
}
}
class C extends A {
static List<String>myArray = new LinkedList<String>();
public abstract void doStuff() {
// do C stuff
}
}
Static variable is bound to a class rather than an instance. If you need a separate static variable for subclasses, you need to declare them in each of your subclasses.
In Java, I'd like to have something as:
class Clazz<T> {
static void doIt(T object) {
// ...
}
}
But I get
Cannot make a static reference to the non-static type T
I don't understand generics beyond the basic uses and thus can't make much sense of that. It doesn't help that I wasn't able to find much info on the internet about the subject.
Could someone clarify if such use is possible, by a similar manner? Also, why was my original attempt unsuccessful?
You can't use a class's generic type parameters in static methods or static fields. The class's type parameters are only in scope for instance methods and instance fields. For static fields and static methods, they are shared among all instances of the class, even instances of different type parameters, so obviously they cannot depend on a particular type parameter.
It doesn't seem like your problem should require using the class's type parameter. If you describe what you are trying to do in more detail, maybe we can help you find a better way to do it.
Java doesn't know what T is until you instantiate a type.
Maybe you can execute static methods by calling Clazz<T>.doit(something) but it sounds like you can't.
The other way to handle things is to put the type parameter in the method itself:
static <U> void doIt(U object)
which doesn't get you the right restriction on U, but it's better than nothing....
I ran into this same problem. I found my answer by downloading the source code for Collections.sort in the java framework. The answer I used was to put the <T> generic in the method, not in the class definition.
So this worked:
public class QuickSortArray {
public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){
//do it
}
}
Of course, after reading the answers above I realized that this would be an acceptable alternative without using a generic class:
public static void quickSort(Comparable[] array, int bottom, int top){
//do it
}
I think this syntax has not been mentionned yet (in the case you want a method without arguments) :
class Clazz {
static <T> T doIt() {
// shake that booty
}
}
And the call :
String str = Clazz.<String>doIt();
Hope this help someone.
It is possible to do what you want by using the syntax for generic methods when declaring your doIt() method (notice the addition of <T> between static and void in the method signature of doIt()):
class Clazz<T> {
static <T> void doIt(T object) {
// shake that booty
}
}
I got Eclipse editor to accept the above code without the Cannot make a static reference to the non-static type T error and then expanded it to the following working program (complete with somewhat age-appropriate cultural reference):
public class Clazz<T> {
static <T> void doIt(T object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
private static class KC {
}
private static class SunshineBand {
}
public static void main(String args[]) {
KC kc = new KC();
SunshineBand sunshineBand = new SunshineBand();
Clazz.doIt(kc);
Clazz.doIt(sunshineBand);
}
}
Which prints these lines to the console when I run it:
shake that booty 'class com.eclipseoptions.datamanager.Clazz$KC' !!!
shake that booty 'class com.eclipseoptions.datamanager.Clazz$SunshineBand' !!!
It is correctly mentioned in the error: you cannot make a static reference to non-static type T. The reason is the type parameter T can be replaced by any of the type argument e.g. Clazz<String> or Clazz<integer> etc. But static fields/methods are shared by all non-static objects of the class.
The following excerpt is taken from the doc:
A class's static field is a class-level variable shared by all
non-static objects of the class. Hence, static fields of type
parameters are not allowed. Consider the following class:
public class MobileDevice<T> {
private static T os;
// ...
}
If static fields of type parameters were allowed, then the following code would be confused:
MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();
Because the static field os is shared by phone, pager, and pc, what is the actual type of os? It cannot be Smartphone, Pager, and
TabletPC at the same time. You cannot, therefore, create static fields
of type parameters.
As rightly pointed out by chris in his answer you need to use type parameter with the method and not with the class in this case. You can write it like:
static <E> void doIt(E object)
Something like the following would get you closer
class Clazz
{
public static <U extends Clazz> void doIt(U thing)
{
}
}
EDIT: Updated example with more detail
public abstract class Thingo
{
public static <U extends Thingo> void doIt(U p_thingo)
{
p_thingo.thing();
}
protected abstract void thing();
}
class SubThingoOne extends Thingo
{
#Override
protected void thing()
{
System.out.println("SubThingoOne");
}
}
class SubThingoTwo extends Thingo
{
#Override
protected void thing()
{
System.out.println("SuThingoTwo");
}
}
public class ThingoTest
{
#Test
public void test()
{
Thingo t1 = new SubThingoOne();
Thingo t2 = new SubThingoTwo();
Thingo.doIt(t1);
Thingo.doIt(t2);
// compile error --> Thingo.doIt(new Object());
}
}
Since static variables are shared by all instances of the class. For example if you are having following code
class Class<T> {
static void doIt(T object) {
// using T here
}
}
T is available only after an instance is created. But static methods can be used even before instances are available. So, Generic type parameters cannot be referenced inside static methods and variables
When you specify a generic type for your class, JVM know about it only having an instance of your class, not definition. Each definition has only parametrized type.
Generics work like templates in C++, so you should first instantiate your class, then use the function with the type being specified.
Also to put it in simple terms, it happens because of the "Erasure" property of the generics.Which means that although we define ArrayList<Integer> and ArrayList<String> , at the compile time it stays as two different concrete types but at the runtime the JVM erases generic types and creates only one ArrayList class instead of two classes. So when we define a static type method or anything for a generic, it is shared by all instances of that generic, in my example it is shared by both ArrayList<Integer> and ArrayList<String> .That's why you get the error.A Generic Type Parameter of a Class Is Not Allowed in a Static Context!
#BD at Rivenhill: Since this old question has gotten renewed attention last year, let us go on a bit, just for the sake of discussion.
The body of your doIt method does not do anything T-specific at all. Here it is:
public class Clazz<T> {
static <T> void doIt(T object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
// ...
}
So you can entirely drop all type variables and just code
public class Clazz {
static void doIt(Object object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
// ...
}
Ok. But let's get back closer to the original problem. The first type variable on the class declaration is redundant. Only the second one on the method is needed. Here we go again, but it is not the final answer, yet:
public class Clazz {
static <T extends Saying> void doIt(T object) {
System.out.println("shake that booty "+ object.say());
}
public static void main(String args[]) {
Clazz.doIt(new KC());
Clazz.doIt(new SunshineBand());
}
}
// Output:
// KC
// Sunshine
interface Saying {
public String say();
}
class KC implements Saying {
public String say() {
return "KC";
}
}
class SunshineBand implements Saying {
public String say() {
return "Sunshine";
}
}
However, it's all too much fuss about nothing, since the following version works just the same way. All it needs is the interface type on the method parameter. No type variables in sight anywhere. Was that really the original problem?
public class Clazz {
static void doIt(Saying object) {
System.out.println("shake that booty "+ object.say());
}
public static void main(String args[]) {
Clazz.doIt(new KC());
Clazz.doIt(new SunshineBand());
}
}
interface Saying {
public String say();
}
class KC implements Saying {
public String say() {
return "KC";
}
}
class SunshineBand implements Saying {
public String say() {
return "Sunshine";
}
}
T is not in the scope of the static methods and so you can't use T in the static method. You would need to define a different type parameter for the static method. I would write it like this:
class Clazz<T> {
static <U> void doIt(U object) {
// ...
}
}
For example:
public class Tuple<T> {
private T[] elements;
public static <E> Tuple<E> of(E ...args){
if (args.length == 0)
return new Tuple<E>();
return new Tuple<E>(args);
}
//other methods
}