How do I call a method on an object when it is outside the scope of where the object was created [closed]

StackOverflow https://stackoverflow.com/questions/19507009

Pergunta

I have an ArrayList called "filmList" in a separate class called actors, I want to use case 2 in the switch to call newActor.filmList.get(i); but I keep getting object may not be initialized errors from the compiler. If I put the same line in switch case 1 it works fine, but in case 2 i get the error. Can someone please tell me how I can call a method on the object from outside where the constructor creates the newActor object, I will be eternally grateful, it is doing my head in and my lecturer is terrible at explaining things. Thanks.

public class ActorsMain {

public static void main(String[] args) {

    Scanner kb = new Scanner(System.in);

    String fName="";
    String lName="";
    String address="";
    int age;
    String filmEntry="";
    String code="";


    ArrayList actors = new ArrayList(); 
    ArrayList films = new ArrayList();
    int choice=0;
    while(choice!=3){
    System.out.println("Make your selection.\n1. Add Actor\n2. List Actors");
    choice=kb.nextInt();

    switch (choice){

    case 1:
            System.out.println("\nPlease enter the actors first name:");
            fName=kb.next();
            System.out.println("Please enter the actors second name:");
            lName=kb.next();
            System.out.println("Please enter the actors address:");
            address=kb.next();
            System.out.println("Please enter the actors age:");
            age=kb.nextInt();
            kb.nextLine();

            for(int a=0;a<10;a++){
            System.out.println("Please enter the actors film.\nType 'Stop' to stop entering films.");
            filmEntry=kb.nextLine();
            //kb.nextLine();
                if(filmEntry.equalsIgnoreCase("stop")){
                    break;
                }
                else {

                    Films filmObject = new Films(filmEntry,code);
                    films.add(filmObject);
                }
            }


            Actors newActor = new Actors(fName,lName,address,age);
            actors.add(newActor);

            newActor.setFilm(films);
            films.clear();
            break;

    case 2:

        break; 


    }
    }





}       

}

Foi útil?

Solução

You will have to declare newActor outside the scope of the switch statement. Inside case 2 of your switch, newActor doesn't exist.

int c = 0;
switch (c) {
    case 1:
        Object obj = new Object();
        break;
    case 2:
        System.out.println(obj.toString()); // obj only exists in case 1
        break;
}

This is actually a little peculiar and maybe somebody else can explain why, but the error you are getting seems to be particular to the switch statement. If you try to do the following:

int c = 0;
if (c == 1) {
    Object obj = new Object();
} else if (c == 2) {
    System.out.println(obj.toString());
}

You will get a different error that says "cannot find symbol" which is more to the point. Apparently cases inside a switch share scope such that they can "see each other". I assume this is related to the sans-break fall-through. Switches are all one block and the cases only determine the entrance point.

I'm not sure what you are trying to do to tell you where to put your newActor declaration but the point is right now case 2 in your switch can't use it. It only exists inside case 1.

Also you shouldn't use a switch for such a long statement. You should at least refactor it so it uses if statements. Switches are just not meant for this kind of thing. They are meant for long conditions with lots of possibilities and small statements for each case:

char operator = '*';
int leftNumber = 5;
int rightNumber = 9;

switch (operator) {
    case '+': System.out.println(leftNumber + rightNumber);
              break;
    case '-': System.out.println(leftNumber - rightNumber);
              break;
    case '*': System.out.println(leftNumber * rightNumber);
              break;
    case '/': System.out.println(leftNumber / rightNumber);
              break;
    case '^': System.out.println(Math.pow(leftNumber, rightNumber));
              break;
    default:  System.out.println("Unknown operator");
}

As a long side note, you are not passing a type parameter to your ArrayLists. Java doesn't know that your ArrayLists contain Actors and Films unless you say so:

ArrayList<Actors> actors = new ArrayList<Actors>();

ArrayLists and other generics are supposed to be initialized with a bracketed parameter of <E> where E is the desired class type of the elements in the array.

The type parameter is a little bit like extending a class. The ArrayList class will have E all over the source code and when you pass Actor in to the E parameter, E is replaced with Actor.

class ArrayList<E> {
    Object[] array = new Object[some_length];
    public E get(int index) {
        return (E)array[index];
    }
}

becomes

class ArrayList<Actor> {
    Object[] array = new Object[some_length];
    public Actor get(int index) {
        return (Actor)array[index];
    }
}

Note that even then whether or not Java knows that that ArrayList contains Actors while the application is running is still vague due to the way generics are implemented. They are implemented using something called erasure. At runtime there is no way to know that the ArrayList is of the Actor type.

If you declare them with the type parameter, you will be able to access their elements using get() as Actors and Films in your code which you won't be able to right now.

In other words you can do this:

System.out.println(actors.get(aIndex).filmList.get(fIndex));

Which it looks like you are starting to try to do under case 2 but you also won't be able to do at the moment. Without <Actor> or <Film> it will tell you "cannot find symbol" or "incompatible types" because the ArrayList holds an array of Object without the type parameter. (It's still an array of Object with the type parameter but you can use it like the type you pass in.)

Outras dicas

Im guessing your Actor class has an ArrayList called filmList and you want to get the value from it at a certain position. If that is the case you should probably create a getFilmListIndex(int pos) method in your Actor class that takes in an index value and returns whatever object your film list stores. Assuming your filmList stores String it might look something like this.

  public String getFilmListIndex(int pos)
      {
         return filmList.get(i);
      }

Then call this method from your ActorMain class.

  String result = newActor.getFilmListIndex(i);

age is uninitialized when you declare it. In case 1 it will be set, but in case 2 it is not clear that it has been set yet.

You could assign it a dummy value when you declare it, but in general it is better practice to mostly scope variables only where they are actually being used & have a valid value.

That would suggest putting all the actor details into a separate method or (not as nice) inside {} curly brackets, and only declare them as you are assigning the value. Having accessible variables hanging around with undefined, dummy or outdated values is provably less correct than only having a variable declared with a scope equivalent to when it's value is valid & applicable.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top