I am very new to programming and have a question about using variables in what I believe to be called "nested classes."
class BeginningGameTest {
int attack;
int defend;
public static class James
{
attack = 25;
defend = 15;
}
public static class Janet
{
attack = 45;
defend = 1;
}
public static class Jackson
{
attack = 10;
defend = 20;
}
public static void main(String[] args) {
System.out.prinln(James.attack);
}
}
Do I have the general idea down? I would like to save variables that are the "same" thing, but are different from class to class and are accessed differently like in the print line. I do get a few errors, what should I do to keep the same concept and still keep it fairly simple so I could understand it? Are there any easy to understand tutorials for people who are new to programming in general?
Thanks in advance!
The design of this seems incorrect.
What you're trying to go for when working in an object-oriented language is the basic model of something you wish to represent.
Those three static classes seem to represent the same type of object, so let's create a simple model for them. Think of models like a cookie-cutter. Every cookie cut with this will be the same generic "shape", but will have different characteristics about it (sprinkles, frosting beard, etc). This model should be in its own separate file.
public class Player {
private String name;
private int attack;
private int defense;
public Player(String theirName, int theirAttack, int theirDefense) {
name = theirName;
attack = theirAttack;
defense = theirDefense;
}
// create getters and setters for their attack and defense
}
To actually make use of it, you'd want to instantiate the object.
public class BeginningGameTest {
public static void main(String[] args) {
Player p1 = new Player("James", 25, 15);
Player p2 = new Player("Janet", 45, 1);
Player p3 = new Player("Jackson", 10, 20);
// interactions with the objects below
}
}
Some superb beginner resources already exist in the Java tag wiki; give those a thorough reading. Try new things out, and don't be afraid to ask (good) questions about things you don't understand.
You should create an inner class then define instances of that class within the main method.
public class BeginningGameTest {
public static void main(String[] args) {
Player james = new Player(25,15);
Player janet = new Player(45,1);
Player jackson = new Player(10,20);
System.out.println(james.getAttack());
}
}
class Player{
int attack;
int defend;
public Player(int attack, int defend){
this.attack = attack;
this.defend = defend;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefend() {
return defend;
}
public void setDefend(int defend) {
this.defend = defend;
}
}
You should use the concept of instances to distinguish persons, rather than defining a class for each person. You can define a single class "Person" and instantiate James, Jackson etc. To give them each different attack/defence values, you can use constructors with arguments.
I feel that you might benefit from reading an introduction to object oriented programming. Try searching for "object oriented programming".
You can go two ways about this. You could create subclasses such that James, Janet and Jackson are all classes of the same type, being BeginningGameTest. For example, James could be:
public class James extends BeginningGameTest
{
public James()
{
attack = 25;
defend = 15;
}
}
What I think you want James, Janet and Jackson to be, are not subclasses, but rather instances of the same class BeginningGameTest, like this:
BeginningGameTest James = new BeginningGameTest();
James.setAttack(25);
James.setDefend(15);
There are a few concepts you should read upon:
Classes vs instances
Inheritance
And I also implicitly introduced you to the concept of setters (and getters), typical for Java beans.
This will work:
public static class James
{
static int attack = 25;
static int defend = 15;
}
// ...
Then this would work:
public static void main(String[] args)
{
System.out.prinln(James.attack);
}
This is probably a better design:
public class Player()
{
public static enum NAME { JAMES, JANET };
int attack, defend;
public Player(NAME name)
{
switch (name)
{
case JAMES:
attack = 25;
defend = 15;
break;
// ...
}
}
public static void main(String[] args) throws Exception
{
System.out.println(new Player(NAME.JAMES).attack);
}
}
This is a better design for realistic requirements: (allowing run-time creation of players)
int attack, defend;
String name;
public Player(int attack1, int defend1, String name1)
{
attack = attack1;
defend = defend1;
name = name1;
}
What you can simply do is create different objects of your class that will hold different values of variables attack and defend. Here is the code for the same.
/* package whatever; // don't place package name! */
class Main
{
int attack,defend;
public Main(int attack,int defend)
{
this.attack=attack;
this.defend=defend;
}
public void show()
{
System.out.println("attack: "
+attack+" defend: "+defend);
}
public static void main (String[] args) throws java.lang.Exception
{
Ideone James = new Main(125,15);
James.show();
Ideone Janet = new Main(45,1);
Janet.show();
Ideone Jackson = new Main(10,20);
Jackson.show();
}
}
Related
I'd like to create an array of objects where 3 objects are from one class, and a 4th is from second class.
In the first class I did the following:
public class Pupil {
public int n= 0;
Pupil(int n) {
this.n = n;}
}
in the second class I did the following:
public class Tutor {
public int m= 0;
Tutor(int m) {
this.m = m;}
}
In the main class, I created several pupil objects and one tutor object, like this:
public class Main {
public static void main (String[] args) {
//Pupil(n) while for tutor objects it'd be Tutor(m)
Pupil pupil1 = new Pupil(9);
Pupil pupil2 = new Pupil(8);
Pupil pupil3 = new Pupil(6);
Tutor tutor1 = new Tutor(2);
Using objects for printing in main works fine.
But I'd like to create a fourth class where I group them into arrays of objects, but it won't see the objects that I created to create groups out of them. I'm also not sure about the format for creating an array of objects.
public class Groups {
public static void main(String [] args){
Pupil [] g1 = {tutor1, pupil1, pupil2, pupil3};
//cannot resolve any symbols
}
}
EDIT: according to my tutor the groups class should be static to solve this, but I'm not sure how to actually code this?
Edit2: an answer pointed that the array should be Object as the above code would only be able to create an array of pupils, not pupils and tutors objects.
Object [] g1 = {tutor1, pupil1, pupil2, pupil3};
but that still doesn't solve the main issue where no objects are seen from the groups class (//cannot resolve any symbols)
Arrays can only contain the same type of object. With that being said, here is a way:
Object[] g1 = {tutor1, pupil1, pupil2, pupil3};
Java is a strongly typed programming language so you cannot add different type objects to a same collection. But you take advantage of OPP polymorphism principle. You can create a parent class and extend your subclasses from parent class.
Parent Class
public class Group {
}
Child Classes
public class Pupil extends Group {
public int m = 0;
public Pupil(int m) {
this.m = m;
}
}
public class Tutor extends Group {
public int n = 0;
public Tutor(int n) {
this.n = n;
}
}
So this way you can use it as follows:
public class TestSchool {
public static void main(String[] args) {
Pupil pupil1 = new Pupil(9);
Pupil pupil2 = new Pupil(8);
Pupil pupil3 = new Pupil(6);
Tutor tutor1 = new Tutor(2);
Tutor tutor2 = new Tutor(2);
Group[] groupArray = {pupil1, pupil2, pupil3, tutor1, tutor2};
}
}
So I just started with java, so this is just a simple problem ig, but I have to make a small project for school. I made 2 classes, one called Pokémon and one called trainer. In the Pokémon class I made a constructor and a method to create objects, because I couldn't just create the object:
public class Pokemon {
public String name;
public String typ;
public int maxLp;
public int aktLp;
public int ap;
public Pokemon(String pname, String ptyp, int pmaxLp, int paktLp, int pap) {
name=pname;
typ=ptyp;
maxLp=pmaxLp;
aktLp=paktLp;
ap=pap;
}
public void CreatePokemon(String[] args) {
Pokemon Squirtle = new Pokemon("Squirtle", "Water", 20, 20, 5);
Pokemon Charmander = new Pokemon("Charmander", "Fire", 20, 20, 5);
}
}
In the other class, Trainer, I wanted to use these created objects (Pokemon Squirtle and Pokemon Charmander) to let them fight, the "fight" is basically just one pokemon, I wanted to use Squirtle in the function Squirtle attack, attacking Charmander dealing as much damage as declared in ap, changing the variable aktLp in the object Glumanda, which is the current hp of glumanda:
public class Trainer
{
public String name;
public String gender;
public int money;
public int amountPokemon;
public int amountFights;
public Trainer(String tname, String tgender, int tmoney, int tamountPokemon, int tamountFights) {
name=tname;
gender=tgender;
money=tmoney;
amountPokemon=tamountPokemon;
amountFights=tamountFights;
}
public void ChooseSquirtle() {
System.out.println("You choose Squirtle!");
}
public void ChooseCharmander() {
System.out.println("You choose Charmander!");
}
public void SquirtleAttack() {
System.out.println("Squirtle attacks Charmander!");
Charmander.aktLp = Charmander.aktLp - Squirtle.ap;
}
}
So for this project I have to use - even if I don't like it - BlueJ. BlueJ says: "cannot find symbol - variable Glumanda" - but why? Do I have to call the method CreatePokemon() ? Well I thought I had to and added CreatePokemon(); ,pressed compile and there was another error, but there is no explanation whatsoever. I can't find the problem even though it might be easy. As I said I pretty much just started with java so tips are appreciated - also, I tried my best translating the variables, sorry if you don't understand them and if they are inacurrate.
Your code is not very abstract and has a few flaws:
You're creating pokemon object inside the pokemon class definition. What you should do instead is create it in some higher level method, e.g.: main.
The trainer class uses two pokemons to attack each other. The problem is, the pokemon classes have not been instantiated in a scope that trainer can access. What you should do instead is either instantiate a new pokemon inside the trainer class, or pass pokemon objects as parameters to the generic attack function.
The trainer class could like this with instantiating new pokemon inside.
class Trainer {
public String name;
public String gender;
public int money;
public int amountPokemon;
public int amountFights;
private Pokemon squirtle;
private Pokemon charmander;
public Trainer(String tname, String tgender, int tmoney, int tamountPokemon, int tamountFights) {
name = tname;
gender = tgender;
money = tmoney;
amountPokemon = tamountPokemon;
amountFights = tamountFights;
squirtle = new Pokemon("Squirtle", "Water", 20, 20, 5);
charmander = new Pokemon("Charmander", "Fire", 20, 20, 5);
}
public void ChooseSquirtle() {
System.out.println("You choose Squirtle!");
}
public void ChooseCharmander() {
System.out.println("You choose Charmander!");
}
public void SquirtleAttack() {
System.out.println("Squirtle attacks Charmander!");
charmander.aktLp = charmander.aktLp - squirtle.ap;
}
}
Or like this with accepting pokemons as parameters:
class Trainer {
public String name;
public String gender;
public int money;
public int amountPokemon;
public int amountFights;
public Trainer(String tname, String tgender, int tmoney, int tamountPokemon, int tamountFights) {
name = tname;
gender = tgender;
money = tmoney;
amountPokemon = tamountPokemon;
amountFights = tamountFights;
}
public void SquirtleAttack(Pokemon attacker, Pokemon defender) {
System.out.println(attacker.name+" attacks "+defender.name+"!");
defender.aktLp = defender.aktLp - attacker.ap;
}
}
public class Main {
public void CreatePokemon(String[] args) {
Pokemon squirtle;
Pokemon charmander;
squirtle = new Pokemon("Squirtle", "Water", 20, 20, 5);
charmander = new Pokemon("Charmander", "Fire", 20, 20, 5);
}
}
Just a couple of hints:
Not sure what your project structure is, but you cannot have 2 public classes in a single file. Public class has to have the same name as filename. You can, however, have multiple non-public classes in a single file. But generally it is not recommended to define multiple classes in a single file anyways.
Per Java naming conventions, you should name variables or object instances beggining with lowercase letter. Read more: https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html
Try to use public class properties as least as possible and private as often as possible. To manipulate private properties values, use getters and setters. more info here: https://www.freecodecamp.org/news/java-getters-and-setters/
I'm trying to add let's say 5 classes that they all extend a General class and implements an init() method in a different way.
What I need is a way to store those classes while passing a number of chances for that Class to "happen"
For this I created a Class holder:
public class ClassHolder {
private Class<? extends GeneralOutcome> holdClass;
private int chances;
public ClassHolder(Class<? extends GeneralOutcome> holdClass, int chances) {
super();
this.holdClass = holdClass;
this.chances = chances;
}
public Class<? extends GeneralOutcome> getHoldClass() {
return holdClass;
}
public void setHoldClass(Class<? extends GeneralOutcome> holdClass) {
this.holdClass = holdClass;
}
public int getChances() {
return chances;
}
public void setChances(int chances) {
this.chances = chances;
}
}
Also a GeneralOutcome class that the ones that will be added to a list will extend:
public class GeneralOutcome {
public void init(String text, int times) {
}
}
And the way I'm adding them to a list:
public class Randomizer {
private static List<ClassHolder> myList = new ArrayList<ClassHolder>();
private static ClassHolder outcome01 = new ClassHolder(Outcome01.class, 10);
private static ClassHolder outcome02 = new ClassHolder(Outcome02.class, 10);
private static ClassHolder outcome03 = new ClassHolder(Outcome03.class, 10);
private static ClassHolder outcome04 = new ClassHolder(Outcome04.class, 10);
private static ClassHolder outcome05 = new ClassHolder(Outcome05.class, 10);
public static void main(String[] args) {
for(int i = 0; i < outcome01.getChances(); i++) {
myList.add(outcome01);
}
for(int i = 0; i < outcome02.getChances(); i++) {
myList.add(outcome02);
}
for(int i = 0; i < outcome03.getChances(); i++) {
myList.add(outcome03);
}
for(int i = 0; i < outcome04.getChances(); i++) {
myList.add(outcome04);
}
for(int i = 0; i < outcome05.getChances(); i++) {
myList.add(outcome05);
}
System.out.println(myList.size());
int rand = (int) (Math.random() * myList.size());
System.out.println(rand);
ClassHolder theHoldClass = myList.get(rand);
System.out.println(theHoldClass.getHoldClass());
Class<? extends GeneralOutcome> theOutcome = theHoldClass.getHoldClass();
theOutcome.init();
}
}
The problem is that I'm not able (Don't know how really) cast back to GeneralOutcome to I can access the .init() method.
I get The method init() is undefined for the type Class<capture#3-of ? extends GeneralOutcome>
I know this isn't the best way to do this. So I'm open to both, a fix for this and also what would be a better way to achieve something like this.
What you are trying to do here doesn't work for some reasons.
First of all, your init method isn't static. So that call
Class<? extends GeneralOutcome> theOutcome = theHoldClass.getHoldClass();
theOutcome.init();
leads directly to a compile-time error.
But then, the whole design looks strange. What is the point of holding Class objects in the first place?
Why don't you create an interface
public interface OutcomeFunctionality {
public void foo(String text, int times);
}
to later instantiate objects of whatever class implementing that interface? So that you can finally can deal with lists of such objects (together with those probabilities)?
[ I used the name foo on purpose: alone the strange name "init" makes it very unclear what your code is intended to do! In that sense you should rethink your design, and find better method names to express what those methods will be doing! ]
Long story short: using/holding Class objects doesn't buy you anything in your example code - it only adds complexity. So my advise is: start working there and get rid of that "detour". You might also want to read about the Open/Closed principle - that could give you some guidance how a good OO design looks like that uses abstract classes / subclassing in order to split "behavior" between base and derived classes.
I have a similar question on this topic but I dumbed it down and left out all the extra code. Also, I took the advice of the old question and set my variables to zero but it didn't make any difference.
Main:
public class WhyAPrints0Main {
public static void main(String[] args) {
int x = 24;
WhyAPrints0 set = new WhyAPrints0();
WhyAPrints01 get = new WhyAPrints01();
set.setWhy(x);
get.print();
}
}
Class 1
public class WhyAPrints0 {
private int why;
public int getWhy() {
return why;
}
public void setWhy(int why) {
this.why = why;
}
}
Class 2
public class WhyAPrints01 {
WhyAPrints0 get = new WhyAPrints0();
int a = 0;
public void print(){
a = get.getWhy();
System.out.println(a);
}
}
I really don't understand why this doesn't print 24 so if someone could explain well and possibly fix the code to where it does I would really appreciate it.
Why would you expect it to print 24?
You invoke the print() method:
get.print();
Which prints 0:
public class WhyAPrints01 {
WhyAPrints0 get = new WhyAPrints0();
int a = 0;
public void print(){
a = get.getWhy();
System.out.println(a);
}
}
(Since 0 is the default value for an int, which is what is returned by get.getWhy().)
I think your confusion is coming from the concept of having multiple instances of the same class. You have two different instances of WhyAPrints0. One in your main() method and one in your second class. These two instances have nothing to do with one another. Setting a value in one doesn't affect the other.
As an analogy, consider two identical cars. If you put something in the trunk of one car, you shouldn't expect to retrieve it from the trunk of the other car. It doesn't matter that the cars are otherwise identical, they're not the same car.
You have to link your WhyAPrints01 to your WhyAPrints0 some how. Right now you have 2 instances of WhyAPrints0. You can change your WhyAPrints01 to something like this so you can set an instance of WHyAPrints0 in your WhyAPrints01 class.
public class WhyAPrints01 {
WhyAPrints0 get;
int a = 0;
public WhyAPrints01(WhyAPrints0 get){
this.get = get;
}
public void print(){
a = get.getWhy();
System.out.println(a);
}
}
And your main to:
public static void main(String[] args) {
int x = 24;
WhyAPrints0 set = new WhyAPrints0();
set.setWhy(x);
WhyAPrints01 get = new WhyAPrints01(set);
get.print();
}
So I'm building a game engine and I need to be able to call methods from a class that implements a certain interface(I only want to call methods implemented by the interface).
My problem is that I don't know what the class name will be implementing it.
So how does, for instance, Java call the run() method in all classes that implement Runnable without knowing the class name?
Really, you're asking about the Factory pattern or a dependency injection container such as Spring.
Of course you can call the methods on an interface, the question is how you get the instance. That of course has to be specified, coded or configured somewhere. Configuration is preferable if there could ever be more than one in the future.
Thus, more of a real example:
public interface MovementStrategy {
public Move selectMove (Actor actor, ActorSituation theirSituation);
}
public class MonsterTypes {
public static MonsterType GOBLIN = new MonsterType( "goblin", new AttackMover(1.2));
public static MonsterType TROLL = new MonsterType( "troll", new AttackMover(0.45));
public static MonsterType DEER = new MonsterType( "deer", new FleeMover(2.0));
// useful to have, also.
public static List<MonsterType> getAllRegisteredTypes();
public static class MonsterType {
protected String name;
protected MovementStrategy moveStrategy;
// TODO -- getters & setters for all properties.
// constructor.
public MonsterType (String name, MovementStrategy moveStrategy) {
this.name = name;
this.moveStrategy = moveStrategy;
}
}
}
public class AttackMover implements MovementStrategy {
// SPEC: generally move towards/attack PC, with varying speeds.
}
public class FleeMover implements MovementStrategy {
// SPEC: generally run away from PCs.
}
This isn't probably a perfect design -- it conflates "movement" (aka goal-seeking) with the actor's turn/actions overall -- but hopefully it gives you some more idea.
If you only want to call methods from the interface (good!), then you usually don't need to now the name of the implementor.
getRunnableFromSomewhere().run();
always works and calls the run() method on the instance that is returned by that method.
If you want to now the class name at runtime, simpy call getClass().getName() on the instance:
System.out.println(getRunnableFromSomewhere().getClass().getName());
A simple example with the Number interface:
public class NumberExample {
public static void main(String[] args) {
MagicNumber magic = MagicNumberProvider.get(); // a random implementation
System.out.println(magic.getMagicNumber().doubleValue()); // We know nothing about the implementations
}
}
class MagicNumberProvider {
public static MagicNumber get() {
return Math.random() > 0.5d ? new ItsMagicOne() : new ItsMagicTwo();
}
}
interface MagicNumber {
public Number getMagicNumber();
}
class ItsMagicOne implements MagicNumber {
#Override
public Number getMagicNumber() {return new Long(1);}
}
class ItsMagicTwo implements MagicNumber {
#Override
public Number getMagicNumber() {return new Double(2.5);}
}
It only calls interface methods and we have, from the perspective of the main method, no idea, which implementation of MagicNumber is used (it's random) and on which implementation of Number we actually call the doubleValue() method.
Service Provide Interface
You can use java SPI (Service Provider Interface) by which later implementing jars declare the same service in the manifest. A using app can do a lookup, iterate over them and pick one.
An example is the different XML parser implementations.
Parameter
For your case it might suffice to have a run method:
class GameRunner {
public static void mainEntry(MyGameInterface mgi) {
}
}
And the implementors may do
cöass ThirdPartyGame implements MyGameInterface {
}
GameRunner.mainEntry(new ThirdPartyGame());
Plugin with java reflection
You can make your ad-hoc, self-define plugin emchanism, and use java reflection to instantiate the class. The third party jar must be placed at some location, that is in the class path, as defined in your jar's manifest. The class somewhere defined:
String klazz = resBundle.getProperty("pluginClass");
Class<MyGameInterface> klazz = Cass<MyGameInterface>.forName(klazz);
MyGameInterface game = klazz.getConstructor().newInstance();
If I understood your question correctly it seems you have slightly misunderstood polymorphism, you don't need to know the type that implements the interface.
See the following example, there is only one class that directly knows the types of each enemy, the initializing class.
import java.util.ArrayList;
import java.util.List;
public class SO18671999 {
public static interface Enemy {
public void Attack(Enemy other);
public String getName();
}
public static class Dragon implements Enemy {
String name = "Onyxia";
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for 10 dmg!");
}
public String getName() {
return this.name;
}
}
public static class Cerberus implements Enemy {
private String name;
private int dmg;
public Cerberus(String name, int dmg) {
this.name = name;
this.dmg = dmg;
}
#Override
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for " + this.dmg + " dmg!");
}
#Override
public String getName() {
return this.name;
}
}
public static class EnemyInitializer {
private List<Enemy> enemies;
public EnemyInitializer() {
enemies = new ArrayList<>();
enemies.add(new Dragon());
enemies.add(new Cerberus("CerberusHeadLeft", 10));
enemies.add(new Cerberus("CerberusHeadRight", 10));
enemies.add(new Cerberus("CerberusHeadCenter", 20));
}
public List<Enemy> getEnemies() {
return enemies;
}
}
public static class EnemyAttacker {
private EnemyInitializer eI = new EnemyInitializer();
public void startAttacking() {
List<Enemy> enemies = eI.getEnemies();
for (Enemy one : enemies) {
for (Enemy two : enemies) {
if (one == two)
continue;
one.Attack(two);
}
}
}
}
public static void main(String[] args) {
EnemyAttacker eAttacker = new EnemyAttacker();
eAttacker.startAttacking();
}
}