I need a function to create instances of a dynamically given class in java.
I had found many samples but in all of them, the class to be instantiated was known before runtime.
There are user defined classes:
class Student { //some code }
class Teacher { //some code }
class Course { //some code }
What I need is
List<class> MyFunction(<class>) {
List<class> items = new ArrayList<class>();
for(int i = 0; i < 5; i++) {
create_a_new_class_instance;
items.add(new_created_instance);
}
return items;
}
How will I use
List<Student> students = MyFunction(Student);
List<Teacher> teachers = MyFunction(Teacher);
List<Course> courses = MyFunction(Course);
Hope someone helps.
This is my first question in Stackoverflow, sorry for any inconvenience.
Utku
In Java 8, you can use a method reference or lambda expression in order to create instances of classes dynamically without using reflection.
public static <T> List<T> myFunction(Supplier<T> supplier) {
return Stream.generate(supplier)
.limit(5)
.collect(Collectors.toList());
}
You would call it like:
List<Student> students = myFunction(Student::new);
If you're not familiar with streams, the imperative equivalent is:
public static <T> List<T> myFunction(Supplier<T> supplier) {
int size = 5;
List<T> list = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
list.add(supplier.get());
}
return list;
}
This should work.
import java.util.ArrayList;
import java.util.List;
public class DynamicClassList {
public <T> List<T> myFunction(Class<T> inputClass) {
List<T> items = new ArrayList<T>();
for(int i = 0; i < 5; i++) {
try {
T myT = inputClass.getConstructor().newInstance();
items.add(myT);
} catch (Exception e) {
e.printStackTrace();
}
}
return items;
}
public static void main(String[] args) {
DynamicClassList dynamicClassList = new DynamicClassList();
List<Student> s = dynamicClassList.myFunction(Student.class);
List<Teacher> t = dynamicClassList.myFunction(Teacher.class);
List<Course> c = dynamicClassList.myFunction(Course.class);
}
}
Assuming that the classes supplied to MyFunction have a default constructor, a simple implementation would be
public static <T> List<T> MyFunction(Class<T> clazz) {
if (clazz == null) {
return null;
}
T item;
List<T> items = new ArrayList<T>();
for (int i = 0; i < 5; i++) {
try {
item = clazz.newInstance();
} catch (Exception e) {
item = null;
}
if (item != null) {
items.add(item);
}
}
return items;
}
and the above method could be called like
List<Student> student = MyFunction(Student.class);
For increased transparency, the exception thrown inside the method could be handled in another way (e.g., added to the method signature).
You could use reflection to do this
each class you pass must have a default no-argument constructor.
for this specific application you will likely need all 3 classes to share an interface so that you can properly send a list back
public interface Unit {
//Put any common functionality method stubs here
}
public class Teacher implements Unit {
}
//....etc for the other classes
List<Unit> MyFunction(Class<Unit> clazz) {
List<Unit> items = new ArrayList<Unit>();
for(int i = 0; i < 5; i++) {
items.add(clazz.newInstance());
}
return items;
}
when you assign your list to a list variable you will have to cast it.
such as:
List<Student> students = (List<Student>) MyFunction(Student.class);
you can use a pattern stategy like this :
///interface
package strategy;
public interface IStrategy {
public void appliquerStrategy();
}
package tpdesignpattern2.strategy;
public class StrategyImpl1 implements IStrategy{
#Override
public void appliquerStrategy() {
System.out.println("Appliquer la strategy 1");
}
}
package tpdesignpattern2.strategy;
public class StrategyImpl2 implements IStrategy{
#Override
public void appliquerStrategy() {
System.out.println("Appliquer la strategy 2");
}
}
/////// Context class
package tpdesignpattern2.strategy;
public class Context {
/***
* injection de l'interface
*/
private IStrategy iStrategy = new StrategyImpl1() ;
/**
* #param iStrategy
*/
public void setiStrategy(IStrategy iStrategy) {
this.iStrategy = iStrategy;
}
public void appliquerStrategy() {
iStrategy.appliquerStrategy();
}
}
///Application
package tpdesignpattern2.strategy;
import java.util.Scanner;
import strategy.IStrategy;
public class App {
public static void main(String[] args) {
Context context = new Context();
Scanner scanner = new Scanner(System.in);
while(true) {
System.out.print("Entrer le nom de la calss : ");
String nom = "tpdesignpattern2.strategy."+scanner.nextLine();
tpdesignpattern2.strategy.IStrategy strategy;
try {
strategy = (tpdesignpattern2.strategy.IStrategy) Class.forName(nom).newInstance();
context.setiStrategy(strategy);
context.appliquerStrategy();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
}
}
}
Related
I have an entity that has as children several lists of objects that, although they have different classes, all have the order attribute, in several parts I end up with repeated code, for example in one part I need to order the lists by that attribute and I cannot simplify because they are of different type.
The relevant part of the entity is this:
contenido={
"educaciones":[
{
...
"orden":0
},{
...
"orden":1
}
],
"experiencias":[
{
...
"orden":0
},{
...
"orden":1
}
]
},
...
The code I would like to simplify:
if(tipo.equals("experiencias")){
List<Experiencia> iterable=contenido.getExperiencias();
for(int i = 0; i < iterable.size(); i++){
iterable.get(i).setOrden( orden.get(i) ); //orden = [0,3,5,...]
}
iterable.sort((it1,it2)-> it1.getOrden().compareTo(it2.getOrden()));
}else if(tipo.equals("educaciones")){
List<Educacion> iterable=contenido.getEducaciones();
for(int i = 0; i < iterable.size(); i++){
iterable.get(i).setOrden( orden.get(i) );
}
iterable.sort((it1,it2)-> it1.getOrden().compareTo(it2.getOrden()));
}else if...
Is there a way to create a code that is more generic and supports different objects?
Create an interface for the methods that are common between all you classes:
interface HasOrden {
int getOrden();
void setOrden(int i);
}
Each of your classes needs to implement HasOrden.
Then you can declare sortOrden function:
import java.util.ArrayList;
import java.util.List;
interface HasOrden {
int getOrden();
void setOrden(int i);
}
class Experiencia implements HasOrden {
private final String name;
int orden;
public Experiencia(String name) {
this.name = name;
}
#Override
public int getOrden() {
return orden;
}
#Override
public void setOrden(int i) {
orden = i;
}
public String toString() {
return name;
}
}
public class Eg {
static void sortOrden(List<? extends HasOrden> l, List<Integer> order) {
if (l.size() != order.size()) {
throw new RuntimeException("length mismatch");
}
for (int i = 0; i < l.size(); i++) {
l.get(i).setOrden(order.get(i));
}
l.sort((it1,it2)-> Integer.compare(it1.getOrden(), it2.getOrden()));
}
public static void main(String[] args) {
List<Experiencia> items = new ArrayList<>(List.of(new Experiencia("a"), new Experiencia("b")));
List<Integer> order = List.of(2,1);
sortOrden(items, order);
System.out.println(items);
}
}
You can call sortOrden on any list of HasOrden instances.
you can try to create a List<?> - list with a dynamic type outside of your if else block and move your duplicated code outside too and at the end of the if else block. In addition, you have to create a common class or some interface for your classes, which holds all the common field you needed
public class Main {
public static class Something {
private Integer sth;
public Integer getSth() {
return sth;
}
public void setSth(Integer sth) {
this.sth = sth;
}
}
public static class ThisClass extends Something {
private Integer num;
public ThisClass(Integer num) {
this.num = num;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
}
public static class ThatClass extends Something {
private String str;
public ThatClass(String str) {
this.str = str;
}
public String getStr() {
return str;
}
public void setNum(String str) {
this.str = str;
}
}
public static List<? extends Something> sortList(Class<?> itemClass, List<? extends Something> list)
throws Exception {
for(int i = 0; i < list.size(); i++){
list.get(i).setSth(i);
}
list.sort((it1,it2)-> it1.getSth().compareTo(it2.getSth()));
return list;
}
public static void main(String[] args) {
System.out.println("Hello World");
List<? extends Something> someList = new ArrayList<>();
boolean check = true;
if(check) {
someList = Arrays.asList(new ThisClass(1),new ThisClass(1),new ThisClass(1),new ThisClass(1));
} else {
someList = Arrays.asList(new ThatClass("a"), new ThatClass("a"),new ThatClass("a"),new ThatClass("a"));
}
try {
someList = sortList(ThisClass.class, someList);
for(int i = 0; i < someList.size(); i++){
System.out.println(someList.get(i).getSth());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Currently I'm writing a program where I have the following statement.
List<BaseballStatistic> q = BaseballStatistic.FIND.where().eq("teamID", "CHN").query();
Here, it complains
Unchecked assignment: 'java.util.List' to 'java.util.List'. Reason: 'BaseballStatistic.FIND.where().eq("teamID", "CHN")' has raw type, so result of query is erased more...
I have an interface which looks like this
public interface Query<T> {
...
List<T> execute();
}
then an abstract class that implements this interface
public abstract class AbstractQuery<T> implements Query<T> {
Statement _statement = null;
String _tableName;
List<Clause> _clauses;
Class<T> _type;
AbstractQuery(Class<T> type) {
_type = type;
_clauses = new ArrayList<>();
_tableName = type.getAnnotation(Table.class).name();
}
...
public abstract List<T> execute();
}
and finally a concrete implementation:
public class SimpleQuery<T> extends AbstractQuery<T> {
public SimpleQuery(Class<T> type) {
super(type);
}
which houses the following .query function which looks like:
#Override
public List<T> execute() {
try {
JSONObject jsonObject = Peanut.getClient().listStatistics(buildQuery());
if (jsonObject == null || !jsonObject.has("results")) {
return Collections.emptyList();
}
JSONArray columnNames = jsonObject.getJSONArray("columns");
Map<String, Integer> columnNameMap = new HashMap<>();
for (int i = 0; i < columnNames.length(); i++) {
columnNameMap.put((String) columnNames.get(i), i);
}
JSONArray results = jsonObject.getJSONArray("results");
List<T> ts = new ArrayList<>();
for (int i = 0; i < results.length(); i++) {
JSONArray result = results.getJSONArray(i);
T t = _type.newInstance();
for (Field field : ObjectUtils.getFieldsUpTo(t.getClass(), PinotModel.class)) {
if (field.getAnnotation(Column.class) == null) {
continue;
}
Object obj = ObjectUtils.getDefaultValue(field.getType());
String columnName = field.getAnnotation(Column.class).name();
if (columnNameMap.containsKey(columnName)) {
int idx = columnNameMap.get(columnName);
field.setAccessible(true);
field.set(t, ObjectUtils.convertObject(obj, result.get(idx)));
}
}
ts.add(t);
}
return ts;
} catch (Exception e) {
// TODO: Throw Peanut specific error.
Peanut.LOG.error(e);
return Collections.emptyList();
}
}
It seems like here, at compilation, the returned list has lost it's type leading to the warning. If I change the original variable declaration to List the warning will leave, which makes sense.
Is there anyway around this or is there a larger fundamental issue at play?
EDIT:
Query Function that calls execute is here
public List<T> query() {
return _query.execute();
}
And the relationship between SimpleQuery and BaseballStatistic.Find is as follows.
#Table(name = "baseballStats")
public class BaseballStatistic extends PinotModel {
public static final Find FIND = new Find<BaseballStatistic (BaseballStatistic.class) { };
...
and PinotModel looks like
public class PinotModel {
public static class Find<T> {
private final Class<T> type;
protected Find(Class<T> type) {
this.type = type;
}
public Query select(String... s) {
return new SimpleQuery<T>(type).select(s);
}
public Clause where() {
return new SimpleQuery<T>(type).where();
}
public Clause limit(Integer n) {
return new SimpleQuery<T>(type).limit(n);
}
public Clause top(Integer n) {
return new SimpleQuery<T>(type).top(n);
}
public Clause orderBy(String columnName, Order o) {
return new SimpleQuery<T>(type).orderBy(columnName, o);
}
public String tableName() {
return new SimpleQuery<T>(type).getTableName();
}
}
}
There are 2 places that you're missing generic type parameters.
BaseballStatistic.FIND:
public static final Find<BaseballStatistic> FIND = new Find<BaseballStatistic> (BaseballStatistic.class) { };
PinotModel.select:
public Query<T> select(String... s) {
return new SimpleQuery<T>(type).select(s);
}
You're also missing type parameters on PinotModel.where(). Clause would also need a type parameter, including on the AbstractQuery._clauses field.
I am working on some kind of software delivery tool. For one of its task the program needs to find the class file names which will generate after compiling any given java file.
I need some kind of parsing library/approach which can detect all inner
classes(named as well as anonymous) too.
e.g.: If input file contains below code. Our program should generate output as: SampleClass1.class, SampleClass1$Data.class, SampleClass1$1.class
package com.aci.uob.patchmanifest.helper.testapp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SampleClass1 {
public static String CONSTANT_ATTR = "Sample String Constant";
int attr;
boolean b;
private class Data implements Comparable<Data>{
String val="--";
public Data(String val) {
super();
this.val = val;
}
#Override
public int compareTo(Data o) {
return this.val.compareTo(o.val);
}
}
public SampleClass1(int attr, boolean b) {
super();
System.out.println("this is a sample constructor");
this.attr = attr;
this.b = b;
}
private void runInnerClasses(){
List<Data> list=new ArrayList<Data>();
list.add(new Data("Hello"));
list.add(new Data("World"));
list.add(new Data("20"));
list.add(new Data("100"));
list.add(new Data(" Hello"));
Collections.sort(list);
printList(list);
Collections.sort(list, new Comparator<Data>() {
#Override
public int compare(Data o1, Data o2) {
// TODO Auto-generated method stub
return o1.val.trim().compareToIgnoreCase(o2.val.trim());
}
});
}
private void printList(List<Data> list) {
for(Data d: list)
System.out.println(d.val);
}
}
If your program are running under Eclipse, JDT API(org.eclipse.jdt.core plugin) is a choice. Here is a example:
IJavaElement ele = JavaCore.create(ifile);
if (ele instanceof ICompilationUnit) {
IType[] czs = ((ICompilationUnit)ele).getAllTypes();
for (int i = 0; i < czs.length; i++) {
System.out.println(czs[i].getTypeQualifiedName());
//IType.getFullyQualifiedName() will return value include package name
IMethod[] ims = czs[i].getMethods();
for (int j = 0; j < ims.length; j++) {
IJavaElement[] childs = ims[j].getChildren();
//find anonymous type inside Method
for (int k = 0; k < childs.length; k++) {
if (childs[k] instanceof IType) {
System.err.println(((IType)childs[k]).getTypeQualifiedName());
}
}
}
}
}
Output example:
SampleClass1
SampleClass1$Data
SampleClass1$1
The JDT core API doesn't handle naming of anonymous types.
If private void printList(List list) also include a anonymous type.
The API also return SampleClass1$1.
You may also need czs[i].getFields() to find anonymous type inside Field. If SampleClass1 declare a class variable like:
Runnable r = new Runnable() {
public void run(){};
};
I am attempting to reference a variable in a method in my class and keep running into a NullPointerException. I know it is happening at the variable pbook when it is referenced from the addPerson method. Why is this happening and how could I go about fixing it?
public class Phonebook <T> {
private LinkedList<T> pbook;
public T findPerson(T person) {
for (int i = 0; i < pbook.size(); i++) {
if (pbook.get(i).equals(person)) {
return person;
}
else
{
i++;
}
}
return null;
}
public void addPerson(T person) {
pbook.addFirst(person);
}
public void deletePerson(T person) {
for (int i = 0; i < pbook.size(); i++) {
if (pbook.get(i).equals(person)) {
pbook.remove(i);
}
else
{
i++;
}
}
}
/**
* #param args
*/
public static void main(String[] args){
try{
Phonebook<Integer> sspb = new Phonebook<Integer>();
Phonebook<String> idpb = new Phonebook<String>();
sspb.addPerson(1234567890);
idpb.addPerson("Bob");
}
catch (Exception e){
e.printStackTrace();
}
}
}
You must add a constructor to instantiate your LinkedList:
public Phonebook() {
pbook = new LinkedList<T>();
}
Change:
private LinkedList<T> pbook;
To:
private LinkedList<T> pbook = new LinkedList<T>();
private LinkedList<T> pbook; You don't create a list.
Try this.
private LinkedList<T> pbook = new LinkedList<T>()
1) You can define a constructor e.g. like this.
public Phonebook(LinkedList<T> pbook){
this.pbook = pbook;
}
Then the calling code will have to set the
pbook when instantiating the Phonebook.
2) You can initialize pbook where you declare it.
private LinkedList<T> pbook = new LinkedList<T>();
I am creating objects that will have properties in common based on user input and then passing the objects to a common method that will take appropriate action based on the object type.
I've been able to sort of get this working using a visitor class but it is not quite what I want. I want to be able to determine the object type in the common method and then access the methods associated with that object. I am not sure if I am close and just missing something or if I just have a bad implementation... or both =).
Here is my (complete) code:
package com.theory.bang.big;
public interface Particle
{
public enum ParticleType {
QUARK,
LEPTON
}
int processParticle(Particle p);
}
package com.theory.bang.big;
import java.util.ArrayList;
public class Quark implements Particle
{
ArrayList<String> flavorList;
/**
* Constructor for objects of class Quark
*/
public Quark()
{
flavorList = new ArrayList<String>();
flavorList.add("up");
flavorList.add("down");
flavorList.add("charm");
flavorList.add("strange");
flavorList.add("top");
flavorList.add("bottom");
}
public ArrayList<String> getFlavors()
{
return flavorList;
}
#Override
public int processParticle(Particle p)
{
System.out.println("In processParticle(Quark)");
// Never called?
return 0;
}
}
package com.theory.bang.big;
import java.util.ArrayList;
public class Lepton implements Particle
{
ArrayList<String> typeList;
/**
* Constructor for objects of class Lepton
*/
public Lepton()
{
typeList = new ArrayList<String>();
typeList.add("electron");
typeList.add("electron neutrino");
typeList.add("muon");
typeList.add("muon neutrino");
typeList.add("tau");
typeList.add("tau neutrino");
}
public ArrayList<String> getTypes()
{
return typeList;
}
#Override
public int processParticle(Particle p)
{
System.out.println("In processParticle(Lepton)");
return 0;
}
}
package com.theory.bang.big;
import java.lang.reflect.*;
class ParticleVisitor
{
public void visit( Quark q )
{
System.out.println("Quark:[" + q.getFlavors() + "]");
}
public void visit( Lepton l )
{
System.out.println("Lepton:[" + l.getTypes() + "]");
}
public void visit( Object e ) throws Exception
{
Method m = getClass().getMethod
( "visit", new Class[]{e.getClass()} );
m.invoke( this, new Object[]{e} );
}
}
package com.theory.bang.big;
import java.io.File;
public class Accelerate implements Particle
{
/**
* Constructor for objects of class Accelerate
*/
public Accelerate(Particle p)
{
processParticle(p);
}
//#Override
public int processParticle(Particle p)
{
try {
ParticleVisitor pv = new ParticleVisitor();
pv.visit(p);
} catch (Exception x) {
System.out.println(x);
}
return 0;
}
}
package com.theory.bang.big;
import java.io.File;
import java.util.Scanner;
public class Physics
{
public static void main(String[] args)
{
boolean done = false;
while (!done) {
System.out.print("Enter the particle [Quark or Lepton]: ");
Scanner in = new Scanner(System.in);
String input = in.next();
if (input.equals("Quark")) {
System.out.println("Quark");
Quark q = new Quark();
new Accelerate(q);
} else if (input.equals("Lepton")) {
System.out.println("Lepton");
Lepton l = new Lepton();
new Accelerate(l);
} else {
done = true;
}
}
}
}
Currently I can print the Quark flavors and Lepton types via the visit methods but what I need is to be able to execute (to be implemented) getter/setters (e.g. getSpin(), setSpin(double s)) for the respective objects in Accelerate().
What am I missing? Or is there a better way to implement this?
Thank you very much for your time.
-Walter
For your concrete example, you can throw away all that stuff and use overloading by parameter types:
public class Physics {
public static void processParticle( Quark q ) {
System.out.println("Quark:[" + q.getFlavors() + "]");
}
public static void processParticle( Lepton l ) {
System.out.println("Lepton:[" + l.getTypes() + "]");
}
public static void main(String[] args) {
boolean done = false;
while (!done) {
System.out.print("Enter the particle [Quark or Lepton]: ");
Scanner in = new Scanner(System.in);
String input = in.next();
if (input.equals("Quark")) {
System.out.println("Quark");
Quark q = new Quark();
processParticle(q);
} else if (input.equals("Lepton")) {
System.out.println("Lepton");
Lepton l = new Lepton();
processParticle(q);
} else {
done = true;
}
}
If you want to call processParticle() where compiler does not know the exact type of the particle, use double dispatch pattern:
// add method processParticle
public interface Particle{
...
void processParticle();
}
class Quark implements Particle {
void processParticle() {
Physics.processParticle(this);
}
}
class Lepton extends Particle {
void processParticle() {
Physics.processParticle(this);
}
}
public class Physics {
public static void main(String[] args) {
for (;;) {
System.out.print("Enter the particle [Quark or Lepton]: ");
Scanner in = new Scanner(System.in);
String input = in.next();
Particle p;
if (input.equals("Quark")) {
System.out.println("Quark");
p = new Quark();
} else if (input.equals("Lepton")) {
System.out.println("Lepton");
p = new Lepton();
} else {
break;
}
p.processParticle();
}
}
}
Then you can evolve to true visitor pattern, but reflection can and should be avoided here.