I have several child classes extending an abstract parent class. I want the parent class to have a static ArrayList holding instances of each child. If possible, I would like to be able to add more child classes without having to change the parent class's code.
One solution I came up with is to give each of the child classes a static block that will add an instance of itself to the ArrayList. The only problem with this is that I then need to make some call to each child to get it to load and run the block.
abstract public class Parent {
protected static ArrayList<Parent> children = new ArrayList<Parent>();
}
public class ChildA extends Parent {
static {
children.add(new ChildA());
}
}
public class ChildB extends Parent {
static {
children.add(new ChildB());
}
}
Is there a way around this? Can I load a class without making a call to it? Would there be any better ways of doing this?
Edit:
This is actually for a tile based game. I have an abstract "Tile" class and an arbitrary number of tile types extending it. I would like to be able to easily add new tiles to the game without having to change the code all over the place. If you have a better idea for how to do this, I am open to suggestion.
You can do it outside the class hierarchy. Have a utility function that uses reflection to find all descendants of Parent and then adds them to your list.
Your motivation for wanting to do this is unclear, but there are solutions that don't necessarily involve reflection.
Shift the responsibility for creating the child classes into a factory class. In that factory class, insert the children classes into your list as well.
Here's a snippet that could do just that. Remember: because your list is bound to Parent, you will have to cast to the correct child class type to actually use the classes later.
public final class ChildFactory {
private static ChildFactory instance = new ChildFactory();
private ChildFactory() {
}
public <C extends Parent> C generateChild(Class<C> childClass) {
try {
final C child = childClass.newInstance();
Parent.children.add(child);
return child;
} catch(InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static ChildFactory getInstance() {
return instance;
}
}
I think threre might be an easier way to do it but this class may be usefull:
package classFinder;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassFinder {
protected static Class<?> getClass(String prefix, String classPath)
throws ClassNotFoundException {
if (!classPath.endsWith(".class") || !classPath.startsWith(prefix)) {
return null;
}
return Class.forName(classPath.substring(prefix.length(),
classPath.length() - ".class".length()).replace('/', '.'));
}
protected static Class<?> getClass(File rootFile, File classFile)
throws ClassNotFoundException {
return getClass(rootFile.getPath() + '/', classFile.getPath());
}
#SuppressWarnings("unchecked")
protected static <T> Set<Class<T>> searchAllSubclassesInDirectory(
File rootFile, File searchFile, Class<?> cls,
boolean abstractClasses) throws ClassFinderException {
Set<Class<T>> result = new HashSet<Class<T>>();
if (searchFile.isDirectory()) {
for (File file : searchFile.listFiles()) {
result.addAll(ClassFinder.<T> searchAllSubclasses(
rootFile.getPath(), file.getPath(), cls,
abstractClasses));
}
return result;
}
String fileName = searchFile.getName();
if (!fileName.endsWith(".class")) {
return result;
}
try {
Class<?> entry = getClass(rootFile, searchFile);
if (entry != null
&& (abstractClasses || !Modifier.isAbstract(entry
.getModifiers()))) {
Class<?> superClass = entry;
while (!((superClass = superClass.getSuperclass()) == null)) {
if (superClass.equals(cls)) {
result.add((Class<T>) entry);
return result;
}
}
}
return result;
} catch (ClassNotFoundException e) {
// e.printStackTrace(); //DEBUG only
return result;
}
}
#SuppressWarnings("unchecked")
protected static <T> Set<Class<T>> searchAllSubclassesInJar(File jar,
Class<?> cls, boolean abstractClasses) {
Set<Class<T>> result = new HashSet<Class<T>>();
try {
JarFile jarFile = new JarFile(jar);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry file = entries.nextElement();
if (file.isDirectory()) {
continue;
}
Class<?> entry = getClass("", file.getName());
if (entry != null
&& (abstractClasses || !Modifier.isAbstract(entry
.getModifiers()))) {
Class<?> superClass = entry;
while (!((superClass = superClass.getSuperclass()) == null)) {
if (superClass.equals(cls)) {
result.add((Class<T>) entry);
}
}
}
}
jarFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
protected static <T> Set<Class<T>> searchAllSubclasses(String rootPath,
String searchPath, Class<?> cls, boolean abstractClasses)
throws ClassFinderException {
if (searchPath.endsWith(".jar")) {
return searchAllSubclassesInJar(new File(searchPath), cls,
abstractClasses);
// return new HashSet<Class<T>>();
} else {
return searchAllSubclassesInDirectory(new File(rootPath), new File(
searchPath), cls, abstractClasses);
}
}
// TODO create public method to search inside a not root directory/package
public static <T> Set<Class<T>> searchAllSubclasses(Class<?> cls,
boolean abstractClasses) throws ClassFinderException {
Set<Class<T>> result = new HashSet<Class<T>>();
String classpath = System.getProperty("java.class.path");
for (String path : classpath
.split(System.getProperty("path.separator"))) {
result.addAll(ClassFinder.<T> searchAllSubclasses(path, path, cls,
abstractClasses));
}
return result;
// return ClassFinder.<T> searchAllSubclasses(ROOT_URL, cls,
// abstractClasses, "");
}
}
If you're working with a standard java desktop application it may work.
This class searches for implementations of a given superclass on a your program directory tree. Works for jar files too.
You can then initialize your static field:
abstract public class Parent {
protected static Set<Parent> children = ClassFinder
.<Parent> searchAllSubclasses(Parent.class, true);
}
Related
I have a java jar file contain interface named IOperator like this :
public interface IOperator {
String execute(Map<String, String> parameters);
boolean isSuccess();
}
now in groovy script (in single file):
public class ClassA {
}
public class ClassB {
}
public class classC implements IOperator {
#Override
String execute(Map<String, String> parameters) {
ClassA classA = new ClassA();
ClassB classB = new ClassB();
return null
}
#Override
boolean isSuccess() {
return false
}
}
Is there any way scan this groovy script to find that specific class implemented IOperator and invoke execute method ?
Note: I want do it in Java code.
Finally i found answer :
public class OperatorManager {
public static void run(File scriptFile) {
try {
GroovyScriptEngineImpl engine = (GroovyScriptEngineImpl) new GroovyScriptEngineFactory().getScriptEngine();
GroovyClassLoader classLoader = new GroovyClassLoader();
classLoader.parseClass(new GroovyCodeSource(scriptFile));
engine.setClassLoader(classLoader);
Class<?>[] loadedClasses = engine.getClassLoader().getLoadedClasses();
Class<?> operatorImplClass = Arrays.stream(loadedClasses)
.filter(IOperator.class::isAssignableFrom)
.findFirst().orElse(null);
if (operatorImplClass != null) {
String result = invokeMethod(operatorImplClass);
System.out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String invokeMethod(Class<?> item) {
try {
Object instance = item.getConstructor().newInstance();
Method execute = item.getDeclaredMethod("execute", Map.class);
return (String) execute.invoke(instance, new Object[]{null});
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
I am trying to develop a dynamic Factory Class, where Factory Class does not know the factories, I will put the code so that the question is clearer.
App.java:
package br.com.factory;
public class App {
public static void main(String[] args) {
Product product = ProductFactory.createProduct("Xiaomi", "MI XX");
if (product != null) {
System.out.println(product.getName());
}
}
}
Product.java:
package br.com.factory;
public interface Product {
public String getName();
}
ProductFactory.java:
package br.com.factory;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class ProductFactory {
private static HashMap<String, Map<String, Supplier<Product>>> registries = new HashMap<>();
private ProductFactory(){}
static {
ClassLoaderInitializer.initialize(ProductSupplier.class);
}
public static Product createProduct(String manufacturer, String model) {
Map<String, Supplier<Product>> manufacturers = registries.getOrDefault(manufacturer, null);
if (manufacturers != null){
Supplier<Product> suppliers = manufacturers.getOrDefault(model, null);
if (suppliers != null) {
return suppliers.get();
}
}
return null;
}
public static void registerFactory(String manufacturer, String model, Supplier<Product> supplier) {
registries
.computeIfAbsent(manufacturer, p -> new HashMap<>())
.putIfAbsent(model, supplier);
}
}
ProductSupplier.java:
package br.com.factory;
import java.util.function.Supplier;
public interface ProductSupplier extends Supplier<Product> {
}
XiaomiFactory.java:
package br.com.factory.xiaomi;
import br.com.factory.Product;
import br.com.factory.ProductFactory;
import br.com.factory.ProductSupplier;
public class XiaomiFactory implements ProductSupplier {
static {
ProductFactory.registerFactory("Xiaomi", "MI XX", XiamoMiXX::new);
}
private XiaomiFactory() {
}
#Override
public Product get() {
return new XiamoMiXX();
}
}
class XiamoMiXX implements Product {
#Override
public String getName() {
return "Xiaomi Mi XX";
}
}
ClassLoaderInitializer.java:
package br.com.factory;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
public class ClassLoaderInitializer {
private ClassLoaderInitializer() {
}
public static void initialize(Class<?> parentClass) {
try {
Enumeration<URL> resources = ClassLoaderInitializer.class.getClassLoader().getResources("");
while (resources.hasMoreElements()) {
URL nextElement = resources.nextElement();
try (URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { nextElement });) {
URL[] urLs = urlClassLoader.getURLs();
for (URL u : urLs) {
try {
File file = new File(u.toURI());
initializeClass(file, file, urlClassLoader, parentClass);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void initializeClass(File root, File file, ClassLoader loader, Class<?> parentClass) {
if (file.isDirectory()) {
File[] listFiles = file.listFiles();
for (File f : listFiles) {
initializeClass(root, f, loader, parentClass);
}
} else {
if (file.getName().toUpperCase().endsWith(".class".toUpperCase())) {
try {
String fileName = file.toString();
String className = fileName.substring(root.toString().length() + 1,
fileName.toUpperCase().lastIndexOf(".class".toUpperCase())).replace(File.separator, ".");
Class<?> clazz = Class.forName(className, false, loader);
if (clazz.isAssignableFrom(parentClass)) {
Class.forName(className, true, loader);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
The problem occurs in the initializeClass method,
more precisely in:
Class <?> Clazz = Class.forName (className, false, loader);
if (clazz.isAssignableFrom (parentClass)) {
Class.forName (className, true, loader);
}
the idea of the ClassLoaderInitializer class is to initialize the classes that inherit from a given class "Class <?> parentClass"
but when I call the method
Class.forName (className, true, loader);
for the second time, passing true in the second parameter, the class is not initialized.
if I call:
Class.forName (className, true, loader);
directly, the initializeClass method will initialize all classes, what I would not like to happen.
is there any outside of me explicitly initializing (forcing) the class specifies?
Use ServiceLoader
ServiceLoader allows you to register services using metadata in the META-INF/services/ folder. It allows you to use a Java API to register all your services at once. It's better than trying to do it yourself, especially since it's standardized and doesn't require "magic" to get registered. Magic which might be broken in Java 9 and later with the introduction of modules.
This is how you should use it:
ProductSupplier.java
public interface ProductSupplier extends Supplier<Product> {
// Add these methods
String getManufacturer();
String getModel();
}
ProductFactory.java
public class ProductFactory {
private static final Map<List<String>, ProductSupplier> SUPPLIERS;
static {
var suppliers = new HashMap<List<String>, ProductSupplier>();
for (var supplier : ServiceLoader.load(ProductSupplier.class)) { // Yes, it's as easy as this.
var key = List.of(supplier.getManufacturer(), supplier.getModel());
suppliers.put(key, supplier);
}
SUPPLIERS = Map.copyOf(suppliers);
}
public static Product createProduct(String manufacturer, String model) {
var key = List.of(manufacturer, model);
var supplier = suppliers.getOrDefault(key, () -> null);
return supplier.get();
}
}
XiaomiFactory.java
public class XiaomiFactory implements ProductSupplier {
#Override public String getManufacturer() { return "Xiaomi"; }
#Override public String getModel() { return "Mi XX"; }
#Override public Product get() { return new XiaomiMiXX(); }
}
In META-INF/services/com.br.factory.ProductSupplier:
com.br.factory.xiaomi.XiaomiFactory
com.br.factory.samsung.SamsungFactory # Need to create
com.br.factory.apple.AppleFactory # Need to create
This question already has answers here:
Create instance of generic type in Java?
(29 answers)
Closed 5 years ago.
I want to create an instance just by defining the type for a generic class
public abstract class Base<T> {
private final T genericTypeObject;
protected Base(){
//Create instance of T here without any argument
}
}
So that I just can call the default constructor:
public class Child extends Base<SomeClass>{
public Child () {
super();
}
}
and the Base-class implementation will create me an instance of the GenericType.
The generic information will be erased at compile time, so there will be no T anymore during runtime (you loose the information). Thats why you somewhere will need a Class<> to store the information.
The most clean & simple solution form my point of view is to pass in the class to to the constructor. I know you requested it to be without any constructor argument, but I do not think this is possible.
Code Sample
public abstract class AbstractBase<T> {
private final T genericTypeObject;
protected Base(Class<T> type){
try {
genericTypeObject = type.newInstance();
} catch (InstantiationException e) {
// Handle
} catch (IllegalAccessException e) {
// Handle
}
}
}
public class Child extends Base<SomeClass> {
public Child () {
super(SomeClass.class);
}
}
Alternative Solution
Using a Supplier (thanks for the comment #Jorn Vernee):
public abstract class AbstractBase<T> {
private final T genericTypeObject;
public AbstractBase(Supplier<T> supplier) {
genericTypeObject = supplier.get();
}
}
public class Child extends AbstractBase<SomeClass> {
public Child() {
super(SomeClass::new);
}
}
You must have access to the class to create an instance, so creating an instance without an argument is not possible. You must pass a Class<T>.
UPDATE:
See #JDC's answer.
At runtime this returns me a Class instance:
public static Class<?> getGenericClassOfType(Object object){
Class<?> clazz = (Class<?>) ((ParameterizedType) object.getClass() .getGenericSuperclass()).getActualTypeArguments()[0];
return clazz;
}
and afterwards I can initiate it with:
public static <T> T getDefaultInstance(Class<T> clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException {
T instance = null;
Constructor<T>[] constructors = (Constructor<T>[]) clazz.getDeclaredConstructors();
Constructor<T> constructor = null;
for (Constructor cstr : constructors) {
//Only if default constructor
if (cstr.getParameters().length == 0) {
constructor = (Constructor<T>) cstr;
break;
}
}
if (constructor != null) {
constructor.setAccessible(true);
instance = constructor.newInstance();
}
return instance;
}
so the code in my base constructor looks like:
public abstract class BaseScene<T extends SceneController> {
private final static Logger LOGGER = LogManager.getLogger(BaseScene.class);
private final T sceneController;
//public T getSceneController() {
// return sceneController;
//}
protected BaseScene(){
T newInstance = null;
try {
Class<T> clazz = (Class<T>)ReflectionHelper.getGenericClassOfType(this);
newInstance = ReflectionHelper.getDefaultInstance(clazz);
} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
LOGGER.error("Error while trying to initiate BaseScene",e);
}
sceneController = newInstance;
}
}
which works perfectly as I tested it.
I have to handle two classes with identical methods but they don't implement the same interface, nor do they extend the same superclass. I'm not able / not allowed to change this classes and I don't construct instances of this classes I only get objects of this.
What is the best way to avoid lots of code duplication?
One of the class:
package faa;
public class SomethingA {
private String valueOne = null;
private String valueTwo = null;
public String getValueOne() { return valueOne; }
public void setValueOne(String valueOne) { this.valueOne = valueOne; }
public String getValueTwo() { return valueTwo; }
public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; }
}
And the other...
package foo;
public class SomethingB {
private String valueOne;
private String valueTwo;
public String getValueOne() { return valueOne; }
public void setValueOne(String valueOne) { this.valueOne = valueOne; }
public String getValueTwo() { return valueTwo; }
public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; }
}
(In reality these classes are larger)
My only idea is now to create a wrapper class in this was:
public class SomethingWrapper {
private SomethingA someA;
private SomethingB someB;
public SomethingWrapper(SomethingA someA) {
//null check..
this.someA = someA;
}
public SomethingWrapper(SomethingB someB) {
//null check..
this.someB = someB;
}
public String getValueOne() {
if (this.someA != null) {
return this.someA.getValueOne();
} else {
return this.someB.getValueOne();
}
}
public void setValueOne(String valueOne) {
if (this.someA != null) {
this.someA.setValueOne(valueOne);
} else {
this.someB.setValueOne(valueOne);
}
}
public String getValueTwo() {
if (this.someA != null) {
return this.someA.getValueTwo();
} else {
return this.someB.getValueTwo();
}
}
public void setValueTwo(String valueTwo) {
if (this.someA != null) {
this.someA.setValueTwo(valueTwo);
} else {
this.someB.setValueTwo(valueTwo);
}
}
}
But I'm not realy satisfied with this solution. Is there any better / more elegant way to solve this problem?
A better solution would be to create an interface to represent the unified interface to both classes, then to write two classes implementing the interface, one that wraps an A, and another that wraps a B:
public interface SomethingWrapper {
public String getValueOne();
public void setValueOne(String valueOne);
public String getValueTwo();
public void setValueTwo(String valueTwo);
};
public class SomethingAWrapper implements SomethingWrapper {
private SomethingA someA;
public SomethingWrapper(SomethingA someA) {
this.someA = someA;
}
public String getValueOne() {
return this.someA.getValueOne();
}
public void setValueOne(String valueOne) {
this.someA.setValueOne(valueOne);
}
public String getValueTwo() {
return this.someA.getValueTwo();
}
public void setValueTwo(String valueTwo) {
this.someA.setValueTwo(valueTwo);
}
};
and then another class just like it for SomethingBWrapper.
There, a duck-typed solution. This will accept any object with valueOne, valueTwo properties and is trivially extensible to further props.
public class Wrapper
{
private final Object wrapped;
private final Map<String, Method> methods = new HashMap<String, Method>();
public Wrapper(Object w) {
wrapped = w;
try {
final Class<?> c = w.getClass();
for (String propName : new String[] { "ValueOne", "ValueTwo" }) {
final String getter = "get" + propName, setter = "set" + propName;
methods.put(getter, c.getMethod(getter));
methods.put(setter, c.getMethod(setter, String.class));
}
} catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueOne() {
try { return (String)methods.get("getValueOne").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueOne(String v) {
try { methods.get("setValueOne").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueTwo() {
try { return (String)methods.get("getValueTwo").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueTwo(String v) {
try { methods.get("setValueTwo").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
}
You can use a dynamic proxy to create a "bridge" between an interface you define and the classes that conform but do not implement your interface.
It all starts with an interface:
interface Something {
public String getValueOne();
public void setValueOne(String valueOne);
public String getValueTwo();
public void setValueTwo(String valueTwo);
}
Now you need an InvocationHandler, that will just forward calls to the method that matches the interface method called:
class ForwardInvocationHandler implements InvocationHandler {
private final Object wrapped;
public ForwardInvocationHandler(Object wrapped) {
this.wrapped = wrapped;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method match = wrapped.getClass().getMethod(method.getName(), method.getParameterTypes());
return match.invoke(wrapped, args);
}
}
Then you can create your proxy (put it in a factory for easier usage):
SomethingA a = new SomethingA();
a.setValueOne("Um");
Something s = (Something)Proxy.newProxyInstance(
Something.class.getClassLoader(),
new Class[] { Something.class },
new ForwardInvocationHandler(a));
System.out.println(s.getValueOne()); // prints: Um
Another option is simpler but requires you to subclass each class and implement the created interface, simply like this:
class SomethingAImpl extends SomethingA implements Something {}
class SomethingBImpl extends SomethingB implements Something {}
(Note: you also need to create any non-default constructors)
Now use the subclasses instead of the superclasses, and refer to them through the interface:
Something o = new SomethingAImpl(); // o can also refer to a SomethingBImpl
o.setValueOne("Uno");
System.out.println(o.getValueOne()); // prints: Uno
i think your original wrapper class is the most viable option...however it can be done using reflection, your real problem is that the application is a mess...and reflection is might not be the method you are looking for
i've another proposal, which might be help: create a wrapper class which has specific functions for every type of classes...it mostly copypaste, but it forces you to use the typed thing as a parameter
class X{
public int asd() {return 0;}
}
class Y{
public int asd() {return 1;}
}
class H{
public int asd(X a){
return a.asd();
}
public int asd(Y a){
return a.asd();
}
}
usage:
System.out.println("asd"+h.asd(x));
System.out.println("asd"+h.asd(y));
i would like to note that an interface can be implemented by the ancestor too, if you are creating these classes - but just can't modify it's source, then you can still overload them from outside:
public interface II{
public int asd();
}
class XI extends X implements II{
}
class YI extends Y implements II{
}
usage:
II a=new XI();
System.out.println("asd"+a.asd());
You probably can exploit a facade along with the reflection - In my opinion it streamlines the way you access the legacy and is scalable too !
class facade{
public static getSomething(Object AorB){
Class c = AorB.getClass();
Method m = c.getMethod("getValueOne");
m.invoke(AorB);
}
...
}
I wrote a class to encapsulate the logging framework API's. Unfortunately, it's too long to put in this box.
The program is part of the project at http://www.github.com/bradleyross/tutorials with the documentation at http://bradleyross.github.io/tutorials. The code for the class bradleyross.library.helpers.ExceptionHelper in the module tutorials-common is at https://github.com/BradleyRoss/tutorials/blob/master/tutorials-common/src/main/java/bradleyross/library/helpers/ExceptionHelper.java.
The idea is that I can have the additional code that I want to make the exception statements more useful and I won't have to repeat them for each logging framework. The wrapper isn't where you eliminate code duplication. The elimination of code duplication is in not having to write multiple versions of the code that calls the wrapper and the underlying classes. See https://bradleyaross.wordpress.com/2016/05/05/java-logging-frameworks/
The class bradleyross.helpers.GenericPrinter is another wrapper that enables you to write code that works with both the PrintStream, PrintWriter, and StringWriter classes and interfaces.
So I have a few 'Manager' classes, for example GroupManager. All these Managers are singletons.
Using this method for instancing:
private static GroupManager groupManager = null;
private GroupManager()
{
}
public static GroupManager Instance()
{
if (groupManager == null)
{
groupManager = new GroupManager();
}
return groupManager;
}
I'm thinking I should start to use some inheritance as they have a lot of copied methods.
The Instance() methods for each Manager is the same.
So for inheritance i can do this (obviously):
GroupManager extends Manager
Is it possible to use generics to use the same Instance method for all managers, something like:
public class Manager<E>
{
private static E instance = null;
public static E Instance()
{
if (instance == null)
{
instance = new E();
}
return instance;
}
}
I think that makes sense :)
So then you would do GroupManager.Instance() like normal.
You don't understand how generics and statics work. If you have a static field or method (such as "instance" or instance()), which can be called without instantiating the class Manager, how do you expect the JVM (and the compiler even) to know what type E is supposed to be?
Here's an example, as per G_H's suggestion:
GeneralManager and AreaManager both extend Manager
The Manager class is the only one that has the getInstance() static method:
public class Manager {
private static Map<Class<? extends Manager>,Manager> INSTANCES_MAP = new java.util.HashMap<Class<? extends Manager>, Manager>();
//Also, you will want to make this method synchronized if your application is multithreaded,
//otherwise you mihgt have a race condition in which multiple threads will trick it into
//creating multiple instances
public static <E extends Manager> E getInstance(Class<E> instanceClass) throws InstantiationException, IllegalAccessException {
if(INSTANCES_MAP.containsKey(instanceClass)) {
return (E) INSTANCES_MAP.get(instanceClass);
} else {
E instance = instanceClass.newInstance();
INSTANCES_MAP.put(instanceClass, instance);
return instance;
}
}
}
Nope, it's not gonna work. Java uses generics at compile time for type checking, but doesn't generate extra classes or retain info regarding type parameters at runtime.
When you declare Manager<E> with that type parameter E, that's something that will only play a role in an actual instance. You could have a subclass like GroupManager extends Manager<String> or whatever, but that's not magically gonna generate a variety of the static method.
Static methods and members belong with a class, not an instance. So trying to use generics there, which are intended for typing instances, isn't gonna fly.
If you make your group manager class as follows then you can call your instance method.
public class GroupManager extends Manager<GroupManager>{}
And in your Manager class try this...
public class Manager<E>
{
private static E instance = null;
public static E Instance()
{
try {
return instance.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Or if you know the object you want an instance for, just make the method generic
public static <T> T getInstance(Class<T> t){
try {
return t.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
I havn't tried any of this so not sure if it will work.
Injecting the constructor in a generic context. Cash is not thread safe, but is only used in static context so its fine if you don't miss use it
public class Example {
public static class MySingletonClass {
}
public interface Provider<T> {
T get();
}
static final Provider<MySingletonClass> myClassInstanceProvider = new Cash<MySingletonClass>(new Provider<MySingletonClass>() {
#Override
public MySingletonClass get() {
return new MySingletonClass();
}
});
public static class Cash<T> implements Provider<T> {
private Provider<T> provider;
public Cash(Provider<T> provider) {
this.provider = provider;
}
#Override
public T get() {
final T t = provider.get();
provider = new Provider<T>() {
#Override
public T get() {
return t;
}
};
return t;
}
}
}
public class Manager<E>{
private static Object instance = null;
public static E Instance() {
if (instance == null)
{
instance = new E();
}
return (E)instance;
}
}