I want to transfer a variable value of type List (variable name is seznamRacunov) from one class to another.
Class 1
public class UvoziRacun
{
private String potRacuna;
private List<String> seznamRacunov = new ArrayList();
public void setRacun(List<String> seznamRacunov)
{
this.seznamRacunov = seznamRacunov;
}
public List<String> getRacun()
{
return seznamRacunov;
}
public String getPotRacuna()
{
return potRacuna;
}
public void showDailog()
{
try
{
JFileChooser racun = new JFileChooser();
racun.setCurrentDirectory(new File(""));
racun.setFileFilter(new javax.swing.filechooser.FileFilter()
{
public boolean accept(File f)
{
return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory();
}
public String getDescription()
{
return "XML Datoteka";
}
});
//racun.setMultiSelectionEnabled(true);
int r = racun.showOpenDialog(new JFrame());
if (r == JFileChooser.APPROVE_OPTION)
{
potRacuna = racun.getSelectedFile().getPath();
seznamRacunov.add(potRacuna); //value is stored
}
//System.out.print("Racuni: " + seznamRacunov);
}
catch(Exception ex){}
}
}
Class 2
public class PrikaziRacune extends javax.swing.JFrame
{
UvoziRacun rac = new UvoziRacun();
public PrikaziRacune()
{
initComponents();
try
{
System.out.print(rac.getRacun()); // value is null, why?
//jLabel2.setText();
}
catch(Exception ex){}
}
Method seznamRacunov.add(potRacuna); store a value into seznamRacunov in Class 1, but the value of list does not pass in class 2 where I called getter. What is wrong?
Method seznamRacunov.add(potRacuna); store a value into seznamRacunov
in Class 1, but the value of list does not pass in class 2 where I
called getter.
Thats because, you are trying to get() your List without even calling the method - showDailog() which in turn invokes your add() method to populate list.
Make sure, you invoke this method - showDailog() to populate the list, before you actually fetch the List with get method
Or, it would be better, if you add a constructor to your class, which does the task of initializing your List. Then you can create an instance using that constructor and thus you won't have any problem.
PS: - You should always have at least a 0-arg constructor to initialize your fields, rather than letting compiler handle this task for you.
And one more thing, you should never, ever engulp your exception by having an empty catch block. Else there is no point in catching them. Add a printStackTrace() call instead.
public PrikaziRacune() {
initComponents();
try
{
rac.showDailog(); // Will populate the list
System.out.print(rac.getRacun()); // You can get the value here.
//jLabel2.setText();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
Also, check your ArrayList declaration in your first class. You are using generic type List on LHS, and a Raw type ArrayList on the RHS. Its something that you should avoid.
Have Generic type on both the sides: -
private List<String> seznamRacunov = new ArrayList<String>();
Related
We have to create a object of any class to use their funtionalities unless those are static functionalities. But why we dont need to create a ArrayList object to use its methods like add, contains etc..
ArrayList<Egg> myList = new ArrayList<Egg>();
myList.add(a);
According to my understanding, myList is just variable which holds ArrayList object's reference of type ArrayList class. So again how can we write following without passing object to myList.
ArrayList<Egg> myList;
myList.add(a);
Complete code:
import java.util.ArrayList;
public class DotCom {
private ArrayList<String> locationCells;
public void setLocationCells(ArrayList<String> loc)
{
locationCells = loc;
}
public String checkYourself(String userInput)
{
String result = "miss";
int index = locationCells.indexOf(userInput);
if (index >= 0) {
locationCells.remove(index);
if (locationCells.isEmpty()) {
result = "kill";
}
else
{
result = "hit";
}
}
return result;
}
//TODO: all the following code was added and should have been included in the book
private String name;
public void setName(String string) {
name = string;
}
}
PS
I am referring heads first java book.
The ArrayList reference is being set in the setter method:
public void setLocationCells(ArrayList<String> loc)
{
locationCells = loc;
}
If this method is not called, and the reference not set before trying to use the ArrayList, then the code will throw a NullPointerException.
Side note: This does not look to be safe code, since it can be easily run incorrectly and so a NPE is easy to create. Better perhaps to set the ArrayList (List is even better) in a constructor.
I want to test a private method using reflection. In this case isEdible method from Food class.
public class Food {
private Boolean isEdible() {
return true;
}
}
When I'm using getDeclaredMethod without specifying Food class, it ran successfully.
#Test
public void foodTestOne() throws Exception {
Food food = new Food();
Method method = food.getClass().getDeclaredMethod("isEdible");
method.setAccessible(true);
boolean isEdible = (boolean) method.invoke(food);
assertTrue(isEdible);
}
But when I add Food Class on a second parameter I got NoSuchMethodException.
#Test
public void foodTestTwo() throws Exception {
Food food = new Food();
Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);
// execution stop here
}
My questions are:
What should I put in second parameters to make it work? Changing getDeclaredMethod("isEdible", Boolean.class) still throws the same Exception.
It seems pretty basic and intuitive, why is this happening?
getDeclaredMethod needs to match the argument types that the method expects. When a method takes no arguments (such as isEdible()) you can pass null (or an empty Class[]), for example
public class Food {
private Boolean isEdible() {
return true;
}
public static void main(String[] args) {
Food food = new Food();
try {
Class<?>[] methodArgumentTypes = null; // {};
Object[] methodArguments = null; // new Object[0];
Method method = food.getClass().getDeclaredMethod("isEdible",
methodArgumentTypes);
System.out.println(method.invoke(food, methodArguments));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Will actually invoke isEdible() and output true.
Can be done like this, if method has no parameters:
obj.getClass().getDeclaredMethod(methodName, (Class<?>[]) null).invoke(obj);
Read more...
The issue you are having is that in the line
Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);
You specify Food as a parameter of the method; it is not. Instead, you should have
Method method = food.getClass().getDeclaredMethod("isEdible");
isEdible() is declared private, so you will not be able to access it in the current context, even with getDeclaredMethod. To allow for access, you can set it to accessible before invoking the method.
method.setAccessible(true);
method.invoke(food);
My program is structured as follows: a class that represents an atomic concept which is essentially a String and another class that is made of a list of general concepts. Both classes extends the class Concept that is an abstract class, this means that in the list I could have both atomic concepts and intersection of concepts arbitrary nested.
Each concept, atomic or composed, is printed out by toString method.
Roughly speaking, this is based on this context-free grammar:
C : atom | (C and)+ C
Where C is the abstract class Concept, atom is AtomicConcept and (C and)+ C is Intersection.
This is the AtomicConcept class:
public class AtomicConcept extends Concept{
private String atomicConceptName;
public AtomicConcept(String c) {
this.atomicConceptName = c;
}
#Override
public String toString() {
return atomicConceptName;
}
}
This is che ConceptIntersection class:
import java.util.List;
public class ConceptIntersection extends Concept{
private List<Concept> list;
public ConceptIntersection(List<Concept> l) throws Exception {
if(l.size()>1)
{
this.list = l;
}
else
{
throw new Exception("Intersection needs at least two concepts!");
}
}
public String toString()
{
return Utils.conceptIntersection + Utils.lparen + Utils.splitConcepts(list) + Utils.rparen;
}
}
As you can see in toString function, I also created a method called splitConcepts that takes in input a list of general concepts and returns one string made of each concept separated by comma.
public static String splitConcepts(List<Concept> list)
{
String result = "";
for (Concept item : list) {
System.out.println(item);
result += item.toString() + comma;
}
result = result.substring(0, result.length() - 1);
return result;
}
Where is the problem?
I have trouble with this function because when I call a nested intersection in another one, this function never ends!
One example:
public static void main(String[] args) throws DLRException {
// TODO Auto-generated method stub
AtomicConcept atom = new AtomicConcept("one");
AtomicConcept at = new AtomicConcept("two");
List<Concept> list = new LinkedList<Concept>();
list.add(at);
list.add(atom);
DLRConceptIntersection intersection = new DLRConceptIntersection(list);
System.out.println(intersection); // works fine
list.add(intersection);
DLRConceptIntersection intersection2 = new DLRConceptIntersection(list);
System.out.println(intersection2); //loop never ends!
}
Is a correct approach to fix this problem?
You have a circular reference :
DLRConceptIntersection intersection = new DLRConceptIntersection(list);
list.add(intersection);
This causes the intersection's List to contain a reference to the same instance referred by intersection, which is why toString() run into infinite recursion.
I'm assuming you didn't intend intersection and intersection2 to share the same List.
You can avoid it if you create a copy of the List in the DLRConceptIntersection constructor:
public ConceptIntersection(List<Concept> l) throws Exception {
if(l.size()>1) {
this.list = new ArrayList<>(l);
} else {
throw new Exception("Intersection needs at least two concepts!");
}
}
I created an ArrayList to store Classes. Then I would like to use the members in the ArrayList to create an instance. How can I instantiate?
import java.util.ArrayList;
class Machine{
public String toString(){
return "I am a machine";
}
}
class MyMachine extends Machine{
public String toString(){
return "This is a super Machine";
}
}
class MyClass<T> {
public static <T> void showString(T abc){
System.out.println(abc);
}
}
public class myfun {
public static void main(String[] args) {
ArrayList<Class> hahalist = new ArrayList<>();
hahalist.add(MyClass.class);
hahalist.add(Machine.class);
hahalist.add(MyClass.class);
// Machine abc = new Machine();
// I can't do this
// abc = hahalist.get(1);
// I can't do this either
// hahalist.get(1) abc = new hahalist.get(1)()
}
}
Instead of storing classes in the list, you could store references to the constructors:
List<Supplier<Object>> hahalist = new ArrayList<>();
hahalist.add(MyClass::new);
hahalist.add(Machine::new);
hahalist.add(MyMachine::new);
Object instance = hahalist.get(1).get(); // Calling constructor
Because MyClass and Machine have a closest common ancestor of Object that is the return type of the Supplier I'm using here.
If you have a no args constructor on all you classes you can just use the Class.newInstance(), eg
try {
Object x = hahaList.get(0).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
(I haven't got my IDE open so haven't verified the exact syntax).
If you've got arguments to the constructor then its a bit more convoluted. You can read the full details here: https://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html
Let's say we have to check some set of rules before adding a new element in a collection. Elements are objects of a few similar types. All type specific features are encapsulated in subclasses of an abstract class. Collection contains objects of this abstract class. The rules apply conditions for types along with other constraints. For that reason the abstract superclass of items has additional type code. New element can be added to collection but due to additional rules other elements in collection can be removed or replaced.
In the code that needs to be refactored, validation of the rules is implemented as one long block of code with nested control flow statements. Validation of the type code breaks encapsulation. Separate branches of the control flow statements cannot be defined as method of corresponding subclasses of collection elements because them need to check type and make changes to collection.
additional facts regarding type code in my case:
type code does not affect the behaviour of class
type code is immutable
type code is used by ItemsManager to resolve some rules before to add
new element to collection.
How to eliminate type code and separate rules from types?
Here is example of such problem:
Type specific features of Items are encpsulated in AbstractItem subclasses.add method of ItemManager class breaks encapsulation.Rule: item of Type2 must be removed if new item of Type1 with the same value of SomeUsefull property is adding to collection.
For simplicity implementation of ICloneable and IComparable interfaces is omitted. In real world items in collection are immutable and cloneable and the system of rules is quite tangled.
abstract class AbstractItem {
private int Type; // this would like to eliminate
private int SomeUseful;
protected AbstractItem(int Type, int Value) {
this.Type = Type;
this.SomeUseful = Value;
}
public int getType() { return this.Type; }
public int getSomeUseful() { return this.SomeUseful; }
#Override
public String toString() {
return String.format("Item{Type=%d, Value=%d}", Type, SomeUseful);
}
}
class ItemType1 extends AbstractItem {
ItemType1(int Value) { super(1, Value); }
}
class ItemType2 extends AbstractItem {
ItemType2(int Value) { super(2, Value); }
}
class ItemManager {
private java.util.ArrayList<AbstractItem> ListOfItems;
public ItemManager(){
this.ListOfItems = new java.util.ArrayList<AbstractItem>();
}
public void add(final AbstractItem newItem) {
// this code breaks encapsulation
switch (newItem.getType()) {
case 1:
// do some type dependent operations
for(AbstractItem i: this.ListOfItems) {
if (i.getType()==2 && i.getSomeUseful()==newItem.getSomeUseful()) {
this.ListOfItems.remove(i);
break;
}
}
break;
case 2:
// do some other type dependent operations
break;
default:
// throw error
}
this.ListOfItems.add(newItem);
}
#Override
public String toString() {
String str = String.format("ItemsManager content");
for(AbstractItem i: this.ListOfItems) {
str += String.format("\n\tType = %d, Value = %d", i.getType(), i.getSomeUseful());
}
return str;
}
}
public class Example1 {
public static void main(String[] arg) {
System.out.println("Example 1");
ItemManager im = new ItemManager();
im.add(new ItemType1(1));
im.add(new ItemType2(2));
im.add(new ItemType2(3));
im.add(new ItemType1(3));
System.out.println(im.toString());
}
}
/*
Example 1
ItemsManager content
Type = 1, Value = 1
Type = 2, Value = 2
Type = 1, Value = 3
*/
Starting from #dbugger's answer you can push it further.
You can use Double Dispatch to hide the type code. Still not a perfect solution because the parent knows too much about its children, but the type code is gone now.
It is hard to tell what a better solution might be with the example code you have given, because when you simplified, you removed all the information about the items involved. There might be something there that could be used for discrimination in some other way, allowing you to get rid of the double dispatch with shoudBeRemovedBecauseType1.
Here is the altered onAdd method from type 1
#Override
public List<AbstractItem> onAdd(List<AbstractItem> list) {
for (AbstractItem item : list) {
if (item.shoudBeRemovedBecauseType1(this)) {
list.remove(item);
break;
}
}
return list;
}
A new method in the base class
public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
{
return false;
}
overridden in the type 2 subclass
#Override
public boolean shoudBeRemovedBecauseType1(ItemType1 itemType1)
{
return getSomeUseful() == itemType1.getSomeUseful();
}
It's not ideal, but it's a step towards getting some encapsulation and killing the switch statement...
add an onAdd method to the base class that takes the list as a parameter.
public java.util.ArrayList<AbstractItem> onAdd(java.util.ArrayList<AbstractItem> list) { return list; }
then override it in the sub classes, for example...
#Override
public java.util.ArrayList<AbstractItem> onAdd(java.util.ArrayList<AbstractItem> list) {
for(AbstractItem i: this.ListOfItems) {
if (i.getType()==2 && i.getSomeUseful()==this.getSomeUseful()) {
list.remove(i);
break;
}
}
return list;
}
then rewrite the ItemManager add method to just call the sub classes' onAdd methods...
public void add(final AbstractItem newItem) {
this.ListOfItems = newItem.onAdd(this.ListOfItems);
this.ListOfItems.add(newItem);
}