I'm having a problem with inner classes. I build an object (let's say a train) with an inner class representing states (let's say the stops of the train).
I'm trying to run this code:
private void CustomObjectBuilder (String [] origin) {
final int array_dim = origin.length;
InnerCustomObject[] tmp_bin = new InnerCustomObject[array_dim];
for (int ii = 0; ii < array_dim; ii++) {
String debug = extractData(origin[ii]);
tmp_bin[ii].setData(debug);
}
}
It compiles just just fine but at runtime I get a null object exception.
What am I doing wrong?
Here you can finde the original code:
public class CustomObject {
InnerCustomObject [] stops;
public class InnerCustomObject {
String name, station, schedTime, depTime, schedRail, depRail;
public void setData (String origin) {
this.station = origin;
}
}
}
Edit: I solved by calling
CustomObject.InnerCustomObject ico = new CustomObject(). new InnerCustomObject();
why it needs to be so verbose?
Well, the most immediate thing I notice is you don't populate tmp_bin[] with any objects after you declare it. When you first create an array, all it contains are nulls.
So when you do this in your loop:
tmp_bin[ii].setData(debug);
There is nothing to invoke setData() on, resulting in the exception.
Re edit: you can just do
InnerCustomObject ico = this.new InnerCustomObject();
since you're creating them within your outer CustomObject class's CustomObjectBuilder() instance method.
InnerCustomObject[] tmp_bin = new InnerCustomObject[array_dim];
declares an array of array_dim elements but all are null. Then this
tmp_bin[ii].setData(debug);
won't work.
No problem with inner classes only with an object that is null (=NPE) so you cannot call the method setData().
In your loop you have to create new instance of InnerCustomObject. By new InnerCustomObject[size] you do not create new instances.
Related
In my program, I want to create multiple threads in one of the methods where each thread has to run a specific method with a given input. Using Runnable, I have written this snippet.
class myClass {
public myClass() { }
public void doProcess() {
List< String >[] ls;
ls = new List[2]; // two lists in one array
ls[0].add("1"); ls[0].add("2"); ls[0].add("3");
ls[1].add("4"); ls[1].add("5"); ls[1].add("6");
// create two threads
Runnable[] t = new Runnable[2];
for (int i = 0; i < 2; i++) {
t[ i ] = new Runnable() {
public void run() {
pleasePrint( ls[i] );
}
};
new Thread( t[i] ).start();
}
}
void pleasePrint( List< String > ss )
{
for (int i = 0; i < ss.size(); i++) {
System.out.print(ss.get(i)); // print the elements of one list
}
}
}
public class Threadtest {
public static void main(String[] args) {
myClass mc = new myClass();
mc.doProcess();
}
}
Please note, my big code looks like this. I mean in one method, doProcess(), I create an array of lists and put items in it. Then I want to create threads and pass each list to a method. It is possible to define the array and lists as private class members. But, I want to do that in this way.
Everything seems to be normal, however, I get this error at calling pleasePrint():
error: local variables referenced from an inner class must be final or effectively final
pleasePrint( ls[i] );
How can I fix that?
The reason you are getting this error is straightforward and clearly mentioned - local variables referenced from an inner class must be final or effectively final. This is, in turn, because, the language specification says so.
Quoting Guy Steele here:
Actually, the prototype implementation did allow non-final variables
to be referenced from within inner classes. There was an outcry from
users, complaining that they did not want this! The reason was interesting: in order to support such variables, it was necessary to
heap-allocate them, and (at that time, at least) the average Java
programmer was still pretty skittish about heap allocation and garbage
collection and all that. They disapproved of the language performing
heap allocation "under the table" when there was no occurrence of the
"new" keyword in sight.
As far as your implementation goes, instead of using an array of list, I'd rather use a list of lists.
private final List<List<String>> mainList = new ArrayList<>();
You can create new lists and insert them into the main list in the constructor depending on the number of lists you want.
public ListOfLists(int noOfLists) {
this.noOfLists = noOfLists;
for (int i = 0; i < noOfLists; i++) {
mainList.add(new ArrayList<>());
}
}
You can then change your doProcess() method as follows:
public void doProcess() {
for (int i = 0; i < noOfLists; i++) {
final int index = i;
// Using Lambda Expression as it is much cleaner
new Thread(() -> {
System.out.println(Thread.currentThread().getName());
pleasePrint(mainList.get(index)); // Pass each list for printing
}).start();
}
}
Note: I used an instance variable named noOfLists to (as the name suggests) store the number of lists I need. Something as follows:
private final int noOfLists;
To populate the list, you could do:
mainList.get(0).add("1");
mainList.get(0).add("2");
mainList.get(0).add("3");
mainList.get(1).add("4");
mainList.get(1).add("5");
mainList.get(1).add("6");
// And so on...
And you'll get the output something as:
Thread-0
1
2
3
Thread-1
4
5
6
Hope this helps :)
First to that, you will get a NullPointerException here:
ls[0].add("1"); ls[0].add("2"); ls[0].add("3");
ls[1].add("4"); ls[1].add("5"); ls[1].add("6");
Before, yo must instantiate the lists:
ls[0] = new ArrayList<>();
ls[1] = new ArrayList<>();
About the compiler error, try to define the array as final. Change:
List< String >[] ls;
ls = new List[2]; // two lists in one array
By:
final List< String >[] ls = new List[2]; // two lists in one array
This is because you can't access to non-final (or effectively final) variables from a local class.
'ls' is effectively final but probably, since you have defined it in two lines, the compiler is not able to notice that.
I'm trying to print an array via toString() so I can call it to another method. What exactly am I doing wrong? Why isn't it compiling and what is a better solution.
public class Applicants
{
private String applicant[];
public Applicants()
{
Application student1 = new Application()
Application student2 = new Application()
Application student3 = new Application()
Application student4 = new Application()
Application student5 = new Application()
Application student6 = new Application();
Application applicant[] = new Application[5];
applicant[0] = student1;
applicant[1] = student2;
applicant[2] = student3;
applicant[3] = student4;
applicant[4] = student5;
applicant[5] = student6;
for (int index = 0; index < applicant.length; index++)
{
System.out.println(applicant[index]);
}
}
public String toString(String[] applicant)
{
String output = new String();
String total;
for (int index = 0; index < applicant.length; index++)
{
total = System.out.println(applicant[index]);
}
return total;
}
}
There are three things wrong, and one "hey, pay attention".
You are shadowing your field applicant inside of your constructor. What this means is when you're done with your constructor, your String[] is null. Not full of null, just null.
What you probably meant to do was declare private Application[] applicant as your field, then not redeclare it inside of your constructor.
total = System.out.println(applicant[index]); is not a valid statement. You cannot assign the result of a void method to anything. You have it right in your constructor, so it's surprising that you didn't get it correct down here.
toString does not take any arguments. Use your field.
Please have toString defined on your Application object, as that will make your life easier. Otherwise, extract meaningful information from that object. You're going to do some string concatenation on this one in either event, which I leave as an exercise for the reader.
You need to declare the toString method in the Application class:
public class Application {
#Override
public String toString() {
// your code here
}
}
Note the use of the Override annotation. This will make the compiler check that you are actually overriding the method you say you are - in your current code, you are not as toString does not take any parameters.
As for implementation of toString, I would go with Google Guava
#Override
public String toString() {
return MoreObjects.toStringHelper(this.getClass()).add(..).add(..).toString();
}
See here for more info: https://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained
Guava docs
I am taking in an array of methods and I want to chain them together to modify an object that I am working in.
For example I start with
"getStuff().get(1).get(3).setMoreStuff().put(stuff,6)"
I split it into an array called methods, and clean up the parameters inside each method and I try to modify this.
Object res = this;
String[] methods = targetString.split("\\.(?=\\D)");
for (String m : methods){
List<Object> params = new ArrayList<Object>();
List<Object> params = new ArrayList<Object>();
for (String p : m.split("\\(|,|\\)")) {
try {
if (p.indexOf(".") != -1){
double tempD = Double.parseDouble(p);
params.add(tempD);
} else {
int tempP = Integer.parseInt(p);
params.add(tempP);
}
} catch (Exception ex) { //not a number
params.add(p);
}
}
switch (params.size()) {
case 1:
res = res.getClass().getMethod(
params.get(0)
).invoke(res);
break;
case 2:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass()
).invoke(res, params.get(1));
break;
case 3:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass(),
params.get(2).getClass()
).invoke(res, params.get(1), params.get(2));
break;
}
in the end I notice that res has been modified the way that I expect. All the getters and setters are called correctly. But of course the underlying object "this" refers to has not been changed!
I guess I'm just calling the getters and setters of the copy I made in the first line!
now I can't just use
this.getClass().getMethod(...).invoke(...)
because I need to call the same getMethod on the object returned by this call.
To clarify:
Object res = this;
creates a "pointer" to this. So that when I call
res.getStuff().setStuff(foo)
this will also be modified.
but it seem that when I call
res = res.getStuff();
res = res.setStuff();
like I do in my loop,
this does not modify the underlying object this refers to?
Edit: Included more code as per request.
Edit2: added anther example, to clarify my problem.
Edit3: tried to add more code, its a bit hard to add a working program without including every class
Your general approach should be fine (although your approach to parameter conversion is somewhat ugly) - it's the specifics that are presumably causing you problems. Here's a short but complete program demonstrating calling methods and then seeing the difference afterwards:
import java.lang.reflect.*;
class Person {
private String name = "default";
public String getName() {
return name;
}
// Obviously this would normally take a parameter
public void setName() {
name = "name has been set";
}
}
class Test {
private Person person = new Person();
public Person getPerson() {
return person;
}
// Note that we're only declaring throws Exception for convenience
// here - diagnostic code only, *not* production code!
public void callMethods(String... methodNames) throws Exception {
Object res = this;
for (String methodName : methodNames) {
Method method = res.getClass().getMethod(methodName);
res = method.invoke(res);
}
}
public static void main(String[] args) throws Exception {
Test test = new Test();
test.callMethods("getPerson", "setName");
System.out.println(test.getPerson().getName());
}
}
The output is "name has been set" just as I'd expect. So see if you can simplify your code bit by bit, removing extra dependencies etc until you've got something similarly short but complete, but which doesn't work. I suspect you'll actually find the problem as you go.
Object does not change reference, its VALUE changes. So if you will call this.get("some key"), you will get value that the same value that you put using reflection.
Right?
Ok so I'm doing an assignment for my java coursets part I'm stuck at is :
"Implement an operation createparliamentMembers which will create the particular Parliament
with 80 members."
So i've already created the constructor with it's methods. This is how I wrote the operation to create the objects using the constructor.:
public static void createparliamentMembers(){
Member[] array = new Member[75];
for(int i = 0; i < array.length; i++)
{
if (i < 35) array[i] = new Member(i, "Blue");
else array[i] = new Member(i,"Red");
}
Legislator[] leg = new Legislator[3];
for (int i = 0 ; i < leg.length; i++){
leg[i] = new Legislator(i, "Impartial");
}
Leader[] lead = new Leader[2];
for (int t = 0; t < lead.length; t++){
if (t < 1) lead[t] = new Leader(1, "Red");
else lead[t] = new Leader(2, "Blue");
}
The problem is the arrays and objects only seem to exist in the operation for creating them and when I try running method of the objects created they don't work because the driver class doesn't recognize the arrays. On the other hand when I use this as just a normal part of the Driver for it runs fine and all methods of the objects work normally.
Edit: Ok so I'm still getting the same problem as before even though i initiliased them outside the createparliamentMembers();
The following code is the Driver im using to test the methods: It keeps saying there is a:
Exception in thread "main" java.lang.NullPointerException at Driver.main(Driver.java:11)
which is the code array[1].FlipCoin(); as im trying to use the method flipcoin from the created objects but it's not working.
public static void main(String [] args) {
Commands.createparliamentMembers();
array[1].FlipCoin();
}
Your arrays are only defined locally, which means they live and die with the method. When your method finishes, they get put out of memory.
The solution is to define these arrays as instance variables. By that I mean, you need to define the arrays for your class, and then use them in your method:
class someClass {
int[] myArray = new int[2];
private void someMethod() {
myArray[0] = 3;
myArray[1] = //whatever
}
}
You state in comment:
I do have a parliament class it's on it own and contains the methods and constructor for the members of the parliament. The above method was in a seprate class called Commands. I don't understand completely the "Can you add the members to a Parliament object as you create them?" The parliament isn't an object more se then a class containing a constructor and methods for parliament members i want to create.
Parliament isn't an object yet, but you should in fact create one, and in fact your instructions tell you just that: "which will create the particular Parliament with 80 members...". You will need to tell us more about your program's structure and your specific requirements, but I suggest:
First create a Parliament object in the createParliamentMembers method, and call it parliament.
Then create the members of parliament in that method.
As you create these members, add them to the Parliament object, parliament.
At the end of the method return the parliament variable.
This means that your createParliamentMembers method's signature must change so that rather than return void it should be written to return a Parliament object.
When calling the method in the main method, assign what it returns to a Parliament variable that is in the main method.
It looks like you are writing a factory method. Create a constructor for Parliament like this:
public Parliament(Member[] members, Legislator[] legislators, Leader[] leaders) {
// do whatever with what's passed in
}
Then change your method to return a Parliament object and in the method pass your initialized arrays into the Parliament constructor, like this:
// same code as your except the last line
public static Parliament createParliament(){
Member[] array = new Member[75];
for(int i = 0; i < array.length; i++)
{
if (i < 35) array[i] = new Member(i, "Blue");
else array[i] = new Member(i,"Red");
}
Legislator[] leg = new Legislator[3];
for (int i = 0 ; i < leg.length; i++){
leg[i] = new Legislator(i, "Impartial");
}
Leader[] lead = new Leader[2];
for (int t = 0; t < lead.length; t++){
if (t < 1) lead[t] = new Leader(1, "Red");
else lead[t] = new Leader(2, "Blue");
}
return new Parliament(array, leg, lead);
}
I am having some trouble with passing data of an array from one class to the next.
edits
I am now no longer getting the error, and my code compiles, but as I had been warned, I got null for every element of the array. Now that I have taken out the static modifiers though, it still gives me null. I have also updated the code.
Here is the class where the array is created.
public class AssignSeat {
String[] arrangement = new String[12];
public void SeatStart() {
arrangement[0] = "Collins";
arrangement[2] = "Faivre";
arrangement[3] = "Kinnard";
arrangement[6] = "Morgans";
arrangement[7] = "Rohan";
arrangement[8] = "Shatrov";
arrangement[9] = "Sword";
arrangement[11] = "Tuckness";
System.out.format("%-15s%-15s%n", "seat", "passenger");
for (int i=0; i<arrangement.length; i++) {
System.out.format("%-15s%-15s%n", i+1, arrangement[i]);
}
}
public String[] getArrangement() {
return arrangement;
}
public void setArrangement(String[] arrangement) {
this.arrangement = arrangement;
}
}
and here is the method trying to access the information. It is specifically the for loop that I need help with so Ignore other areas where there are mistakes. Thank you.
public void actionPerformed(ActionEvent event) {
Scanner scanner = new Scanner(System.in);
AssignSeat seat = new AssignSeat();
if(event.getSource() instanceof JButton){
JButton clickedButton = (JButton) event.getSource();
String buttonText = clickedButton.getText();
if (buttonText.equals("first class")) {
entername.setVisible(true);
seatnum.setVisible(true);
confirmed.setVisible(true);
inputline.setVisible(true);
outputline.setVisible(true);
if ((seat.arrangement[1] == null)) {
System.out.println(seat.arrangement[0]);
System.out.println(seat.arrangement[2]);
two.setForeground(Color.green);
}
} else if (buttonText.equals("coach")) {
//System.out.println("so does this!");
entername.setVisible(true);
seatnum.setVisible(true);
confirmed.setVisible(true);
inputline.setVisible(true);
outputline.setVisible(true);
if ((seat.arrangement[4] == null)) {
five.setForeground(Color.green);
}
if ((seat.arrangement[5] == null)) {
six.setForeground(Color.green);
}
if ((seat.arrangement[10] == null)) {
eleven.setForeground(Color.green);
}
}
}
}
The problem lies in the fact that the array was declared as static, but the initialization code for it is in the constructor. Remove all the static modifiers in the original code, and replace this part:
if (AssignSeat.getArrangement()[1].equals("null"))
With this:
AssignSeat assign = new AssignSeat();
if (assign.getArrangement()[1] == null)
Also notice that "null" is not a null value, use null (without quotes) for that.
A different approach would be to leave the array as an static member, but initialize it statically, like this:
private static String[] arrangement = new String[12];
static {
arrangement[0] = "Collins";
arrangement[2] = "Faivre";
arrangement[3] = "Kinnard";
arrangement[6] = "Morgans";
arrangement[7] = "Rohan";
arrangement[8] = "Shatrov";
arrangement[9] = "Sword";
arrangement[11] = "Tuckness";
}
In that case, this would work:
if (AssignSeat.getArrangement()[1] == null)
But I still believe that making the array static is going to be problematic if several instances of the class happen to be modifying its contents.
Replace
if (AssignSeat.getArrangement()[1].equals("null"))
with
if (AssignSeat.getArrangement()[1] == null)
If the value is null, you can't invoke methods (like equals) on it. You need to compare the value directly to null, which is a constant rather than a string.
Ok, I'm a bit confused as to what you're trying to do in the first class. You are initializing a static array from an instance method...
In other words, the String values in the array will be null until you call SeatStart from an instance of the class.
Try to initialize the String array from the static constructor for AssignSeat to make sure it has been initialized before you use it: http://www.snippetit.com/2009/05/java-static-variables-static-methods-and-static-constructor/
You are trying to use an attribute of a class, without instantiating the object first. Until you call a default/user-defined constructor, there is no memory dedicated to the attribute of that object.
Even though you manage to call the method you are using a static method, which can be called without an instance of the object being required.
Create a constructor for the object (or use a default constructor) and then you will be able to access your attribute because your object will be on the heap and have memory allocated for the string[].
Simply define the SeaStart as an Array.
public String[] SeatStart() {
arrangement[0] = "Collins";
arrangement[2] = "Faivre";
arrangement[3] = "Kinnard";
return arrangement;
}
For convinience, make a new array to copy the array from AssignSeat class. Then retrieve the value from that array.
public void actionPerformed(ActionEvent event) {
AssignSeat seat = new AssignSeat();
String[] foo = seat.SeatStart();
System.out.println(foo[0]);
System.out.println(foo[1]);
System.out.println(foo[2]);
}
Though you can acces it also with:
System.out.println(seat.SeatStart()[0]);
The result would be:
Collins
null
Faivre
and that 'null' is because apparently you haven't allocate a value for arrangement[1] :-)
But in the end, it works.