简体   繁体   中英

Java method call in method

I am in the process of learning java. I have previously learned ruby so I am taking some ruby code I know works and trying to convert to java, but I'm a little lost with this one so thanks in advance. I tried extends and that still isn't working :(

I have created a class Visitor which takes in name, gender, age, and citizenship. I am trying to have a new method AdmitNewVisitor in the House class where I can manually insert a new Visitor in a test. So, this code works below, but then the next code will not work and I can't figure out why, I've searched for hours and my book doesn't have an example.

What I am currently doing

    public void AdmitNewVisitor( )
    {
        for (int i = 0; i < 2; i++)
        {
            numVisitors++;
            visitors[numVisitors - 1] = new Visitor("Grates, Brill", "M", 66, "Alien");
        }
    }

What I want to do

I have changed i < numVisitors (max 100) defined in full code

    public void AdmitNewVisitor(String theName, String theGender, int theAge, String theCitizenship )
    {
        for (int i = 0; i < numVisitors; i++)
        {
            numVisitors++;
            visitors[numVisitors - 1] = new Visitor(theName, theGender, theAge, theCitizenship);
        }
    }

New Test Method

t.AdmitNewVisitor("Grates, Brill", "M", 66, "Alien");

In ruby you would just do

def admit_new_visitor the_name, the_gender, the_age, the_citizenship
  @num_visitors += 1
    @visitors[@num_visitors - 1] = Visitor.new(the_name, the_gender, 
  the_age, the_citizenship)
end

Edit: Forgot to specify error, sorry long day the error is there nothing displayed when I do toString(), no error message, just prints my string and no visitors where visitors should appear. I now see that I should not run this in a loop as that doesn't make sense, when I try

public void AdmitNewVisitor(String theName, String theGender, int theAge, String theCitizenship)
{
    numVisitors++;
    visitors[numVisitors - 1] = new Visitor(theName, theGender, theAge, theCitizenship);
}

I receive error:

error: constructor Visitor in class Visitor cannot be applied to given types
     {
     ^
Required: String, String, int, String
found: no arguements
reason: actual and formal arguments differ in length

I believe it's referring to this line of code in Visitor class, all variables are public in Visitor

public Visitor(String theName, String theGender, int theAge, String theCitizenship)

Edit: Everyone has been very helpful but since I'm learning from scratch and haven't gotten to lists yet, is there any way to do this the way I am trying? The ant eats the elephant one bite at a time


Edit 3 Visitor Class

import java.util.*;

public class Visitor
{
    // Define Instance Variables
    public String name;
    public String gender;
    public int age;
    public String citizenship;
    public int currentRoom;

    // Define Constructor
    public Visitor(String theName, String theGender, int theAge, String theCitizenship)
    {
        name = theName;
        gender = theGender;
        age = theAge;
        citizenship = theCitizenship;
        currentRoom = 0;
    }

    public String toString( )
    {
        String output = String.format("%-20s %-15s %d", name, citizenship, currentRoom);
        return output;
    }
}

Edit 4 forgot this, included in HouseTour class where AdmintNewVisitor is located in

public Visitor[ ] visitors = new Visitor[100];

Edit: SOLVED

Well, I have been tinkering with my code for a bit and I think I know the problem. Thanks to all but specifically @Dan Temple, I should have probably worked on this when I was less tired so I know exactly where I went wrong but I ended up using the code below, numVisitors = 0 is defined previously so numVisitors++ comes first, then subtracts 1 to get place in array. I believe, and I could be wrong, the problem was listing my public String toString() method that involved visitor BEFORE listing my AdmitNewVisitor, or maybe I'm just tired. In ruby, I had no problems listing my to_s (toString() in java) before my new_visitor method. Thanks again, great to know I'm not in this alone :{o :{/ :)

public void AdmitNewVisitor(String theName, String theGender, int theAge, String theCitizenship)
{
    numVisitors++;  
    visitors[numVisitors - 1] = new Visitor(theName, theGender, theAge, theCitizenship);    
}

The joy with Java is it's Object Oriented nature. You can achieve what you're Ruby does, but let a List do all the heavy lifting for you.

If you create and maintain a list of visitors, then you can simply create your Visitor object and add it to the list. The list then has a size() method that will allow you get the number of visitors whenever you need it.

In my example, I have used ArrayList (the most common type) but there are a number of lists (and indeed other collections) that could be used. This page could be useful.

import java.util.ArrayList;
import java.util.List;

public class Visitors {

    private final List<Visitor> visitors;

    public Visitors() {
        this.visitors = new ArrayList<Visitor>(); //Initialise the list within the constructor here.
    }

    public void AdmitNewVisitor(final String theName, final String theGender, final int theAge, final String theCitizenship ) {
        //create your new visitor with the new keyword. Then add it to the list of visitors.
        final Visitor visitor = new Visitor(theName, theGender, theAge, theCitizenship);
        this.visitors.add( visitor );
    }

    public Integer getNumberOfVisitors() {
        //There's no need to maintain the number of visitors yourself, you can let the List do it.
        return this.visitors.size();
    }
}

Edit:

Of course, this relies on having a Visitor object with the correct constructor:

public class Visitor {

    private final String theName;
    private final String theGender;
    private final int theAge;
    private final String theCitizenship;

    public Visitor(final String theName, final String theGender, final int theAge, final String theCitizenship) {
        this.theName = theName;
        this.theGender = theGender;
        this.theAge = theAge;
        this.theCitizenship = theCitizenship;
    }

    public String getTheCitizenship() {
        return theCitizenship;
    }

    public int getTheAge() {
        return theAge;
    }

    public String getTheGender() {
        return theGender;
    }

    public String getTheName() {
        return theName;
    }
}

Edit:

You could do it maintaining your own array and number of visitors, but you'd need to think about the following:

  • The number of visitors would need to be defined as an instance/static field. (Personally, I'd go with instance and have the Visitors class instantiated when using it.)
  • You're only adding one visitor at a time, so there's no need to have a loop in your addNewVisitor method.
  • Arrays are indexed from 0, so the first visitor is at index 0 and the last visitor is at index ( this.visitors.length - 1 ) . Incrementing the number of visitors after adding the visitor to the array will avoid any index arithmetic.
  • When maintaining the array, keep in mind that it won't expand by itself. If you have an array of size 10, but then you try to add a visitor to index 11 (you get a surprise 11th visitor!) then you will need to copy the array contents into a bigger array. This is why we use Lists in Java. They handle this dynamic size issue for us.

As requested in the comments, no code solution, just the above tips.

Edit:

Adding a solution using arrays and maintaining the number of visitors by hand. I will ignore the dynamic size of arrays problem for now. (The array will just be initialised to be large)

From what I can gather, you need the visitor class that I have given previously. This is a separate class to you overall class that monitors the array (or list) of visitors. This class represents your visitor object. In your Ruby, you have Visitor.new(the_name, the_gender, the_age, the_citizenship) . This becomes new Visitor(theName, theGender, theAge, theCitizenship) in Java.

The @num_visitors needs to be defined outside of the method that adds a visitor because it is a globally maintained value, it does not just exist within the admitNewVisitor method.

The only other thing of note is that I increment the numberOfVisitors after adding the visitor to avoid doing index arithmetic.

public class Visitors {

    private int numberOfVisitors = 0;
    private final Visitor[] visitors;

    public Visitors() {
        this.visitors = new Visitor[250];
    }

    public void AdmitNewVisitor(final String theName, final String theGender, final int theAge, final String theCitizenship ) {
        final Visitor visitor = new Visitor(theName, theGender, theAge, theCitizenship);
        this.visitors[this.numberOfVisitors] = visitor;
        this.numberOfVisitors++;
    }

    public Integer getNumberOfVisitors() {
        return this.numberOfVisitors;
    }
}

And a test for this would look maybe like this:

@Test
public void thatnumberOfVisitorsIncreasesWhenAVisitorIsAdmitted() {
    final Visitors visitors = new Visitors();

    Assert.assertEquals(visitors.getNumberOfVisitors(), (Integer) 0);

    visitors.AdmitNewVisitor("name", "male", 50, "British");

    Assert.assertEquals(visitors.getNumberOfVisitors(), (Integer) 1);

    visitors.AdmitNewVisitor("name2", "female", 48, "British");

    Assert.assertEquals(visitors.getNumberOfVisitors(), (Integer) 2);
}

Hope that helps. Testing is always important, but don't get too bogged down with format/syntax of the test method while you are learning.

I don't think you want to keep the for loop in your method.

    for (int i = 0; i < numVisitors; i++)
    {
        numVisitors++;
        visitors[numVisitors - 1] = new Visitor(theName, theGender, theAge, theCitizenship);
    }

That will loop forever, since you're increasing numVisitors in your loop, while using it as the limit. It also doesn't make sense even if it didn't loop forever, because it would fill your visitors array with the same named Visitor. So if you had 5 visitors and you admitted a new visitor "George", you'd have 6 "Georges" in there.

If you remove the for-loop, it will add a single new Visitor to your array.

Well, some tips for you:

  • In java you should use List instead of simple array to avoid IndexOutOfBounds exception.
  • In ruby array is analogue of javas list so you should just push your new visitor to it.
  • You have an infinitive loop here: HouseTour#AdmitNewVisitor

You want a code? Get some:

// java 7.

public class HouseTour {
    // Define Instance Variables
    private List<Visitor> visitors = new LinkedList<>;
    //...

    /*
    *  renamed method to java-style.
    */
    public void admitNewVisitor (String theName, String theGender, 
                                int theAge, String theCitizenship){
       numVisitors ++;
       visitors.push(new Visitor(theName, theGender, theAge, theCitizenship));
    }

}

You can choose between LinkedList and ArrayList. First is needed when you want to resize it often. Second is needed when you want to access its elements often.

Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM