I'm working on a little project for fun, that's essentially a little combat emulator. I'm trying to use a class similar to struct in C++, as in using it to create an object (in this case, a character or "entity", as the class is called). I'm getting the error in the title when attempting to call any integer in said class from the main function.
class entity{
public int health;
public int accuracy;
public int power;
public int defense;
}
And
public class Tutorial {
static Random rnd = new Random();
entity player;
player.health = 100; // Issue on the health part
player.accuracy = 19; // Issue on the accuracy part
player.power = 15; // Issue on the power part
player.defense = 18; // I think you get it by now...
I've been looking around for a while to find some explanation, but there's none that I could find that explain the nature of the error as well as possible fixes for my situation. If I could get those, it would be wonderful.
The compiler is expecting a variable declaration on the line
player.health = 100;
but is finding an assignment instead. The statements
Entity player = new Entity();
player.health = 100;
player.accuracy = 19;
player.power = 15;
player.defense = 18;
should be in a code block such as a method or constructor rather than the class block
Procedural code cannot be written directly in a class definition. The code is causing syntax errors because it's not legal to do so.
Instead, put the code in an appropriate method or initialization block. (I do not think an initialization block is appropriate here, so I am trivially showing a "factory method".)
As such, consider an approach like
// This is a member variable declaration, which is why it's OK
// to have a (static) method call provide the value.
// Alternatively, player could also be initialized in the constructor.
Entity player = makeMeAPlayer();
static Entity makeMeAPlayer() {
// Create and return entity; the code is inside a method
Entity player = new Entity();
player.health = 100;
// etc.
return player;
}
(I've also cleaned up the type to match Java Naming Conventions - follow suite!)
Here is another way to suffer from highly accurate yet not terrible intuitive messaging for VariableDeclaratorId.
#PostMapping("/showCompany")
public String processForm(#ModelAttribute("company") CompaniesDAO company, company_name, company_function) {
Will produce:
Syntax error, insert "... VariableDeclaratorId" to complete FormalParameter
This is telling you that is need the variable type like String or int...
#PostMapping("/showCompany")
public String processForm(#ModelAttribute("company") CompaniesDAO company, String company_name, String company_function) {
It turns out VariableDeclaratorId is a class
public class VariableDeclaratorId
extends Expression
implements prettyprint.PrettyPrintable
If you read the class description using it with the error message to determine that you forgot to define the variable type, I am impressed; I simply made an educated guess.
It is because you forgot to add the main method,
public class Tutorial {
public static void main(String[] args) {
static Random rnd = new Random();
entity player;
player.health = 100; // Issue on the health part
player.accuracy = 19; // Issue on the accuracy part
player.power = 15; // Issue on the power part
player.defense = 18; // I think you get it by now...
}
}
and
class entity{
public int health;
public int accuracy;
public int power;
public int defense;
}
Related
I am learning Java, so I understand this is a very simple question, but I still want to understand it.
I want to let my code automatically generate soldiers, and the number automatically increases, but I failed.
the Soldier.class:
package com.mayer;
import java.util.Random;
public class Soldier {
private int number=0;
private int ATK;
private int HP;
Random ra = new Random();
public Soldier(){
this.number++;
this.ATK = ra.nextInt(10)+90;
this.HP = ra.nextInt(20)+180;
}
public void report(){
System.out.println("number:"+this.number+"\t"+
"ATK:"+this.ATK+"\t"+
"HP:"+this.HP);
}
}
the main.class
package com.mayer;
public class Main {
public static void main(String[] args) {
Soldier[] soldiers = new Soldier[5];
int i = 0;
while(i<5){
soldiers[i] = new Soldier();
i++;
}
for(Soldier sol:soldiers){
sol.report();
}
}
}
That's what I get:
number:1 ATK:94 HP:187
number:1 ATK:94 HP:181
number:1 ATK:96 HP:193
number:1 ATK:90 HP:183
number:1 ATK:95 HP:193
So you see,each of this number is 1.
You have added number field which is instance field. It will initialize per instance. You are looking for static type variable. Please check static into java.
Instance Variables (Non-Static Fields) Technically speaking, objects
store their individual states in "non-static fields", that is, fields
declared without the static keyword. Non-static fields are also known
as instance variables because their values are unique to each instance
of a class (to each object, in other words); the currentSpeed of one
bicycle is independent from the currentSpeed of another.
Class Variables (Static Fields) A class variable is any field declared with the static modifier; this tells the compiler that there
is exactly one copy of this variable in existence, regardless of how
many times the class has been instantiated. A field defining the
number of gears for a particular kind of bicycle could be marked as
static since conceptually the same number of gears will apply to all
instances. The code static int numGears = 6; would create such a
static field. Additionally, the keyword final could be added to
indicate that the number of gears will never change.
The constructor is changed to:
public Soldier(int number){
this.number = number;
this.ATK = ra.nextInt(10)+90;
this.HP = ra.nextInt(20)+180;
}
As others have said, each Soldier instance has its own separate number field which starts with 0. You can use a static field to count the instances:
public class Soldier {
private static int counter = 0;
private int number;
// other fields left out for clarity
public Soldier(){
Soldier.counter++; // field shared among all Soldier instances
this.number = counter; // number belongs to this instance only
// ...
}
// ...
}
However, I wouldn't recommend doing it this way. When you get more advanced, you'll learn that using a static field like this can cause problems in a multi-threaded application. I would instead advise passing the number to the Soldier constructor:
public class Soldier {
private int number;
// ...
public Soldier(int number){
this.number = number;
// ...
}
// ...
}
And then:
public static void main(String[] args) {
Soldier[] soldiers = new Soldier[5];
int i = 0;
while(i<5){
soldiers[i] = new Soldier(i);
i++;
}
Soldier.class
all-uppercase field names tend to be used for constants.. basic fields use headless camel-case.. They should also be descriptive, i.e. you should look at them an it should be apparent what they represent - for example a variable "number" is not a good idea, because it's ambiguous
Random can be converted to a local variable, no need to keep it on the class level
The mechanism by which soldiers are assigned IDs should be on a higher level - it can't be managed by the soldier object itself, hence the constructor with an argument
overriding the toString method is the traditional way of transforming the object to string for debugging purposes.. also most IDEs can generate it with a press of a button so no space for human error
You will obviously need getters and setters for your variables, if you wish to read or change them from elsewhere, but I don't think that's necessary to post here.
private int soldierID;
private int attack;
private int health;
public Soldier(int id){
this.soldierID = id;
Random random = new Random();
this.attack = random.nextInt(10) + 90;
this.health = random.nextInt(20) + 180;
}
#Override
public String toString() {
return "Soldier{" +
"soldierID=" + soldierID +
", attack=" + attack +
", health=" + health +
'}';
}
Main.class
it's perfectly fine and actually preferred to use a List instead of an array, because it's more comfortable to work with
this way it's even much easier to add them dynamically and use the iterator for ID
you can "report" in the creation cycle
This even shortens the method a bit, not that it's that important here.
public static void main(String[] args){
List<Soldier> soldiers = new ArrayList<>();
for(int i=0; i<5; i++){
Soldier newSoldier = new Soldier(i);
soldiers.add(newSoldier);
System.out.println(newSoldier.toString());
}
}
This way when you define the soldier IDs it's not from within the Soldier class but rather from something that is "observing" all the soldier classes and knows which is which.
The purpose of this program is to create a class and tester class for a select object(in my case a monitor), with at least one overloaded method. And in the client class, I have to instantiate at least three instances of the object. So far I believe I've finished the first class with the declaration of methods, getters and setters, and constructors. The problem occurs in my tester class, where I get the error "Cannot resolve method 'MonitorV82' in 'Monitor V82'. I don't know for sure why I'm getting this error, any advice?
My first class is:
public class MonitorV82
{
private double l;
private double h;
//one parameter constructor, all private instance variables initialized
public MonitorV82(double monitor1Height) {
//2.When this gets name1(jupiter), it designates "jupiter" to the variable "n"
h = monitor1Height;
l = (monitor1Height * 1.77);
}
//two parameter constructor
public MonitorV82(double monitor1Height, double monitor1Length){
//3.When this gets name1(jupiter), and a double, it sets jupiter to "n" and the diameter to "d"
h = monitor1Height;
l = monitor1Length;
}
public double getMon1height() { return h; }
public double getMon1Length() {
return l;
}
public void setMon1height(double name) { h = name; }
public void setMon1Length(double diam) {
l = diam;
}
public String monType(int resolution)
{
String monitType = "";
if (resolution == 1080) {
monitType = "lenovo";
} else if (resolution == 4000) {
monitType = "samsung";
}
return monitType;
}
//overloaded method
public String monType(int pixLength,int pixHeight)
{
String monitType = "";
if (pixHeight == 1080) {
monitType = "lenovo";
} else if (pixHeight == 4000) {
monitType = "samsung";
}
return monitType;
}
}
My tester class(where the error is) is:
public class V8Tester {
public static void main(String[] args) {
double length1 = 32.2;
double height1 = 51.8;
double length2 = 31.8;
double height2 = 50.6;
int resolution = 0;
MonitorV82 monit1 = new MonitorV82(length1);
resolution = monit1.MonitorV82(height1);
}
}
I am still learning Java in school so please don't roast me if something seems obvious or simple. Thank you for your help.
You are getting this error because there is no method MonitorV82, only a constructor. Also you are trying to instantiate the int variable resolution with a MonitorV82 object, which is not possible, because the compiler expects an int value.
If you want the resolution that refers to the pixel count of the MonitorV82 object with known pixel height, you first need to find out it's pixel length. You can do this by using your getMon1length() method and the calculate the resolution by length * height. Ultimately what I think you are trying to do is:
int heightMonit1 = monit1.getMon1height();
int resolution = (int)length1 * (int)heightMonit1;
You need to type cast, because you want to instantiate the int variable resolution with a calculation of double values.
You could however also use your second constructor and do:
MonitorV82 monit1 = new MonitorV82(length1, height1);
int resolution = (int)monit1.getMon1height() * (int)monit1.getMon1length();
Before answering the question in the title, you need the answer to this question:
What is a constructor in Java?
A constructor in Java is a special method used to "construct" (build, instantiate, etc.) objects. A constructor follows these basic rules:
The name of the constructor should match exactly the class name. In your case, MonitorV82 is this name.
A constructor doesn't have a return type. The new operator is responsible for returning a new object matching the type of the class in which the constructor is being invoked.
Knowing this, let's address the original question: Why the error? Because in MonitorV82 there is only a constructor a with matching name, but not a regular method with the same name. Consider my example below
public class Test {
private String name = "default";
// constructor #1
public Test() {}
// constructor #2
public Test(String name) {
this.name = name;
}
// method #1
public void Test() {
System.out.println(name);
}
// method #2
public void Test(String name) {
System.out.println(name);
}
}
Notice that in the code above, I have two constructors and two methods with the same name (matching case) and same parameters. This is allowed in Java although this is STRONGLY discouraged due to how confusing it can get.
What does this mean for you?
To create monit1, you need to invoke a CONSTRUCTOR. Once you construct the object, you cannot use it to invoke a constructor. You use objects to invoke non-static, accessible methods. Based on this, the line
MonitorV82 monit1 = new MonitorV82(length1);
is totally fine. However, the set resolution line is not resolution = monit1.MonitorV82(height1); because you have no METHOD named MonitorV82 (you just have a constructor with a matching name). You fix this by creating a method in your class that does exactly that. Since method names should be descriptive of their function, creating a method named setResolution or calculateResolution should be fine. What you should not do is used an ambiguous name; especially using the same name as the constructor.
Lastly, I will leave you with this small piece of advice: Just because the language allows you to do something, that does not mean that it is correct or OK to do so. My code example (along with this lengthy explanation) should've illustrated this point.
tl;dr
You asked:
Why am I getting the error "cannot resolve method "x" in "x""?
Because your last line tries to call a method named MethodV82 which does not exist on an instance of the class named MethodV82.
Details
Firstly, you should have indicated which line of code is causing that error.
You have at least one offending line, that last line. The code monit1.MonitorV82(height1) makes no sense. That code is trying to call a method named MonitorV82 on the instance named monit1. But of course there is no such method. Thus the error « Cannot resolve method ».
I cannot follow your logic, so I cannot give a fixed replacement code snippet.
I think you are misunderstanding the use of constructors.
I guess that what you want to do with your monit1.MonitorV82(height1) is to set the height of your monit1 instance to height1.
You need to call the setter to do so, not a constructor. The constructor is not known as a class method, that is why your error occurs. Use
monit1.setMon1height(height1);
Next, I think that you are trying to retrieve a resolution from your monitor, but you have no method inside of your MonitorV82 with this aim so I suggest that you create a method for this such as
public int computeResolution() {
return this.h * this.l;
}
In your test class you end up with:
public class V8Tester {
public static void main(String[] args) {
double length1 = 32.2;
double height1 = 51.8;
double length2 = 31.8;
double height2 = 50.6;
int resolution = 0;
MonitorV82 monit1 = new MonitorV82(length1);
monit1.setMon1height(height1);
resolution = monit1.computeResolution();
}
}
Edit: Even the instantiation of your monit1 does not seem correct. The only one parameter constructor you have is based on height and you are calling it with length1
Edit2: My example of computeResolution() will probably end up with an exception as I am returning an int from a compute action on doubles. But I think that it is not the main issue here
This is probably a really silly question, but I figured I'd try asking! Basically the question is this: can I use a switch statement in my setters?
Here's what I'm doing: I've created a Monster class with the attributes of healthPoints, description, damage, and type, in which type is an enum. In my driver, I've written a few lines of code that will randomly generate a monster type from the enum values, and it will create a new monster using that type.
The issue is that when I display the monster stats, it shows healthPoints and damage as 0, and description as null. When I try to run the program using the default Monster constructor, it crashes and shows a NullPointerException error.
I think the error is in either my setters or the constructors. Each of the setters has a switch case inside, which sets a certain number of healthPoints, damage, and a specific description depending on the type of monster that is randomly generated. I'm not sure if it's even okay to use a switch statement in a setter because I've never really had to before.
Here is some of my code. First, my constructors.
public Monster(int healthPoints, monsterType type, int damage, String description)
{
setHealthPoints(healthPoints);
setType(type);
setDamage(damage);
setDescription(description);
}
public Monster(monsterType type)
{
setType(type);
}
Below is one of the setters.
public void setHealthPoints(int healthPoints)
{
switch(type)
{
case DROW:
healthPoints = 30;
break;
case LICH:
healthPoints = 40;
break;
case ORC:
healthPoints = 20;
break;
case OWLBEAR:
healthPoints = 20;
break;
case RUST_MONSTER:
healthPoints = 10;
break;
}
this.healthPoints = healthPoints;
}
And below is the line in the driver that creates the monster.
int number = new Random().nextInt(monsterType.values().length);
Monster monster = new Monster(monsterType.values ()[number]);
I want the monster's healthPoints, damage, and description to be set depending on the type of monster that is generated. I'm not sure if this can be done using switches in the setters, and I feel like my mistake is probably obvious and I'm just not seeing it because I've been staring at it for a long time...or, if there's a different or easier way to do this, please let me know! Thank you for taking the time to read; I tried to make my question/problems thorough.
Explanation
Yes you can use switch cases in the constructor and in methods. The issue is that you are calling setHealthPoints before setType but the first methods uses the type in its switch statement:
setHealthPoints(healthPoints);
setType(type);
Therefore the variable type is uninitialized when you visit the switch of setHealthPoints and thus currently null.
A switch statement will throw a NullPointerException if its argument is null. Thus you get the NPE.
You can fix this by first executing setType.
Advice on game architecture
You should create a more readable structure that is also easier to maintain and especially easy to extend.
Therefore consider creating a Monster interface or abstract class. After that create explicit monsters as subclasses. The class Monster will contain everything that is equal among all monsters, try to abstract from specific monsters. The monsters themselve will then only contain what differentiates them from the rest.
For example you could use some kind of this:
public abstract class Monster {
private int mHealthPoints;
private int mDamage;
private String mDescription;
public Monster(int healthPoints, int damage, String description) {
this.mHealthPoints = healthPoints;
this.mDamage = damage;
this.mDescription = description;
}
public int getHealthPoints() {
return this.mHealthPoints;
}
public int getDamage() {
return this.mDamage;
}
public String getDescription() {
return this.mDescription;
}
}
And then you have specific monster classes like
public class Orc extends Monster {
private static int HEALTH = 20;
private static int DAMAGE = 10;
private static String DESCRIPTION = "Nasty orc.";
public Orc() {
super(Orc.HEALTH, Orc.DAMAGE, Orc.DESCRIPTION);
}
}
You also don't need that monsterType enum anymore since you can differentiate via monster instanceof Orc. However for a really modular design you shouldn't work on specific classes. Instead use a lot of interfaces that describe properties and abilities.
For example interfaces like:
CanAttack
IsAttackable
HasHealth
CanWalk
CanFly
CanCollide
...
Your game logic then may be built only on those interfaces. For example CanAttack could look like:
public interface CanAttack {
void attack(IsAttackable target);
}
The huge advantage is that you then can easily extend your game. For example by creating monsters with arbitrary combinations of abilities:
public SuperFlyingPig extends Monster implements
CanAttack, HasHealth, CanWalk, CanFly {
...
}
And it magically will work without any additional coding effort since your logic will not care for the specific monster. It will only work on the interfaces.
My question is regarding the declaration and value assignment rules in Java.
When writing the fields we can declare and assign values together but we cannot do the same separately.
E.G.:
class TestClass1 {
private int a = 1;
private int b ;
b= 1;
private int sum;
public int getA() {
return a;
}
public int getB() {
return b;
}
public int getSum() {
sum = a + b;
return sum;
}
}
public class TestClass {
public static void main(String[] args) {
TestClass1 testClass1 = new TestClass1();
System.out.println("total =" + testClass1.getSum());
}
}
Here in line:
private int a = 1;
We are able to declare a as a private int and assign a value 1 to it. But in case of:
private int b ;
b= 1;
Eclipse does not allow this to happen and throws an error. Kindly explain the logic behind this.
Code inside a class, but outside a function, is purely declarations. It does not get "executed". It simply declares what fields a class contains.
The reason you can do the shorthand private int a = 1; is just syntactic sugar that the Java language allows. In reality, what happens is that the a = 1 part is executed as part of the constructor. It's just easier to read and write when it is next to the variable declaration.
It's something nice that the Java langage creators allowed. Not every language allows that, look at C++ as an example that does not always allow it.
you have to put b=1; inside a method or put this inside a constructor.
you are getting this error since you can't do any thing other than declaration(private int a= 1;
) in class level.
It's just a question of syntax in Java. In the example you show, you try to affect a value to b in the member declaration part of your class. This is not allowed by the syntax of Java. You can only do it when you declare your attribute, in the body of a method or in a static block if your attribute is static e.g. :
private static int b;
static {
b = 1;
}
It is only a syntax problem. You can do it like this :
private int b ;
{ // <- Initialization block
b= 1;
}
See What is an initialization block?
You are unable to write logic directly in the class. You should move it to the constructor.
Java only allow declaration within the class and outside any method. Declarations like int b = 1; will be executed when you initialize a new Object.
I have a task to operate on complex number. Each number consists of double r = real part, double i = imaginary part and String name. Name must be set within constructor, so I've created int counter, then I'm sending its value to setNextName function and get name letter back. Unfortunately incrementing this 'counter' value works only within costructor and then it is once again set to 0. How to deal with that?Some constant value? And second problem is that I also need to provide setNextNames(char c) function that will change the counter current value.
The code :
public class Imaginary {
private double re;
private double im;
private String real;
private String imaginary;
private String name;
private int counter=0;
public Imaginary(double r, double u){
re = r;
im = u;
name = this.setNextName(counter);
counter++;
}
public static String setNextName(int c){
String nameTab[] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N",
"O","P","Q","R","S","T","U","W","V","X","Y","Z"};
String setName = nameTab[c];
System.out.println("c: "+c);
return setName;
}
public static String setNextName(char c){
//
//don't know how to deal with this part
//
}
It's hard to tell what you're doing, but I suspect this will solve your immediate problem:
private static int counter = 0;
You should make counter static.
You should also make nameTab a private static field, then in setNextName(), you can iterate through it to find the name corresponding to the given character, and get its index. (in the plain ASCII world, of course one could simply calculate the index by subtracting the numeric value of 'A' from the given character, but I am not quite sure how it would work out with Java, in Unicode, with crazy inputs - iteration is on the safe side.)
In OO languages there are typically two types of variables that go into a class:
instance variables that are unique to each instance
class variables that are shared by all instances of the class
Given a class like:
public class Person
{
// class variable
private static int numberOfEyes;
// instance variable
private String name;
// other code goes here
}
If you were to do something like:
Person a = new Person("Jane Doe");
Person b = new Person("John Doe");
and then do something like:
a.setName("Jane Foe");
the name for Person "a" would change, but the one for Person "b" would stay the same.
If you woke up one morning and decided you wanted 3 eyes:
Person.setNumberOfEyes(3);
then Person "a" and Person "b" and every other Person instance out there would suddenly have 3 eyes as well.
You want to put "static" in your counter declaration.
is your code being used by multiple threads than i would suggest that making counter static won't solve ur problem.
you need to take extra care by implementing thread synchronization use lock keyword as shown below.
private static readonly obj = new Object();
private static int counter =0;
public Imaginary(double r, double u)
{
re = r;
im = u;
lock(obj)
{
name = this.setNextName(counter);
counter++;
}
}
this will ensure thread safety also while incrementing your counter (there are another ways also to provide thread security but this one is having least code).
Because the field counter is not static, every object has its own counter.